在 bash 中合并两个命令的输出

cho*_*ovy 136 bash io-redirection

是否可以组合这两个命令的输出?

node ~/projects/trunk/index.js 
python ~/projects/trunk/run.py run
Run Code Online (Sandbox Code Playgroud)

这两个命令都没有退出,所以我不确定如何执行此操作。

Gil*_*not 161

您可以通过将其与{ }以下分组来组合两个命令:

{ command1 & command2; }
Run Code Online (Sandbox Code Playgroud)

到目前为止,您可以将组重定向到一个文件(最后一个;之前}是必需的),以及左括号和右括号之间的空格

{ command1 & command2; } > new_file
Run Code Online (Sandbox Code Playgroud)

如果你想分开STDOUTSTDERR在两个文件中:

{ command1 & command2; } > STDOUT_file 2> STDERR_file
Run Code Online (Sandbox Code Playgroud)

  • 我宁愿使用`&&`而不是`&`!`command1 & command2` - 这会在后台运行 command1 并立即启动 command2,从而并行运行这两个命令并弄乱输出。`command1 && command2` - 这会运行 command1(在前台),然后,如果 command1 成功,则运行 command2。 (22认同)
  • 请注意:这不会保留整行!您将获得不可靠的输出,因为线路会部分分开并相互混合。您可以尝试使用 `{ yes {1..20} & yes {1..20}; } | grep -v '^1 2 3'` 如果没有断线,理想情况下不会打印任何内容。 (6认同)
  • 好像你在`}`之前缺少最后一个`;`,这是强制性的! (5认同)
  • @DUzun OP 说这两个命令都没有退出,因此使用您的解决方案,第二个命令将永远不会运行 (5认同)
  • 他们的程序没有完成也没关系。'tail -f' 也不会“完成”,但这仍然有效并结合了两个程序的输出。也适用于两个以上的命令。^c 退出只会杀死一组命令之一。但是,您必须手动杀死其他人。 (3认同)
  • @DUzun“两个命令都没有退出,所以我不知道该怎么做。” OP 指定命令产生无限的输出流,并且不退出。这与产生有限输出然后结束的命令不可比。例如,`{ yes && echo no }` 永远不会打印“no” (3认同)
  • @ZoeyHewell 我明白你的意思。`{是的; 回声没有; 在这种情况下,按下 Ctrl+C 后将输出“no”。`{是与否; }` 将使用 'no' 打乱 `yes` 的输出,并且最有可能的 'no' 将在它自己的行上。用于正确任务的正确工具。 (2认同)

小智 82

更一般地,可以使用子shell 或命令分组,并一次重定向整个组的输出。

代码:

( command1 ; command2 ; command3 ) | cat

{ command1 ; command2 ; command3 ; } > outfile.txt

两者之间的主要区别在于,第一个拆分子进程,而第二个在主 shell 的上下文中运行。这可能会对变量和其他环境设置的设置和使用以及性能产生影响。

不要忘记命令分组(和函数)中的结束括号必须通过分号或换行符与内容分开。这是因为"}"它实际上是一个自己的命令(关键字),必须像一个命令一样对待。

  • `}` 根本不是命令。这是一个保留字。`{` 也是如此。我通常写这样的列表:`{ command1;command2;} > outfile.txt`。您可以在分号后添加空格,但这不是必需的。不过,`{` 之后的空格 * 是* 必要的。 (4认同)
  • 有时您只想在 command1 成功时运行 command2:`( command1 && command2 && command3 ) | 猫` (3认同)
  • 从`()` 重定向也可以正常工作。 (2认同)

Ole*_*nge 12

到目前为止,大多数解决方案都无法很好地处理部分线问题。假设程序是:

cmd1() {
    perl -e 'while(1) { print "a"x3000_000,"\n"}'
}
export -f cmd1
cmd2() {
    perl -e 'while(1) { print "b"x3000_000,"\n"}'
}
export -f cmd2
Run Code Online (Sandbox Code Playgroud)

当并行运行它们时,您希望输出具有完整的as行,然后是完整的bs行。您想要的是as 和bs 在同一行上混合(tr -s aba单个 s替换重复的s a,因此更容易看到会发生什么):

# This is bad - half lines are mixed
$ (cmd1 & cmd2 ) | tr -s ab
bababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababa
ababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababab
Run Code Online (Sandbox Code Playgroud)

如果您改为使用 GNU Parallel,您将获得带有as 或bs 但绝不会混合的漂亮干净的完整行:

$ parallel --line-buffer ::: cmd1 cmd2 | tr -s ab
a
a
b
b
b
b
a
Run Code Online (Sandbox Code Playgroud)

较新版本的 GNU Parallel 甚至可以避免填满您的磁盘:上述内容可以永远运行。


Luk*_*uke 5

对于将多个 BASH 命令输出组合到一行的特殊情况,这里有一个方法来依次运行每个命令,删除它们输出之间的任何换行符。

(echo 'ab' && echo 'cd' && echo 'ef') | tr -d '\n'
>>> abcdef
Run Code Online (Sandbox Code Playgroud)

作为一个真实世界的例子,下面的代码将在两个固定的字节字符串之间嵌入一个 ASCII 消息(在这种情况下形成一个打印命令)

#   hex prefix           encode a message as hex    hex suffix    | strip newline | hex to binary | (then, for example, send the binary over a TCP connection)
(echo '1b40' && echo "Test print #1" | xxd -p && echo '1d564103') | tr -d '\n'    | xxd -r -p     | nc -N 192.168.192.168 9100
Run Code Online (Sandbox Code Playgroud)

(注意:此方法仅在命令退出时才有效。要从不退出的命令中组合 stdout,请参阅其他答案。)


小智 5

cat接受的答案\xe2\x80\x99s 输出可能不按正确的顺序出现,如果您的源是异步的(例如或curl),请勿使用它

\n\n

使用这个代替:

\n\n
cat <(command1) <(command2) <(command3) > output.txt\n
Run Code Online (Sandbox Code Playgroud)\n\n

现实生活中的例子:

\n\n
cat \\\n<(curl https://stackoverflow.com/humans.txt) \\\n<(echo -e "\\n\\nDownloaded from https://stackoverflow.com") \\\n> output.md\n
Run Code Online (Sandbox Code Playgroud)\n\n

生产

\n\n
There\'s a bunch of humans behind Stack Overflow and the network of Stack Exchange sites. If you\'d like to join us check out https://stackoverflow.com/company/work-here\n\nDownloaded from https://stackoverflow.com\n
Run Code Online (Sandbox Code Playgroud)\n


cho*_*ovy 2

我最终这样做了,其他建议不起作用,因为第二个命令要么被杀死,要么从未执行。

alias app () {
    nohup python ~/projects/trunk/run.py run 1>/tmp/log 2>&1 &
    echo $! > /tmp/api.pid
    nohup node ~/projects/trunk/index.js 1>/tmp/log 2>&1 &
    echo $! > /tmp/client.pid
    tail -f /tmp/log
}
Run Code Online (Sandbox Code Playgroud)

  • 可以指定 2 个不同的日志文件并执行“tail -f *.log”,尽管我从未将这视为 2 个不同进程写入同一日志文件的问题。 (2认同)