我试图并行运行许多命令,并且需要先对输入进行一些字符串操作。如何使以下示例有效?
find . -mindepth 1 -type d | xargs -n 1 -P 20 -i sh -c "v={}; echo $v"
当我使用它时,$v
为空。为什么不将其保存为{}
的值?
答案 0 :(得分:2)
在将字符串传递给$v
之前,父shell正在展开xargs
。
假设您的find
命令找到名为./stuff
的子目录。
首先,父bash
shell(您输入find
命令的那个)将展开$v
,因为该字符串是双引号。您目前没有为变量v
设置值,因此它会扩展为空字符串。
接下来,参数传递给xargs
,这将看到:v={}; echo
然后,xargs
将从管道中读取./stuff
,并将{}
替换为./stuff
最后,sh
命令由xargs
执行,sh
会看到:v=./stuff; echo
要解决此问题,您需要转义$
以使父shell不扩展它,或使用单引号来避免变量扩展。您还应该引用字符串,以便其中包含空格的任何目录名称不会导致最终sh
命令出现问题:
find . -mindepth 1 -type d | xargs -n 1 -P 20 -i sh -c "v=\"{}\"; echo \"\$v\""
OR
find . -mindepth 1 -type d | xargs -n 1 -P 20 -i sh -c 'v="{}"; echo "$v"'
使用任一命令,最终sh
进程都会看到:v="./stuff"; echo "$v"
顺便说一句,一种方法可以自己确定这确实发生了什么,就是在父shell中为v
设置一个值,然后运行原始命令。 shell会将$v
扩展为您设置的任何值,您将看到find
找到的每个目录重复该值。
$ v=foobar
$ find . -mindepth 1 -type d | xargs -n 1 -P 20 -i sh -c "v={}; echo $v"
foobar
foobar
foobar
foobar
foobar
foobar
foobar
foobar
foobar
foobar
foobar
...
答案 1 :(得分:0)
使用GNU Parallel,您可以:
find . -mindepth 1 -type d | parallel -P 20 'v={}; echo "$v"'