xargs:使用管道的命令替换$(...)不起作用

16

我正试图编写一个简短的脚本,以下是命令:

echo "aaa111 bbb111" | xargs -I {} echo {} | sed 's/111/222/g'
返回结果为:

返回 aaa222 bbb222,这就是我期望的。

我期待下一个命令:

echo "aaa111 bbb111" | xargs -I {} echo $(echo {} | sed 's/111/222/g')

返回的应该是相同的,但它返回了aaa111 bbb111!为什么会这样?


更新:我想实现什么:

我有很多像pic30-coff-gccpic30-coff-ag之类的文件,并且我需要为每个文件创建一个符号链接,比如pic30-gcc -> pic30-coff-gcc等等。

所以我写了这个:

ls|grep 'coff-'|xargs -I {} ln -s {} $(echo {} | sed 's/coff-//g')

它没起作用:对于每个文件,它都报告该文件存在。我检查了命令,像这样:

ls|grep 'coff-'|xargs -I {} echo "ln -s {} $(echo {} | sed 's/coff-//g')"

没错,sed这部分没有起作用:

ln -s pic30-coff-gcc pic30-coff-gcc
ln -s pic30-coff-gcc-4.0.3 pic30-coff-gcc-4.0.3
...

但如果我只是键入

echo "ln -s pic30-coff-gcc $(echo pic30-coff-gcc | sed 's/coff-//g')"

它有效:

ln -s pic30-coff-gcc pic30-gcc

然后我用 aaa111 编写了测试命令,但它也无法正常工作。仍然不理解,为什么。

3个回答

32

for 循环的答案正是我来这里不想读的内容。使用 xargs 的整个目的就是避免这个循环。可能在这种特定情况下,xargs 并不是最聪明的工具,但问题就是问到它。

这是我最终采用的解决方案。它可能不完美,但仍然有效:

echo "aaa111 bbb111" | xargs -I {} sh -c "echo \$(echo {} | sed 's/111/222/g')"
# Outputs aaa222 bbb222

你可以提出相同命令的不同变体:

echo "aaa111 bbb111" | xargs -I {} sh -c 'echo $(echo {} | sed "s/111/222/g")'
echo "aaa111 bbb111" | xargs -I {} sh -c "echo \`echo {} | sed 's/111/222/g'\`"

这里的主要点是只需调用一个新的shell,该shell将在xargs替换replace-str(此处为{})为正确内容后执行命令替换。


1
更好的表述应该是 echo "aaa111 bbb111" | xargs -I @@ bash -c 'temp="@@"; echo ${temp//111/222}' - akhan
虽然正确,但这里的目标是使用与 OP 相同的命令。 - Jerska

15
$(echo {} | sed 's/111/222/g')在传递给xargs作为参数之前被求值。它将返回{}
因此:
echo "aaa111 bbb111" | xargs -I {} echo $(echo {} | sed 's/111/222/g')

等同于

echo "aaa111 bbb111" | xargs -I {} echo {}

-1

看起来你只需要一个简单的循环:

for file in *coff*; do
  ln -s "${file}" "${file/coff-/}"
done

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接