Объединение канала с состоянием выхода в сценарии оболочки bash - PullRequest
9 голосов
/ 09 сентября 2011

У меня есть команда bash shell-script, которая запускает date , если make завершается успешно (завершается с нулевым статусом выхода) и наоборот:

make && date

но теперь я хочу обработать его вывод, например

make | sed s/a/A/

Если я сделаю

make | sed s/a/A/ && date

, дата запускается, даже когда make терпит неудачу.

Если вместо этого я

make && date | sed s/a/A/

* sed обрабатывает date вывод вместо make s.

Знали бы вы какое-нибудь решение?Спасибо!


PS Я пробовал это:

(make | sed s/a/A/) && date

дата все еще работает, когда make не удается.

(make && (date > /dev/null)) | sed s/a/A/

дата не запускается, когда делает успешным.

Ответы [ 3 ]

10 голосов
/ 09 сентября 2011

Если у вас есть оболочка с подстановкой процессов (bash делает, posix shell нет), тогда

make > >(sed s/a/A/) && date

должен сделать трюк, кроме bash, он не ждет sed (кажется, zsh делает, но я только попробовал, но не проверил doc), поэтому выходные данные date могут быть получены до последней строки вывода sed. В простой оболочке posix вы можете использовать немного более сложную конструкцию

((make && date >&3) | sed s/a/A/) 3>&1

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

Если вы хотите, чтобы дата запускалась только после того, как sed обработал все, ваш единственный шанс - сохранить где-нибудь статус make. Что-то вроде:

(make && touch make-succeeded) | sed s/a/A/
rm make-succeeded 2>/dev/null && date

злоупотребляя тем фактом, что если файл не существует, rm (без -f) выйдет с ненулевым состоянием и отключит сообщение об ошибке с перенаправлением. Как уже упоминал Фредрик, в bash действительно есть место, где он сохраняет статус выхода, поэтому в bash вы можете:

make | sed s/a/A/
[ 0 -eq $PIPESTATUS[0] ] && date
8 голосов
/ 09 сентября 2011

Включите pipefail в подоболочке make.

(set -o pipefail; make 2>/dev/null | sed s/a/A/) && date
1 голос
/ 09 сентября 2011

В основном так;

my_make () {
  local rc
  make >tmp
  rc=$?
  sed s/a/A/ tmp
  rm tmp
  return $rc
}

Временный файл, очевидно, должен обрабатываться надлежащим образом;это пустяки, чтобы сосредоточиться на проблеме под рукой.Возможно, вы могли бы вообще избежать временного файла, если вы умны с файловыми дескрипторами, но сейчас пятница, и мне нужно больше кофе.

...