【问题标题】:sed in backtick expansion, with xargs, not substituting the input stringsed 在反引号扩展中,使用 xargs,不替换输入字符串
【发布时间】:2017-03-29 09:55:25
【问题描述】:
echo "who are you" | xargs -i@ echo `echo @ | sed "s/who/where/"`

预期输出

where are you

实际输出

who are you

注意 - 这不是实际用例,而是一个示例测试用例。

【问题讨论】:

  • 你真正想要完成什么,你为什么在这里使用xargs?显而易见、直接且正确的方法就是 echo "who are you" | sed "s/who/where/"
  • ... 一个非常迂回但名义上正确的尝试可能是echo "who are you" | xargs -i@ sh -c 'echo @ | sed "s/who/where/"'
  • 我没有尝试完成任何事情,我正在学习脚本,只是想知道这个班轮有什么问题。 大家好,请忽略波浪号之前的反斜杠。
  • 我认为你错过了这样一个事实,即反引号中的任何内容(或者bash $(...) 语法)在管道的其余部分之前运行。结果,您实际上正在运行echo "who are you" | xargs -i@ echo @,正如您所注意到的,这有点毫无意义......

标签: shell sed xargs backticks


【解决方案1】:

扩展顺序要稍微修改一下:

echo "who are you" | echo "`sed "s/who/where/"`" | xargs -I@ echo "@"

在您的示例中,命令替换发生在 shell 启动命令之前:

echo "who are you" | xargs -i@ echo `echo @ | sed "s/who/where/"`

命令替换这样做:

echo @ | sed "s/who/where/"

结果是"@",因为 sed 只是打印出输入。 下一步是:

echo "who are you" | xargs -i@ echo @

xargs 将@ 替换为标准输入“你是谁”,然后构建并运行以下命令:

echo "who are you"

所以最后你得到了输出:

who are you

【讨论】:

    【解决方案2】:

    我假设实际用例确实需要xargssample 命令最简单的重新表述就是echo 'who are you' | sed 's/who/where/'

    要获得预期的行为,xargs 必须使用包含 shell 命令的字符串显式调用 shell 二进制文件 sh

    $ echo "who are you" | xargs -I@ sh -c 'echo "$1" | sed "s/who/where/"' - @
    where are you
    
    • 正如twalberg 指出的那样,在您的尝试中,`...` 内部的命令会在 之前 xargs 运行时进行评估,结果是 literal @(由于将 literal @ 传递给 echo,它只输出 @,因为 sed 命令找不到要替换的内容),然后 xargs 简单地替换为它的输入原样;正如 twalberg 所说:您正在有效地运行
      echo 'who are you' | xargs -i@ echo @,这是一个虚拟无操作,除了可能修剪前导和尾随空格。

    • 通常,xargs 只能调用外部实用程序,如果您需要一个需要 shell 功能的命令 - 例如管道 - 您必须使用 单个字符串,其中包含 shell 命令 - 即临时脚本 - 在由 xargs 调用时由该 shell 实例评估。

    • sh -c 使用指定的脚本(一个包含shell 命令的字符串)调用/bin/sh 进行评估,并且将xargs' 参数作为位置传递是最安全的该脚本的参数;注意,脚本后面的first参数绑定到脚本中的$0,因此使用了虚拟值_,后跟@xargs的替换字符串,其扩展value 将绑定到脚本内的$1

    • 'echo "$1" | sed "s/who/where/"' 因此充当临时 shell 脚本,将其第一个位置参数(xargs 传递的参数)通过管道传送到 sed,以产生所需的输出。

    【讨论】:

    • 为什么使用$1...?因为当我执行echo "who are you" | xargs -I@ sh -c 'echo "$0" | sed "s/who/where/"' @ 时,我实际上得到了相同的输出......
    • @maxxyme,因为$0 的目的是反映正在运行的命令的名称,而不是接收参数。是的,您可以像以前那样重新调整它的用途,但这不是一个好主意,特别是如果您想处理 多个 参数。
    • 好吧,我已经读过几次了,但找不到任何相关的例子说明这个$0 是真正有用的......这就是原因。
    • @maxxyme, $0 主要用于脚本发现自己的名称/位置(此处不适用)。所有参数处理功能,例如反映参数计数的$#,都基于存储在$1 中的第一个参数;同样,$*"$@" 仅包含 $1$2、...您可能会争辩说,sh -c 首先不应该暴露设置$0 的能力:很容易忘记这一点ad hoc 脚本后的第一个参数绑定到 $0 - 需要一个虚拟参数,例如 - - 相反,在这种情况下没有充分的理由设置 $0
    猜你喜欢
    • 1970-01-01
    • 2020-03-27
    • 1970-01-01
    • 1970-01-01
    • 2021-08-13
    • 2017-02-21
    • 1970-01-01
    • 2019-11-11
    • 1970-01-01
    相关资源
    最近更新 更多