Труба от B до D? - A && B || C | D


14

Есть ли способ переписать структуру команд A && B || C | Dтак, чтобы B или C передавались по D?

С текущей командой запускаются только B или C и D.

Например:

введите описание изображения здесь

Ответы:


31

Да, в bash вы можете использовать круглые скобки:

(A && B || C) | D

Таким образом, вывод A && B || Cбудет передан в D.


6
Или A && (B || C) | D, если вы не хотите, чтобы B, C или D запускались при сбое A
zwol

2
Вы также можете использовать парены в sh:)
EKons

Неясно, было ли использование скобок вместо фигурных скобок преднамеренным решением (если да, каковы преимущества?) Или просто упущением. Могли бы вы объяснить?
Том Фенек,

@TomFenech Parens заставляет выражение работать в под-оболочке, которая является (отдельным) процессом, отличным от POV остальной части сценария. Поэтому, независимо от вывода выражения внутри паренов, оно будет передано вместе. (Так как Aнаходится внутри подоболочки, это также включает в себя A.)
jpaugh

1
@jpaugh Я думаю, что ваша точка зрения на изоляцию хорошая, но результат будет таким же, как при использовании фигурных скобок, не так ли?
Том Фенек,

14

Вы можете написать это как

if A; then B; else C; fi | D

Вы говорите, что хотите бежать Bили C, но A && B || Cне достигаете этого. Если Aуспешно, но Bработает и не удается, он будет выполнен C.

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

{ A && B || C; } | D

более того ( ... ), так как последний излишне заставляет создавать новую подоболочку, которая может или не может быть оптимизирована.

Примечание 2: обе формы предполагают, что не Aпроизводит вывод, что верно в вашем примере, но не обязательно так в общем. Этого можно избежать

A; if [ "$?" -eq 0 ]; then B; else C; fi | D

Вы уверены, что { … }не создаст подоболочку из-за трубы? Я наблюдаю следующее поведение: pgrep bashи, pgrep bash | catи if true; then pgrep bash; fiи { pgrep bash; }есть одна строка вывода; ( pgrep bash; )и ( pgrep bash; ) | catи { pgrep bash; } | catи if true; then pgrep bash; fi | catимеют две строки вывода.
wchargin

@wchargin ... | ...вызывает создание подоболочки, это неизбежно. ( ... )По крайней мере теоретически, это приводит к созданию дополнительной подоболочки, которая { ...; }избегает, но это то, что я имел в виду, «может или не может быть оптимизировано»: возможно, что в данном конкретном случае оболочка понимает, что это не имеет значения, эффект был бы таким же.
17

5

Ответ акцептора верен, но он не охватывает потенциальный вариант использования, чтобы не выводить в Aкачестве входных данных D. Для этого вам понадобится перенаправление потока в Aзависимости от ваших потребностей.

  • Если вы хотите отказаться от вывода в Aлюбом случае:

    { A >/dev/null && B || C; } | D
  • Если вы хотите увидеть вывод Aна терминале:

    { A >/dev/tty && B || C; } | D
  • Если вам нужен вывод в Aкачестве ввода последующей команды, Eвам понадобится дополнительная группа команд и перенаправление потока:

    { { A >&3 && B || C; } | D; } 3>&1 | E

Если все это выглядит слишком загадочно для вас (как и для меня), я рекомендую вам использовать специальную переменную оболочки для статуса выхода Aи работать с этим:

A
if [ $? -eq 0 ]; then
  B
else
  C
fi |
D

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

A; { [ $? -eq 0 ] && B || C; } | D

(См. Также последнюю часть ответа hvd, которую я не заметил, когда писал свой оригинальный ответ.)


Мой ответ действительно охватывает это. Посмотрите, что я вставил в «Примечание 2:», где я просто Aвышел из конвейера.
HVd

@hvd: Вы правы, и спасибо, что указали на эту часть вашего ответа мне! Я изменил свое требование и дал вам кредит соответственно.
Дэвид Фёрстер
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.