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

时间:2014-03-23 10:10:40

标签: bash pipe command-substitution

我正在尝试编写短脚本,以及以下命令:

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!那是为什么?


UPD:我正在努力实现的目标:

我有很多文件,例如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编写了测试命令,它也不起作用。仍然无法理解,为什么。

4 个答案:

答案 0 :(得分:18)

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,它会在xargs用正确的内容替换replace-str(此处为{})之后执行命令替换。

答案 1 :(得分:7)

$(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 {}

答案 2 :(得分:2)

似乎所有你需要的只是一个简单的循环:

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

答案 3 :(得分:-1)

这是另一种变体,它更改每个输入行以打印源和目标,然后强制 xargs 一次读取两个参数。

# aside: avoid ls | grep
printf '%s\n' coff-* |
sed 's/\(coff-\(.*\)\)/\1 \2/' |
xargs -n 2 ln -s

这显然是脆弱的;如果您的文件名包含空格,它们将被错误地解析。