【问题标题】:Sed and escaping single quoteSed 和转义单引号
【发布时间】:2012-12-26 16:23:25
【问题描述】:

我在使用 sed 和单引号时遇到问题

我有一个这样的字符串:

-cmd af -i 3 -a

我想把这个字符串改成

-cmd 'af -i 3 -a'

现在我正在使用这个:

字符串存储在buff变量中

buff=$(echo $buff | sed -r "s/cmd /CMD '/g")"'"

它回响了-cmd 'af -i 3 -a'

然后我调用一个以 buff 作为参数的函数,在使用 ksh -x 执行脚本时,我可以看到调用不正常

+ buff=$'-CMD \'af -i 3 -a \''
+ echo -CMD $'\'af' -i 3 -a $'\''
-CMD 'af -i 3 -a' #this is the echo
+ functionTest -CMD $'\'af' -i 3 -a $'\''

结果它总会给我

-CMD $'\'af' -i 3 -a $'\''

所以基本上看来我的单引号被解释为$'\''

我不知道为什么,我尝试了很多东西,例如转义字符,但它给了我完全相同的结果,即使使用 \x27

【问题讨论】:

  • 如果您尝试将带有参数的命令存储在字符串中,那么您做错了;你应该改用数组。
  • 不,只是想在那里格式化一个字符串
  • 您的命令在这里运行良好:buff="-cmd af -i 3 -a"; buff=$(echo $buff | sed -r "s/cmd /CMD '/g")"'"; echo "$buff" 输出 -CMD 'af -i 3 -a'
  • 但是我尝试用这个字符串作为参数调用一个函数,当我 ksh -x 调用时,我可以看到它的格式与我放置的方式相同 -CMD $'\'af' - i 3 -a $'\''
  • 您应该在问题中告诉我们一切。我们不是通灵者。

标签: shell sed ksh


【解决方案1】:

您如何看待奇数球的结果?

您所拥有的原始内容还可以(Mac OS X 上的sed 不支持-r,但使用的正则表达式不需要非标准的GNU 扩展选项-r):

$ buff1="-cmd af -i 3 -a"
$ buff2=$(echo $buff1 | sed -e "s/cmd /CMD '/g")"'"
$ echo $buff2
-CMD 'af -i 3 -a'
$

我怀疑您的问题不在于转换,而在于您查看结果的方式。


ksh 测试

Osiris JL: cat so14043243.sh
buff1="-cmd af -i 3 -a"
buff2=$(echo $buff1 | sed -e "s/cmd /CMD '/g")"'"
echo $buff2
echo "$buff2"
Osiris JL: ksh -x so14043243.sh
+ buff1='-cmd af -i 3 -a'
+ sed -e $'s/cmd /CMD \'/g'
+ echo -cmd af -i 3 -a
+ buff2=$'-CMD \'af -i 3 -a\''
+ echo -CMD $'\'af' -i 3 $'-a\''
-CMD 'af -i 3 -a'
+ echo $'-CMD \'af -i 3 -a\''
-CMD 'af -i 3 -a'
Osiris JL: 

输出正确;跟踪有点混乱,但与您显示的相同。

-x 输出付出的额外努力是有充分理由的;它消除了输出的歧义,以便您可以准确地确定什么是什么,如果您可以很好地阅读它。此外,您可以在+ 之后复制'n'粘贴该行并运行它并再次获得完全相同的结果。旧的 Bourne shell 有一个 -x 选项,它没有像这样进行字符映射,这可能会导致混淆,而且您当然不能可靠地复制'n'粘贴跟踪输出以再次执行该命令。

关键是结果——回响的东西——是你想要和期望的,所以你无所顾忌(当它发生时)。但我同意,一开始可能会让人感到困惑。

【讨论】:

  • 好的,这只是一个显示理解问题:) 我会在调用的函数中进一步研究,这就是问题所在 非常感谢您的帮助!
【解决方案2】:

它对我也很好。但是不需要sed; bash 内置函数可以很好地做到这一点:

$ buff='-cmd af -i 3 -a'
$ buff=${buff/cmd /CMD \'}\'
$ echo $buff
-CMD 'af -i 3 -a'

【讨论】:

    【解决方案3】:

    我认为@gniourf_gniourf 关于在变量中存储字符串的初始评论基本上是正确的(即使您只是尝试存储命令参数);见BashFAQ #050: I'm trying to put a command in a variable, but the complex cases always fail!

    现在,您有两个困惑。首先是您误解了-x 模式正在打印什么。它不会打印您正在运行的命令的参数,它会打印一个命令将传递相同的参数。在这种情况下,一些参数包含单引号,因此它提供了一个带引号和转义的字符串,在删除引号后,将导致实际传递的参数相同。比如参数之一是'af,所以-x模式显示为$'\'af'

    其次,您似乎正在尝试在变量中嵌入单引号,以便您可以将多个单词作为单个参数传递给 functionTest(即您正在尝试运行 functionTest -CMD 'af -i 3 -a'). If I'm right about what you're trying to do, you're doing it fundamentally wrong. When the shell parses a command line, it interprets quotes and escapes, *then* substitutes variables. It'll go back and split the replaced variables into words, but it will not go back and pay attention to quotes and escapes in the substituted text. So when it replaces$buff 的等效项with-CMD 'af -i 3 -a'`,它将其拆分为 5 个参数:“-CMD”、“'af”、“-i”、“3”和“-a'”。请注意单引号被视为第二个和第五个参数的一部分,而不是包含一个长参数:

    $ buff="-CMD 'af -i 3 -a'"
    $ printargs $buff
    Got 5 arguments:
      «-CMD»
      «'af»
      «-i»
      «3»
      «-a'»
    

    为了在没有这种混淆的情况下存储多个参数,您需要使用一个数组(再次请参阅@gniourf_gniourf 的评论和BashFAQ #050):

    $ buff=(-CMD 'af -i 3 -a')
    $ printargs "${buff[@]}"
    Got 2 arguments:
      «-CMD»
      «af -i 3 -a»
    

    顺便说一句,如果你想复制这个,你需要 printargs。这是我写的一个非常简单的 shell 脚本来澄清这样的情况:

    #!/bin/sh
    
    echo "Got $# arguments:"
    for arg; do
            echo "  «${arg}»"
    done
    

    【讨论】:

      猜你喜欢
      • 2015-11-06
      • 2019-04-01
      • 1970-01-01
      • 2017-08-05
      • 2011-11-22
      • 2013-02-24
      • 2020-01-31
      • 1970-01-01
      • 2017-09-13
      相关资源
      最近更新 更多