管道B到D?-A && B || C | d


14

有没有一种方法可以重写命令结构,A && B || C | D以便将B或C管道传输到D?

使用当前命令,仅运行B或运行C和D。

例如:

在此处输入图片说明

Answers:


31

是的,可以在bash中使用括号:

(A && B || C) | D

这样的输出A && B || C将通过管道传递到D


6
或者A && (B || C) | D,如果您不希望B在A失败时运行B,C或D
zwol

2
您也可以在sh:)中使用括号
-EKons

目前尚不清楚使用括号而不是大括号是一个故意的决定(如果这样,有什么好处?)还是仅仅是一个疏忽。你能解释一下吗?
Tom Fenech

@TomFenech Parens使表达式在子外壳中运行,这是与脚本其余部分的POV分开的(单个)过程。因此,无论paren内部表达式的输出是什么,都将通过管道将其输出。(由于A位于子外壳中,因此也包括A。)
jpaugh

1
@jpaugh我认为您关于隔离的观点很好,但是使用花括号时,输出将以相同的方式传递,不是吗?
Tom Fenech

14

你可以这样写

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

您说您想运行BC,但是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 bashpgrep bash | catif true; then pgrep bash; fi并且{ pgrep bash; }有一行输出;( pgrep bash; )( pgrep bash; ) | cat{ pgrep bash; } | catif true; then pgrep bash; fi | cat具有输出的两行。
wchargin

@wchargin ... | ...导致创建子壳,这是不可避免的。( ... ),至少在理论上,导致额外的要创建子shell的是{ ...; }避免了,但是这就是我的意思与“可能会或可能不会得到优化”:这是可能的,在这种特殊情况下,壳认识也没关系,该效果是一样的。
hvd

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

如果这一切看起来对您来说都不是一件容易的事(对我来说是如此),我建议您使用特殊的shell变量作为的退出状态A并使用它:

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

如果您想更简洁但又不要太神秘,我建议这样做:

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

(另请参阅hvd答案的最后一部分,当我写原始答案时我没有注意到。)


我的回答确实涵盖了这一点。看看我在“注释2”中输入的内容,我只是A从管道中移出。
hvd

@hvd:您是正确的,并感谢您指出对我的回答!我更改了索赔要求,并相应地给了您信用。
David Foerster
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.