假设我有以下管道:
cmd1 < input.txt |\
cmd2 |\
cmd4 |\
cmd5 |\
cmd6 |\
(...) |\
cmdN > result.txt
在某些情况下,我想在和cmd3
之间添加一个。有没有办法创建一种条件管道而不将结果保存到临时文件中?我会想到这样的事情:cmd2
cmd4
cmd2
cmd1 < input.txt |\
cmd2 |\
(${DEFINED}? cmd3 : cat ) |\
cmd4 |\
cmd5 |\
cmd6 |\
(...) |\
cmdN > result.txt
答案1
只是通常的&&
和||
运算符:
cmd1 < input.txt |
cmd2 |
( [ -n "$DEFINED" ] && cmd3 || cat ) |
cmd4 |
cmd5 |
cmd6 |
(...) |
cmdN > result.txt
虽然,正如指定的这个答案if ... else
,如果您使用 if-else 语法,您通常会更喜欢, :
...
cmd2 |
if [ -n "$DEFINED" ]; then cmd3; else cat; fi |
cmd4 |
...
(请注意,当该行以管道结尾时,不需要尾随反斜杠。)
更新根据乔纳斯的观察。
如果 cmd3 可能以非零退出代码终止,并且您不想cat
处理剩余的输入,请反转逻辑:
cmd1 < input.txt |
cmd2 |
( [ -z "$DEFINED" ] && cat || cmd3 ) |
cmd4 |
cmd5 |
cmd6 |
(...) |
cmdN > result.txt
答案2
if
//else
有效fi
。假设任何类似 Bourne 的 shell:
cmd1 < input.txt |
cmd2 |
if [ -n "$DEFINED" ]; then cmd3; else cat; fi |
cmd4 |
cmd5 |
cmd6 |
(...) |
cmdN > result.txt
答案3
到目前为止给出的所有答案都替换cmd3
为cat
.您还可以避免运行任何命令:
if [ -n "$DEFINE" ]; then
alias maybe_cmd3='cmd3 |'
else
alias maybe_cmd3=''
fi
cmd1 |
cmd2 |
maybe_cmd3
cmd4 |
... |
cmdN > result.txt
这是 POSIX,但请注意,如果bash
脚本中bash
不处于sh
- 模式(例如以 开头的脚本#! /path/to/bash -
),则需要使用shopt -s expand_aliases
(或set -o posix
) 启用别名扩展。
另一种仍然不运行任何不必要命令的方法是使用 eval:
if [ -n "$DEFINE" ]; then
maybe_cmd3='cmd3 |'
else
maybe_cmd3=''
fi
eval "
cmd1 |
cmd2 |
$maybe_cmd3
cmd4 |
... |
cmdN > result.txt"
或者:
eval "
cmd1 |
cmd2 |
${DEFINE:+cmd3 |}
cmd4 |
... |
cmdN > result.txt"
在Linux上(至少),cat
您可以使用pv -q
whichsplice()
而不是read()
+write()
来在两个管道之间传递数据,从而避免数据在内核和用户空间之间移动两次。
另一种选择可能是定义一个函数,该函数运行通过管道传入或传出cmd3
或不依赖于 的给定命令$DEFINE
。
if [ -n "$DEFINE" ]; then
maybe_preprocess_with_cmd3() { cmd3 | "$@"; }
maybe_postprocess_with_cmd3() { "$@" | cmd3; }
else
maybe_preprocess_with_cmd3() { "$@"; }
maybe_postprocess_with_cmd3() { "$@"; }
fi
进而:
cmd1 |
cmd2 |
maybe_preprocess_with_cmd3 cmd4 |
... |
cmdN > result.txt
或者:
cmd1 |
maybe_postprocess_with_cmd3 cmd2 |
cmd4 |
... |
cmdN > result.txt
答案4
我遇到过类似的情况,我用 bash 解决了功能:
if ...; then
my_cmd3() { cmd3; }
else
my_cmd3() { cat; }
if
cmd1 < input.txt |
cmd2 |
my_cmd3 |
cmd4 |
cmd5 |
cmd6 |
(...) |
cmdN > result.txt