并行变量声明 sh -c …

并行变量声明 sh -c …

find我一直在尝试处理with的输出parallel,这又调用了 shell(需要一些文本替换)。我观察到一些奇怪的行为,我无法向自己解释。

每个目录中都有一堆文件,称它们为file1.xtc, file2.xtc.其中一些具有诸如 等名称file1.part0002.xtc。如果传递的文件find具有该*.part000x.*名称,我需要删除该*.part000x.*位,以便生成的命令类似于

command -f file1.part0001.xtc -s file1.tpr 

我使用了findandparallel达到了这个效果,但是parallel的替换(特别是位{.})还不够充分(它们删除了.xtc扩展名,留下了.part0001单独的),所以这是我用来检查输出的命令:

find 1st 2nd 3rd -name '*.xtc' -print0 | parallel -0 sh -c 'name=""; name="{.}"; echo {.} ${name%.*}.tpr'

如果我使用上面的命令,首先声明name并为其分配一个空字符串(或任何其他与此相关的内容),结果是

file1.part0001 file1.tpr

根据需要(这些是我的命令需要使用的名称)。但是,如果我运行这个

find 1st 2nd 3rd -name '*.xtc' -print0 | parallel -0 sh -c 'name="{.}"; echo {.} ${name%.*}.tpr'

结果是:

file1.part0001 .tpr

或者它表现得好像$name不存在一样。

所以我的问题是:

- 这种行为的原因是什么?

- 处理这个问题的首选方式是什么?

第一个问题在这里更重要,因为我上面使用的方法是一种解决方法,虽然不太漂亮,但有效。这不是我第一次需要进行这样的文本替换,这种行为仍然让我感到困惑。

输出sh --version

GNU bash, version 3.2.48(1)-release (x86_64-apple-darwin11)

我安装和使用的较新版本的输出,bash而不是sh在上面的命令中(达到相同的效果)(/usr/local/bin/bash --version

GNU bash, version 4.2.0(1)-release (i386-apple-darwin11.4.2)

答案1

你的问题与bash无关。事实上,既然你告诉parallel运行sh,你甚至可能没有使用bash

问题是,正如其文档所示,parallel 并不是 xargs 的真正替代品。相反,它将其参数累积到单个字符串中(它们之间有空格),然后将其解释为一系列命令。因此,就您而言,您有:

sh -c 'name="{.}"; echo {.} ${name%.*}.tpr'

这被解释为

sh -c 'name="{.}";
echo {.} ${name.*}.tpr

由于这是两个单独的命令,并且第一个命令在子 shell ( sh -c) 中执行,$name因此未在第二个命令中设置。

现在,您可以在字符串的开头添加任何内容,例如true

sh -c 'true; name="{.}"; echo {.} ${name%.*}.tpr'

这将被解释为:

sh -c 'true'
name="{.}"
echo {.} ${name%.*}.tpr'

在这种情况下,对 的调用sh本质上是一次性的; thenname在由 set 维护的环境中设置parallel,最后echonameset 调用。

因此,最简单的解决方案似乎就是删除不必要的调用sh

find 1st 2nd 3rd -name '*.xtc' -print0 |
parallel -0 'name={.}; echo {.} "${name%.*}.tpr"'

笔记:根据@StephaneChazelas 给出的提示,我删除了周围的引号{.}并将它们添加到了周围${name%.*}.ptr。 parallel 自己引用自己的替换,这会以一些奇怪的方式干扰显式引用。但是,它不会在 shell 替换中添加引号,如果替换可能被分词,则应添加引号。

如果您确实想出于某种原因使用子 shell(或特定的子 shell),另一种选择是使用以下选项-q

find 1st 2nd 3rd -name '*.xtc' -print0 |
parallel -0 -q sh -c 'name="{.}"; echo "{.}" "${name%.*}.tpr"'

笔记:如上所述,我调整了报价。在这种情况下,显式-q禁止对替换的引用,因此您必须显式地引用它们。然而,这是文本引用,不如 shell 引用准确;如果替换包含双引号字符,则该字符不会被转义,因此它将关闭显式引号,破坏命令行并有效引入命令注入漏洞(文件名包含$`\人物)。为此,除其他原因外,-q不鼓励该选择。

相关内容