【问题标题】:In a shell (bash) How can I execute more than one command in a pipeline?在 shell (bash) 中,如何在管道中执行多个命令?
【发布时间】:2010-08-03 15:29:11
【问题描述】:

我正在尝试在 Bash shell 中一次通过多个命令通过管道输出 awk 命令的输出,据我所知,我想出了这个:

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

我希望对 awk 命令的结果进行计数和排序,我该如何实现呢? 即使使用 && 命令它也不起作用,它会执行第一个命令然后退出。 我想这是我对 bash 的了解失败了。

提前致谢。

【问题讨论】:

    标签: bash shell awk pipeline


    【解决方案1】:

    如果您想在一行中将输出发送到两个不同的命令,则需要进行进程替换。

    试试这个:

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

    这会在 stderr 上输出行数,在 stdout 上输出排序后的输出。如果您需要 stdout 上的行数,您可以省略 >&2,但随后它将被传递给排序调用并(很可能)排序到输出的顶部。

    编辑:根据进一步测试更正了对所发生情况的描述。

    【讨论】:

    • @Lex:如果 bash 以sh 调用,它将进入兼容模式,进程替换将不起作用。将 shell 显式调用为 bash 应该没问题。
    • 这可行,但不是那么整洁:awk '$13 ~ /type/ {print $15}' filename.txt |三通测试.txt |排序 -u ;猫测试.txt | wc -l
    • 无论如何都投票接受,因为它更准确地回答了我的问题。
    • 它适用于我,但请注意这是一个特定于 bash 的功能。它肯定不会在 sh 或 bash-invoked-as-sh 上工作,而且我不知道其他哪些 shell 有它(例如 ksh、zsh 等)。它也不适用于busybox的shell,它用于许多伪装成bash的安装程序和嵌入式设备。
    • @Walter:它适用于 ksh93、bash 和 zsh,但不适用于更基本的 shell,例如 pdksh、ash 或 busybox。
    【解决方案2】:

    在这种情况下,你在 awk 中计数,为什么需要管道?不要让它变得更复杂

    awk '$13 ~ /type/ {print $15;c++}END{print c} ' filename.txt | sort -u
    

    【讨论】:

      【解决方案3】:

      如果输出中的大小不是太大而无法放入内存,并且出于性能原因您不需要 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)的系统。和Walter's similar construction using the simpler method available in bash, ksh93 and 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 协进程。

      【讨论】:

        【解决方案4】:

        您希望将使用 mkfifo 创建的命名管道与 tee 结合使用。一个例子是http://www.softpanorama.org/Tools/tee.shtml

        【讨论】:

          【解决方案5】:

          我认为更大的问题是:您期望输出是什么?

          如果你想做两件事,那就做两件事:

          awk '$13 ~ /type/ {print $15}' filename.txt > tempfile
          wc -l < tempfile
          sort -u < tempfile
          rm tempfile
          

          【讨论】:

          • 我希望我的输出是两行或多行,一行带有一个结果(行数),另一行(或更多)带有某种 awk 命令的结果。我想知道是否甚至可以在一行中执行此操作,因为我将不得不重复 awk 命令或将其结果分配给变量。
          • 查看我的编辑以了解如何在不重复 awk 的情况下执行此操作。一般来说,即使你找到了一种方法来做你想做的事情,也不要去做。永远不要故意编写令人困惑的代码。
          • 我没有觉得它令人困惑,我只是觉得这样做更有效率。
          • 但是您必须在 StackOverflow.com 上询问如何操作。清晰总是优于晦涩。
          • 'cat tempfile > sort -u' 等价于'cat tempfile -u > sort'。你可能打算使用'|',在这种情况下你有UUOC。只需执行 'sort -u
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2023-03-31
          • 1970-01-01
          • 2017-05-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多