如何在 shell(bash)中执行多个命令并构建管道?

4

我正在尝试在Bash shell中将awk命令的输出一次性传递给多个命令,根据我的经验,我提出了以下解决方案:

awk '$13 ~ /type/ {print $15}' filename.txt | (wc -l || sort -u)

我希望能够同时计算和排序awk命令的结果,我该如何实现? 即使使用&&命令也不起作用,它只执行第一个命令然后退出。 我想这是我对bash知识的不足造成的。
提前感谢。
5个回答

5
如果您想在一行中将输出发送到两个不同的命令,则需要进行进程替换。
请尝试以下操作:
awk '$13 ~ /type/ {print $15}' filename.txt | tee >(wc -l >&2) | sort -u

这将在stderr上输出行数,并在stdout上输出排序后的结果。如果你需要在stdout上输出行数,可以省略>&2,但它会被传递给sort命令,并且很可能会被排到输出的顶部。注意:本文已根据进一步测试更正了描述。

@Lex:如果以“sh”调用bash,则会进入兼容模式,进程替换将无法工作。显式地将shell称为“bash”,那么它应该可以正常工作。 - goldPseudo
这个可以运行,但不够简洁: awk '$13 ~ /type/ {print $15}' filename.txt | tee test.txt | sort -u ; cat test.txt | wc -l - OverLex
无论如何,将其选为被接受的答案,因为它更精确地回答了我的问题。 - OverLex
2
它对我有效,但请注意这是一个特定于bash的功能。它肯定不会在sh或以bash-invoked-as-sh形式工作,我不知道哪些其他shell有它(例如ksh,zsh等)。它也无法与busybox的shell一起使用,该shell用于许多安装程序和伪装为bash的嵌入式设备。 - Walter Mundt
1
@Walter:它在ksh93、bash和zsh中有效,但在更基本的shell(如pdksh、ash或busybox)中无效。 - Gilles 'SO- stop being evil'

4
在这种情况下,您可以在awk中进行计数,为什么需要管道呢?不要让它变得更加复杂。
awk '$13 ~ /type/ {print $15;c++}END{print c} ' filename.txt | sort -u

1
如果输出的大小不太大而且您不需要wcsort命令并行工作以提高性能,那么这里有一个相对简单的解决方案:
output=$(awk '$13 ~ /type/ {print $15}' filename.txt; echo a)
printf "%s" "${output%a}" | sort -u
printf "%s" "${output%a}" | wc -l

关于额外的a的复杂性是为了防止awk命令在输入末尾打印一些空行,而$()结构会将其剥离。您可以轻松选择sortwc中哪个应该先出现。


这里有一种适用于任何 POSIX shell(ash,bash,ksh,zsh等)但仅适用于具有/dev/fd的系统的方法(其中包括相当近期的Linux,*BSD和Solaris)。与{{link1:Walter使用bash,ksh93和zsh中可用的更简单方法进行类似构造}}相似,wc的输出和sort的输出可能会交错在一起。
{
  awk '$13 ~ /type/ {print $15}' filename.txt |
  tee /dev/fd3 |
  wc -l
} 3>&1 1>&3 | sort -u

如果您需要处理不适合内存的中间输出,并且不想让两个命令的输出混合在一起,我认为在POSIX shell中没有简单的方法,但使用ksh或zsh协同进程应该是可行的。


0
我认为更重要的问题是:你期望输出是什么?
如果你想做两件事情,那就分别去做。
awk '$13 ~ /type/ {print $15}' filename.txt > tempfile
wc -l < tempfile
sort -u < tempfile
rm tempfile

请看我的编辑,了解如何在不重复使用awk的情况下完成它。总的来说,即使你找到了实现你想要的功能的方法,也不要这样做。你永远不应该有意地编写令人困惑的代码。 - riwalk
我没有觉得它令人困惑,我只是认为这样做更有效率。 - OverLex
哦,抱歉,我没有意识到,你是对的,下次我一定会注意的。 :) - OverLex
1
'cat tempfile > sort -u' 相当于 'cat tempfile -u > sort'。你可能想使用 '|',这种情况下你有 UUOC(使用无用的 cat 命令)。只需执行 'sort -u < tempfile' 即可。 - William Pursell
@Stargazer712:除非输出内容太大而无法在内存中容纳,否则没有理由使用临时文件,这正是 $(...) 的用途。此外,创建临时文件是一个非常棘手的问题:如果当前目录不可写怎么办?如果脚本的两个实例同时运行怎么办?等等。 - Gilles 'SO- stop being evil'
显示剩余4条评论

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接