每行管道输入执行一次命令?

每行管道输入执行一次命令?

我想为每场比赛运行一次java命令ls | grep pattern -。在这种情况下,我认为我可以这样做,find pattern -exec java MyProg '{}' \;但我对一般情况很好奇 - 有没有一种简单的方法可以说“为标准输入的每一行运行一次命令”? (在鱼或bash中。)

答案1

接受的答案想法是对的,但关键是要通过xargsswitch -n1,也就是说“每个命令行最多使用 1 个参数”:

cat file... | xargs -n1 command

或者,对于单个输入文件,您可以cat完全避免使用管道,只需使用:

<file xargs -n1 command

更新于2020年8月5日:

我还想对用户 Jander 评论中的建议做出回应,尽管其中包含一些错误信息,但该评论得到了大力支持,我现在将对此进行解释。

不要急于推荐-L的选项xargs,而不提及它(所谓的)的麻烦尾随空白功能可导致。在我看来,这种转变弊大于利,并且对于以下情况而言,这无疑是一种延伸-L 1一次对一个非空行进行操作。公平地说,手册页确实xargs阐明了特征(即问题)伴随着开关而来-L

由于 Jander 在向那些仓促且毫无戒心的 StackOverflow 受众寻求快速提示而没有时间做诸如阅读手册页之类乏味的事情而不是接受评论和答案作为福音时,没有提及这些问题-L,所以我现在将介绍我的理由-L如果没有仔细了解旅途中携带的所有行李,这是一个非常糟糕的建议。

为了说明我对 的蔑视-L,让我们考虑一个简单的输入文件,其中包含某人不小心输入的以下文本(可能是一名高中暑期实习生,在他/她的培训中创建了此数据文件,其证据是窗式文件名。幸运的是(业力?),您已被管理层选为新的托管人):

testdata.txt

1
2␠
3

由于包含数字的行2有一个空格字符(在前面的代码中的SYMBOL FOR SPACE数字后面显示为 Unicode 字形2,以防您的浏览器字体没有该字符的视觉表示),因此命令使用xargs -L1,例如:

<testdata.txt xargs -L1 echo

...,会产生以下(也许令人惊讶的)输出:

1
2 3

这是由于-Lswitch 指示xargs将后续行附加到以空格结尾的行,这种行为可能只会在那些奇怪的时刻影响结果输出,其中行没有正确修剪尾随空白 - 等待正确的输入文件出现的定时炸弹错误。

另一方面,使用,-n 1开关代替的相同命令会产生更可接受的输出:xargs-L 1

1
2␠
3

这还不是最糟糕的!与强制“可怕”选项生效不同的是,该-L开关。如果遇到它认为对于其运行环境来说太长的命令行,这会导致进程终止。-n-xxargsxargs

由许多行组成的输入文件连续带有尾随空白,按照交换机的指示及其在混合物中-L使用称为“代理”的化学试剂,如果将所有这些内容串联成一个,则可能会导致中流终止-xxargs超线超出xargs' 的定义线太长对于命令行。如果事情开始变得模糊,请考虑一下线太长xargs是根据为其运行的平台指定的最大长度确定的大小,并通过看似的进一步偏移来确定任意常数正如手册页中更详细地解释的那样。还记得微积分中那些烦人的不定积分及其原理吗?任意常数在测验或测试中丢分,因为您忘记+ C在不定积分的解后写下?好吧,如果将其添加-L到您方便的xargs工具箱中,这句话又回来了,再次咬您的后背。

另一方面,-n值只会将这些长行切成(希望如此)小的一口大小的单行块,并一次执行一个为每个块提供的命令,而不考虑它们是否是否以空格结尾。不再需要排长队,不再需要突然终止而在背后捅你一刀——Et tu,Brute1xargsxargs -x

关于 xargs 手册页中措辞的可选 Segue

不知道为什么用词暧昧不规范空白在整个手册页中使用xargs,而不是定义更好且不那么模糊的选项,例如:

  • 空格,如果空白表示一个或多个ASCII 空格人物
  • 除换行符之外的空格(如果是这样的话)空白暗示)
  • 一组中的一个或多个不可打印字符:{空格、水平制表符}(如果空白被用作这个可怕的二人组的同义词)

更新于 2021 年 6 月 15 日:

用户 @BjornW 询问如何xargs使用每个命令运行一次命令线输入的内容而不仅仅是输入的单词。 (看,我确实读过这些评论,我只会责怪它花了七个月的时间才对 Covid 做出回应:P)。

本着最初问题的精神,为了使我的答案适用于更多的用例,我想详细讨论这个特定的场景。

考虑以下输入文件。它充满了人们在实际工作中可能遇到的各种边缘情况真实世界™(例如,前导/尾随空格、仅由空格组成的行、空行、以连字符开头的行[不应被解释为引入开关]等):

lines.txt

a1 a22 a333 a4444
b4444 b333 b22 b1
␠␠c d e f g
hhh
ii jj kk␠
␠␠␠
-L and -x are the gruesome twosome

在前面的输入文件中,Unicode 字符OPEN BOXU+2423 用于标记空行,并且 UnicodeSYMBOL FOR SPACE用于前导和尾随空格,以使它们更加突出。

假设我们想要在每一行输入上运行一个命令,作为一个整体,并作为单个参数传递给我们的命令,无论内容如何(包括没有内容)。我们将使用 来进行此操作xargs,如下所示(注意:printf将是我们的示例命令,并且%q将使用格式说明符,以便将提供的参数括在撇号中,以便清楚起见,当存在空格或参数是空字符串时 - 全部在,只有我们的hhh输入行“毫发无伤”,%q正如您将在输出中看到的那样,如果存在任何不可打印的字符,它们也会通过%q使用 POSIX$''引用语法进行转义]):

<lines.txt xargs -n1 -d'\n' printf -- 'Input line: %q\n'

输出如下:

Input line: 'a1 a22 a333 a4444'
Input line: 'b4444 b333 b22 b1'
Input line: '   c d e f g'
Input line: ''
Input line: hhh
Input line: 'ii jj kk '
Input line: ''
Input line: '   '
Input line: '-L and -x are the gruesome twosome'
Input line: ''
Input line: ''
Input line: ''

所以你有它。使用该-d开关,我们可以指定应在输入文件中查找的分隔符,xargs以指示参数结束的位置和下一个参数开始的位置。通过将其设置为'\n'本身xargs足够聪明,可以解释为C风格的字符转义-d正如其页面上的开关描述中所述man,我们可以使用xargs将整行输入作为参数转发到我们选择的命令,而我们只需付出最少的努力。

我还想提一下,它xargs可以用于连接多行输入(附带一个警告,我将在本段末尾详细说明),对于需要这种行为的极少数情况,并将它们作为单个参数转发给我们命令。这可以通过将上面的调用命令中传递给-nswitch的数字设置xargs为一个值来完成,该值指示应合并到单个参数中的输入行数,并\n在过程中删除行尾。不幸的是,这种换行剥离行为使得上述xargs方法不适用于许多用例,因为指示一行结束位置和下一行开始位置的信息会在此过程中丢失。

答案2

在 Bash 或任何其他 Bourne 风格的 shell(ash、ksh、zsh 等)中:

while read -r line; do command "$line"; done

read -r从标准输入读取一行(read-r解释反斜杠,你不希望这样)。因此,您可以执行以下任一操作:

$ command | while read -r line; do command "$line"; done  

$ while read -r line; do command "$line"; done <file

答案3

就是这样xargs

... | xargs command

答案4

GNU Parallel 就是为此类任务而设计的。最简单的用法是:

cat stuff | grep pattern | parallel java MyProg

观看介绍视频以了解更多信息:http://www.youtube.com/watch?v=OpaiGYxkSuQ

相关内容