条件管道

条件管道

假设我有以下管道:

cmd1 < input.txt |\
cmd2 |\
cmd4 |\
cmd5 |\
cmd6 |\
(...) |\
cmdN > result.txt

在某些情况下,我想在和cmd3之间添加一个。有没有办法创建一种条件管道而不将结果保存到临时文件中?我会想到这样的事情:cmd2cmd4cmd2

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

到目前为止给出的所有答案都替换cmd3cat.您还可以避免运行任何命令:

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 -qwhichsplice()而不是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

相关内容