cat a.txt | xargs -I % echo %
在上面的示例中,xargs echo %
作为命令参数。但是在某些情况下,我需要多个命令而不是一个来处理参数。例如:
cat a.txt | xargs -I % {command1; command2; ... }
但是xargs不接受这种形式。我知道的一个解决方案是,我可以定义一个包装命令的函数,但这不是管道,我不喜欢它。还有其他解决方案吗?
while
可以包含多个命令的循环的边缘。
cat a.txt | xargs -I % echo %
在上面的示例中,xargs echo %
作为命令参数。但是在某些情况下,我需要多个命令而不是一个来处理参数。例如:
cat a.txt | xargs -I % {command1; command2; ... }
但是xargs不接受这种形式。我知道的一个解决方案是,我可以定义一个包装命令的函数,但这不是管道,我不喜欢它。还有其他解决方案吗?
while
可以包含多个命令的循环的边缘。
Answers:
cat a.txt | xargs -d $'\n' sh -c 'for arg do command1 "$arg"; command2 "$arg"; ...; done' _
<a.txt xargs -d $'\n' sh -c 'for arg do command1 "$arg"; command2 "$arg"; ...; done' _
要解释一些更好的观点:
出于安全考虑,使用"$arg"
代替代替%
(并且-I
在xargs
命令行中没有)是:在sh
的命令行参数列表中传递数据而不是将其替换为代码可防止数据可能包含的内容(例如$(rm -rf ~)
,特别是恶意示例)作为代码执行。
类似地,使用的-d $'\n'
是GNU扩展名,该扩展xargs
名将输入文件的每一行都视为一个单独的数据项。-0
为防止xargs尝试对读取的流进行类shell(但不完全与 shell兼容)的解析,必须使用this或(期望使用NUL而不是换行符)。(如果您没有GNU xargs,则可以不用tr '\n' '\0' <a.txt | xargs -0 ...
来获取面向行的阅读-d
)。
的_
是一个占位符$0
,以使得加入由其它数据值xargs
成为$1
和向前,这恰好是默认设定值的一个for
循环迭代。
sh -c
-请注意,每个命令后的分号不是可选的,即使它是列表中的最后一个命令。
command1
和周围有花括号command2
;后来我意识到它们不是必需的。
}
:sh -c '{ command1; command2; }' -- but it's not required at the end of a command sequence that doesn't use braces:
sh -c'command1; command2'`
%
在你的字符串传递给字符的地方sh -c
,那么这是容易出现安全漏洞:包含文件名的$(rm -rf ~)'$(rm -rf ~)'
(这是一个完全合法的子串有共同的UNIX文件系统的文件名之内!)会引起别人一个非常糟糕的一天。
使用GNU Parallel,您可以:
cat a.txt | parallel 'command1 {}; command2 {}; ...; '
观看介绍性视频以了解更多信息:https : //www.youtube.com/playlist?list=PL284C9FF2488BC6D1
出于安全原因,建议您使用软件包管理器进行安装。但是,如果您不能这样做,则可以使用此10秒钟的安装。
10秒的安装将尝试进行完整安装;如果失败,则进行个人安装;如果失败,则进行最小安装。
$ (wget -O - pi.dk/3 || lynx -source pi.dk/3 || curl pi.dk/3/ || \
fetch -o - http://pi.dk/3 ) > install.sh
$ sha1sum install.sh | grep 3374ec53bacb199b245af2dda86df6c9
12345678 3374ec53 bacb199b 245af2dd a86df6c9
$ md5sum install.sh | grep 029a9ac06e8b5bc6052eac57b2c3c9ca
029a9ac0 6e8b5bc6 052eac57 b2c3c9ca
$ sha512sum install.sh | grep f517006d9897747bed8a4694b1acba1b
40f53af6 9e20dae5 713ba06c f517006d 9897747b ed8a4694 b1acba1b 1464beb4
60055629 3f2356f3 3e9c4e3c 76e3f3af a9db4b32 bd33322b 975696fc e6b23cfb
$ bash install.sh
这只是没有xargs或cat的另一种方法:
while read stuff; do
command1 "$stuff"
command2 "$stuff"
...
done < a.txt
IFS
,否则它将忽略文件名中的前导和尾随空格;除非您添加-r
,否则带文字反斜杠的文件名将忽略这些字符。
xargs
。(很难扩展以执行类似于GNU xargs
' -P<n>
选项的操作)
$ command | while read line; do c1 $line; c2 $line; done
您可以使用
cat file.txt | xargs -i sh -c 'command {} | command2 {} && command3 {}'
{} =文本文件中每一行的变量
file.txt
包含带有$(rm -rf ~)
子字符串的基准该怎么办?
我要做的一件事是将.bashrc / .profile添加到此函数:
function each() {
while read line; do
for f in "$@"; do
$f $line
done
done
}
然后你可以做
... | each command1 command2 "command3 has spaces"
它比xargs或-exec更为冗长。您也可以修改该函数,以将读取的值插入命令中的任意位置(每个命令中的位置),如果您也需要这样做的话。
我更喜欢允许空运行模式(不带| sh
)的样式:
cat a.txt | xargs -I % echo "command1; command2; ... " | sh
也适用于管道:
cat a.txt | xargs -I % echo "echo % | cat " | sh
-P
选项为止(如果没有,我主要使用-exec
on find
,因为我的输入主要是文件名)
晚会晚了。
我使用以下格式在迁移之前用数千个小文件压缩目录。如果您在命令中不需要单引号,则应该可以使用。
经过一些修改,我相信它将对某人有用。在Cygwin
(babun)中测试
find . -maxdepth 1 ! -path . -type d -print0 | xargs -0 -I @@ bash -c '{ tar caf "@@.tar.lzop" "@@" && echo Completed compressing directory "@@" ; }'
find .
在此处查找
-maxdepth 1
请勿进入子目录
! -path .
Exclude。/当前目录路径
-type d
仅匹配目录
-print0
用空字节分隔输出\ 0
| xargs
到xargs的管道
-0
输入是空分隔字节的
-I @@
占位符是@@。用输入替换@@。
bash -c '...'
运行Bash命令
{...}
命令分组
&&
仅在前一个命令成功退出(退出0)时才执行下一个命令
最终;
很重要,否则它将失败。
输出:
Completed compressing directory ./Directory1 with meta characters in it
Completed compressing directory ./Directory2 with meta characters in it
Completed compressing directory ./Directory3 with meta characters in it
2018年7月更新:
如果您喜欢黑客和游戏,这里有一些有趣的事情:
echo "a b c" > a.txt
echo "123" >> a.txt
echo "###this is a comment" >> a.txt
cat a.txt
myCommandWithDifferentQuotes=$(cat <<'EOF'
echo "command 1: $@"; echo 'will you do the fandango?'; echo "command 2: $@"; echo
EOF
)
< a.txt xargs -I @@ bash -c "$myCommandWithDifferentQuotes" -- @@
输出:
command 1: a b c
will you do the fandango?
command 2: a b c
command 1: 123
will you do the fandango?
command 2: 123
command 1: ###this is a comment
will you do the fandango?
command 2: ###this is a comment
说明:
-创建单个线性脚本并将其存储在变量中
- 作为脚本xargs
读取a.txt
并执行-确保每次传递整行-放置在后确保将其作为位置参数输入到命令,而不是start ,即喜欢自己,这意味着bash
@@
@@
--
@@
bash
bash
OPTION
-c
run command
--
是神奇的,它与许多其他的东西,即ssh
,即使kubectl
find . -type f -print0|xargs -r0 -n1 -P20 bash -c 'f="{}";ls -l "$f"; gzip -9 "$f"; ls -l "$f.gz"'
转换循环时,它稍微容易一些)
"$@"
以避免这种情况的唯一方法是...(-n1
如果要限制参数的数量))
--
是,shell使用它来表示不再接受任何选项。这也允许在-
后面有一个--
。如果不添加,则可能会得到非常有趣且令人困惑的输出,例如grep -r
当您包含在模式中时-
!尽管您所说的话方式并不能澄清这一点,但并不能真正解释其工作原理。Iirc这是POSIX的事情,但我认为无论如何都值得指出。只是要考虑的事情。而且我喜欢奖金!
这似乎是最安全的版本。
tr '[\n]' '[\0]' < a.txt | xargs -r0 /bin/bash -c 'command1 "$@"; command2 "$@";' ''
(-0
可以删除并tr
用重定向替换(或该文件可以用空分隔的文件代替)。它主要在此,因为我主要xargs
与find
with -print0
输出配合使用)(这也可能与xargs
没有-0
扩展名的版本有关)
这是安全的,因为args在执行时会将参数作为数组传递给Shell。bash
当使用以下命令获取所有内容时,shell(至少)会将它们作为未更改的数组传递给其他进程["$@"][1]
如果使用...| 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个:
tr '[\n]' '[\0]' < a.txt | xargs -r0 -n10 -P32 /bin/bash -c 'command1 "$@"; command2 "$@";' ''
对于输入中的任何特殊字符,这应该是可靠的。(如果输入为null分隔。)tr
如果某些行包含换行符,则版本将获得一些无效输入,但是对于换行符分隔的文件,这是不可避免的。
的空白第一个参数bash -c
是由于以下原因:(来自bash
手册页)(感谢@clacke)
-c If the -c option is present, then commands are read from the first non-option argument com‐
mand_string. If there are arguments after the command_string, the first argument is assigned to $0
and any remaining arguments are assigned to the positional parameters. The assignment to $0 sets
the name of the shell, which is used in warning and error messages.
"$@"
bash -c 'command1 "$@"; command2 "$@";' arbitrarytextgoeshere
bash
with -c
首先(在命令之后)使用一个参数作为流程的名称,然后使用位置参数。尝试bash -c 'echo "$@" ' 1 2 3 4
看看结果如何。
对我有用的另一种可能的解决方案是-
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 $>
ls | xargs -I % sh -c 'echo 1 "%"; echo 2 "%"'