我试图在固定数量的处理器上动态运行许多进程。我想将输出打印到每个进程的唯一文件,但是xargs没有使用就地文件名为每个进程创建单独的文件存在一些问题。
Bash脚本调用Csh脚本,如下所示:
$ cat temp | xargs -P 8 % csh '%'.csh >& '%'.log
其中temp是csh命令名的文本文件。
我的问题是xargs按字面意思取%.log
并在进程写入时不断覆盖文件,而不是根据需要单独.log
个文件。
我将此脚本作为$ bash run.bash &
答案 0 :(得分:1)
通常,使用字符串替换代替代码是一个坏主意 - 在您的情况下,如果您有一个带有恶意名称的脚本,该名称可用于运行任意命令。 (当然,你正在执行脚本,但同样适用于你纯粹处理数据和输出文件名的情况 - 因此最好养成强大方法的习惯)。
将名称作为参数传递给脚本,而不是将它们替换为脚本(如果您通过添加修复其用法,xargs
将会这样做-I
或-J
参数:
# best-practice approach: run a completely fixed shell script, passing arguments on
# its command line.
xargs -P 8 -n 1 \
sh -c 'for x; do csh "${x}.csh" >"${x}.log" 2>&1; done' _
你会注意到有一个sh -c
实例被调用:这是必需的,因为xargs
本身不理解shell操作,例如重定向;如果你想要执行重定向,你需要一个shell来完成它。
现在,让我们再详细说明原始代码的行为原因:
xargs -P 8 % csh '%'.csh >& '%'.log
... 首先执行重定向到%.log
,然后运行命令
xargs -P 8 % csh '%'.csh
xargs
没有机会替换%.log
字符串,因为在 xargs
命令运行之前,重定向是由封闭的shell 执行的
答案 1 :(得分:1)
使用GNU Parallel看起来像这样:
cat temp | parallel -P 8 'csh {}.csh >& {}.log'
如果您有8个核心,您甚至可以这样做:
cat temp | parallel 'csh {}.csh >& {}.log'
GNU Parallel引用{},以便不会执行恶意输入。