【问题标题】:xargs: command substitution $(...) with pipe doesn't workxargs:用管道替换命令 $(...) 不起作用
【发布时间】:2021-12-31 04:29:12
【问题描述】:

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

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编写了测试命令,它也不起作用。还是不明白,为什么。

【问题讨论】:

    标签: bash pipe command-substitution


    【解决方案1】:

    $(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】:

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

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

      【讨论】:

        【解决方案3】:

        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(这里是{})之后执行命令替换。

        【讨论】:

        • 更好的表述是echo "aaa111 bbb111" | xargs -I @@ bash -c 'temp="@@"; echo ${temp//111/222}'
        • 虽然正确,但这里的目标是使用与 OP 相同的命令。
        【解决方案4】:

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

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

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

        【讨论】:

          猜你喜欢
          • 2014-09-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多