如何将标准输出发送到多个命令?

如何将标准输出发送到多个命令?

有一些命令会过滤或作用于输入,然后将其作为输出传递,我认为通常是这样stdout- 但有些命令只会接受stdin并对其执行任何操作,并且不输出任何内容。

我最熟悉 OS X,因此立即想到的两个是pbcopypbpaste- 这是访问系统剪贴板的方法。

无论如何,我知道如果我想获取 stdout 并将输出吐出到两个stdout文件中,那么我可以使用该tee命令。我对 有所了解xargs,但我认为这不是我要找的。

我想知道如何拆分stdout以在两个(或更多)命令之间切换。例如:

cat file.txt | stdout-split -c1 pbcopy -c2 grep -i errors

可能有一个比那个更好的例子,但我真的很想知道如何将标准输出发送到不中继它的命令,同时避免stdout被“静音” - 我不是问如何发送cat文件和grep它的一部分并将其复制到剪贴板 - 具体命令并不那么重要。

另外 - 我不是问如何将其发送到文件stdout- 这可能是一个“重复”问题(抱歉),但我做了一些查找,只能找到类似的问题,询问如何在标准输出和文件之间进行拆分- 这些问题的答案似乎是tee,我认为这对我不起作用。

最后,您可能会问“为什么不将 pbcopy 作为管道链中的最后一件事呢?”我的回答是 1)如果我想使用它并且仍然在控制台中看到输出怎么办? 2)如果我想使用两个stdout处理输入后不输出的命令怎么办?

哦,还有一件事 - 我意识到我可以使用tee命名管道 ( mkfifo),但我希望有一种方法可以内联、简洁地完成此操作,无需事先设置:)

答案1

您可以使用tee并处理替换:

cat file.txt | tee >(pbcopy) | grep errors

这会将 的所有输出发送到cat file.txt,并且您只能在控制台上pbcopy获得 的结果。grep

您可以在该tee部分中放置多个进程:

cat file.txt | tee >(pbcopy) >(do_stuff) >(do_more_stuff) | grep errors

答案2

您可以向 指定多个文件名tee,此外,标准输出可以通过管道输送到一个命令中。要将输出分派到多个命令,您需要创建多个管道并将每个管道指定为 的一个输出tee。做这件事有很多种方法。

工艺替代

如果您的 shell 是 ksh93、bash 或 zsh,则可以使用进程替换。这是一种将管道传递给需要文件名的命令的方法。 shell 创建管道并像/dev/fd/3命令一样传递文件名。号码是文件描述符管道连接到的。某些 UNIX 变体不支持/dev/fd;在这些上,使用命名管道来代替(见下文)。

tee >(command1) >(command2) | command3

文件描述符

在任何 POSIX shell 中,您可以使用多个文件描述符明确地。这需要一个支持 的 unix 变体/dev/fd,因为除了其中一个输出之外的所有输出tee都必须通过名称指定。

{ { { tee /dev/fd/3 /dev/fd/4 | command1 >&9;
    } 3>&1 | command2 >&9;
  } 4>&1 | command3 >&9;
} 9>&1

命名管道

最基本和可移植的方法是使用命名管道。缺点是您需要找到一个可写目录,创建管道,然后进行清理。

tmp_dir=$(mktemp -d)
mkfifo "$tmp_dir/f1" "$tmp_dir/f2"
command1 <"$tmp_dir/f1" & pid1=$!
command2 <"$tmp_dir/f2" & pid2=$!
tee "$tmp_dir/f1" "$tmp_dir/f2" | command3
rm -rf "$tmp_dir"
wait $pid1 $pid2

答案3

只需玩一下进程替换即可。

mycommand_exec |tee >(grep ook > ook.txt) >(grep eek > eek.txt)

grepmycommand_exec是两个二进制文件,其输出与其流程特定的输入相同。

答案4

还有pee来自更多实用程序包裹。它是为此而设计的:

pee 'command1' 'command2' 'cat -'

相关内容