Как совместить группировку команд и состояние канала

Как объединить группировку команд bash и статус трубы?

Это примерная группа команд:

{ tar -cf - my_folder 2>&1 1>&3 | grep -v "Removing leading" 1>&2; } 3>&1 | gzip --rsyncable > my_file.tar.gz 

Это пример показания состояния трубопровода, чтобы перейти к следующему:

 [[ ${PIPESTATUS[*]} =~ [1-9] ]] && rm my_file.tar.gz 

В этом примере группа команд хранит почтовую катушку без предупреждений о «удалении ведущего /» из tar, доставляемого через cron, потому что они приземляются на stderr (Unices не хватает stdwarn и tar без тихой опции), позволяя реальным ошибкам проходить через ,

Считывание состояния трубы гарантирует, что поврежденные файлы резервных копий будут немедленно удалены, чтобы предотвратить последующую очистку с использованием стандартного алгоритма FIFO для удаления старых файлов.

Но этот пример не работает. В приведенном выше состоянии состояние канала содержит [1 0], то есть код выхода grep и gzip, но не tar.

Одна попытка, которую я пробовал, состояла в следующем:

 { tar -cf - my_folder 2>&1 1>&3 | grep -v "Removing leading" 1>&2; GROUPSTATUS=${PIPESTATUS[*]}; } 3>&1 | gzip --rsyncable > my_file.tar.gz [[ $GROUPSTATUS =~ [1-9] ]] && rm my_file.tar.gz 

Но GROUPSTATUS пуст после выхода из группы.

(Заметим, что, установив GROUPSTATUS на что-либо, кроме состояния канала, например, на литерал какого-либо типа, можно проверить, что эта переменная фактически исключает область группировки команд при обычных обстоятельствах.)

Я также пробовал, если return изнутри группы может привести к выходу кода выхода первого компонента трубы наружу, но возврат внутри командной группы просто приводит к сообщению об ошибке из bash.

  • строка 7: [: ожидаемое выражение echo: integer
  • Суммируйте заданный срез элементов в массиве (bash)
  • Баш: почему не «настроено» вести себя так, как я ожидаю?
  • Почему \ 033 сработает для таких варов, как PS1 и \ x1b, нет?
  • bash throwing "ignored null byte in input" предупреждение в скрипте
  • Разница между printf и echo в bash
  • выход в json-форме
  • Как я могу предотвратить выполнение части / etc / profile в моей оболочке входа?
  • 2 Solutions collect form web for “Как совместить группировку команд и состояние канала”

    Когда вы выполняете конвейер, каждый элемент, разделенный на трубы, выполняется в своем собственном процессе. Переменные назначения вступают в силу только в их собственном процессе. В ksh и zsh последний элемент конвейера выполняется в исходной оболочке; под другими оболочками, такими как bash, каждый элемент конвейера выполняется в своей собственной подоболочке, а исходная оболочка просто ждет их завершения.

     $ bash -c 'GROUPSTATUS=foo; echo GROUPSTATUS is $GROUPSTATUS' GROUPSTATUS is foo $ bash -c 'GROUPSTATUS=foo | :; echo GROUPSTATUS is $GROUPSTATUS' GROUPSTATUS is 

    В вашем случае, поскольку вы заботитесь только обо всех командах, вы можете сделать код состояния текущим.

     { tar -cf - my_folder 2>&1 1>&3 | grep -v "Removing leading" 1>&2; ! ((PIPESTATUS[0])); } 3>&1 | gzip --rsyncable > my_file.tar.gz; if ((PIPESTATUS[0] || PIPESTATUS[1])); then rm my_file.tar.gz; fi 

    Если вы хотите получить более 8 бит информации из левой части канала, вы можете записать еще один дескриптор файла. Вот пример доказательства:

     { { tar …; echo $? >&4; } | …; } | { gzip …; echo $? >&4; } \ 4>&1 | ! grep -vxc '0' 

    Как только вы получите данные на стандартном выходе, вы можете передать его в переменную оболочки с помощью подстановки команд, то есть $(…) . Подстановка команд считывается из стандартного вывода команды, поэтому, если вы также должны печатать на стандартном выходе сценария, им необходимо временно перейти через другой дескриптор файла. Следующий фрагмент использует fd 3 для вещей, которые в конечном итоге переходят к скрипту stdout и fd 4 для вещей, которые захватываются в $statuses .

     statuses=$({ { tar -v … >&3; echo tar $? >&4; } | …; } | { gzip …; echo gzip $? >&4; } 4>&1) 3>&1 

    Если вам нужно записать вывод из разных команд в разные переменные, я думаю, что нет прямого пути даже в «продвинутых» оболочках, таких как bash, ksh или zsh. Вот некоторые обходные пути:

    • Используйте временные файлы.
    • Используйте один выходной поток, например, префикс в каждой строке, чтобы указать его начало, и фильтр на верхнем уровне.
    • Используйте более продвинутый язык, такой как Perl или Python.

    Простым способом является обход проблемы, заключается в том, чтобы поместить my_folder в переменную оболочки и удалить из нее главную косую черту:

     tar -cf - ${my_folder##/} | gzip --rsyncable > my_file.tar.gz 

    В противном случае вы можете проверить $ {PIPESTATUS [0]} внутри блока и использовать false, если он не равен нулю, чтобы сигнализировать об ошибке внешнему процессу:

     { tar -cf - my_folder 2>&1 1>&3 | grep -v "Removing leading" 1>&2; [ ${PIPESTATUS[0]} -eq 0 ] && true || false; } 3>&1 | gzip --rsyncable > my_file.tar.gz 
    Interesting Posts

    Создание переменной в каталоге, который сохраняется до удаления

    gcc 4.6.3 локальная установка с gmp 5.0.5 mpfr 3.1.1 ошибки

    Сценарий Bash не работает, как ожидалось

    Как установить скорость двойного щелчка мыши в Lubuntu

    RHEL6 Не удается запустить мой скрипт при завершении работы и перезагрузке

    netcat работает не так, как ожидалось, когда отсоединяется от консоли с nohup (Ubuntu / Debian 64bit)

    определить пакеты и зависимости

    Неверный порядок запуска службы, когда не загружается в однопользовательский режим

    Дисплей часто показывает черный экран

    Как разморозить после случайного нажатия Ctrl-S в терминале?

    Найти каталог, если количество файлов превышает X

    найти только первое появление, используя только grep

    Использование подстановки процесса для обмана программ, ожидающих файлы, с конкретными расширениями в качестве аргумента?

    Подключен к WIFI, но нет интернета

    Что означают «функции, включенные» в GNU?

    Linux и Unix - лучшая ОС в мире.