您可以使用
cat file.txt | xargs -i sh -c 'command {} | command2 {} && command3 {}'
{} =文本文件中每一行的变量
使用GNU Parallel,您可以:
cat a.txt | parallel 'command1 {}; command2 {}; ...; '
观看介绍视频以了解更多信息: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1
我更喜欢允许干运行模式的风格(没有 | sh ):
| sh
cat a.txt | xargs -I % echo "command1; command2; ... " | sh
也适用于管道:
cat a.txt | xargs -I % echo "echo % | cat " | sh
对我有用的另一个可能的解决方案是 -
cat a.txt | xargs bash -c 'command1 $@; command2 $@' bash
注意最后的'bash' - 我假设它作为argv [0]传递给bash。如果没有此语法,则每个命令的第一个参数都将丢失。它可能是任何一个词。
例:
cat a.txt | xargs -n 5 bash -c 'echo -n `date +%Y%m%d-%H%M%S:` ; echo " data: " $@; echo "data again: " $@' bash
我目前的BKM是这样的
... | xargs -n1 -I % perl -e 'system("echo 1 %"); system("echo 2 %");'
不幸的是,这使用了perl,它比bash更不可能安装;但它处理接受答案的更多输入。 (我欢迎一个不依赖于perl的无处不在的版本。)
@ KeithThompson的建议
... | xargs -I % sh -c 'command1; command2; ...'
很棒 - 除非你的输入中有shell注释字符#,在这种情况下,第一个命令的一部分和第二个命令的所有部分都将被截断。
如果输入来自文件系统列表(例如ls或find),并且编辑器在其名称中创建带有#的临时文件,则哈希#可能非常常见。
问题示例:
$ bash 1366 $> /bin/ls | cat #Makefile# #README# Makefile README
糟糕,这是问题所在:
$ bash 1367 $> ls | xargs -n1 -I % sh -i -c 'echo 1 %; echo 2 %' 1 1 1 1 Makefile 2 Makefile 1 README 2 README
啊,那更好:
$ bash 1368 $> ls | xargs -n1 -I % perl -e 'system("echo 1 %"); system("echo 2 %");' 1 #Makefile# 2 #Makefile# 1 #README# 2 #README# 1 Makefile 2 Makefile 1 README 2 README $ bash 1369 $>
这似乎是最安全的版本。
tr '[\n]' '[\0]' < a.txt | xargs -r0 /bin/bash -c 'command1 "$@"; command2 "$@";'
( -0 可以删除和 tr 替换为重定向(或者文件可以替换为空分隔文件)。因为我主要使用它主要在那里 xargs 同 find 同 -print0 输出)(这也可能与之相关 xargs 没有的版本 -0 延期)
-0
tr
xargs
find
-print0
它是安全的,因为args会将参数传递给shell,作为执行它的数组。壳(至少 bash 然后,当使用获得所有进程时,它们将作为未更改的数组传递给其他进程 ["$@"][1]
bash
["$@"][1]
如果你使用 ...| xargs -r0 -I{} bash -c 'f="{}"; command "$f";' ,如果字符串包含双引号,则赋值将失败。对于每个使用的变体都是如此 -i 要么 -I 。 (由于它被替换为字符串,您始终可以通过在输入数据中插入意外字符(如引号,反引号或美元符号)来注入命令)
...| xargs -r0 -I{} bash -c 'f="{}"; command "$f";'
-i
-I
如果命令一次只能获取一个参数:
tr '[\n]' '[\0]' < a.txt | xargs -r0 -n1 /bin/bash -c 'command1 "$@"; command2 "$@";'
或者使用更少的进程:
tr '[\n]' '[\0]' < a.txt | xargs -r0 /bin/bash -c 'for f in "$@"; do command1 "$f"; command2 "$f"; done;'
如果你有GNU xargs 或另一个与 -P 扩展并且您希望并行运行32个进程,每个进程对每个命令不超过10个参数:
-P
tr '[\n]' '[\0]' < a.txt | xargs -r0 -n10 -P32 /bin/bash -c 'command1 "$@"; command2 "$@";'
这应该对输入中的任何特殊字符都很健壮。 (如果输入为空分隔。) tr 如果某些行包含换行符,则版本将获得一些无效输入,但对于换行符分隔文件,这是不可避免的。
我做的一件事是添加.bashrc / .profile这个函数:
function each() { while read line; do for f in "$@"; do $f $line done done }
然后你可以做的事情
... | each command1 command2 "command3 has spaces"
它比xargs或-exec更简洁。如果您还需要该行为,您还可以修改函数以将读取的值插入命令中的任意位置。
这只是没有xargs和cat的另一种方法:
while read stuff; do command1 "$stuff" command2 "$stuff" ... done < a.txt