BASH在单引号内转义双引号

时间:2015-12-09 14:37:45

标签: regex bash shell sed

我试图编写一个bash函数来逃避单引号内的所有双引号,例如:

'I need to escape "these" quotes with backslashes'

会变成

'I need to escape \"these\" quotes with backslashes'

我的看法是:

  1. 在输入中查找单引号对,并使用grep
  2. 提取它们
  3. 管道进入sed,转义双引号
  4. 再次输入整个输入并用sedded match替换grep匹配
  5. 我设法让它工作到正确转义引号部分,但在整个输入中替换它失败。

    脚本代码copypaste:

    # $1 - Full name, $2 - minified name
    adjust_quotes ()
    {
        SINGLE_QUOTES=`grep -Eo "'.*'" $2`
        ESCAPED_QUOTES=`echo $SINGLE_QUOTES | sed 's|"|\\\\"|g'`
        sed -r "s|'.*'|$ESCAPED_QUOTES|g" "$2" > "$2.escaped"
        mv "$2.escaped" $2
        echo "Quotes escaped within single quotes on $2"
    }
    

    随机附加问题:

    • 在控制台中,只使用两个反斜杠转义引号,但是当代码放入脚本时 - 我需要四个。我很想知道
    • 我可以将此代码修改为一个循环来一个接一个地转发所有单引号对,直到EOF吗?

    谢谢!

    P.S。我知道这可能比较容易。 python,但我真的需要把它保存在bash中。

2 个答案:

答案 0 :(得分:0)

使用BASH字符串替换:

s='I need to escape "these" quotes with backslashes'
r="${s//\"/\\\"}"
echo "$r"
I need to escape \"these\" quotes with backslashes

答案 1 :(得分:0)

这是一个纯粹的bash解决方案,它在stdin上进行转换,打印到stdout。它将整个输入读入内存,因此无法使用真正庞大的文件。

escape_enclosed_quotes() (
  IFS=\'
  read -d '' -r -a fields
  for ((i=1; i<${#fields[@]}; i+=2)); do
    fields[i]=${fields[i]//\"/\\\"}
  done
  printf %s "${fields[*]}"
)

我故意将函数的主体括在括号中而不是括号中,以强制主体在子shell中运行。这限制了IFS对身体的修改,以及隐含地使变量在本地使用。

该函数使用read内置函数将整个输入(因为行分隔符设置为NUL -d '')读入数组(-a),使用单引号作为字段分隔符(IFS=\')。结果是用单引号包围的输入部分位于数组的奇数位置,因此函数在奇数索引上循环以仅对那些字段进行替换。我使用bash的find-and-replace语法,而不是推迟到sed之类的外部实用程序。

这是bash,有几个陷阱:

  1. 如果文件包含NUL,则将忽略文件的其余部分。
  2. 如果文件的最后一行没有以换行符结尾,并且该行的最后一个字符是单引号,则不会输出。
  3. 在便携式文本文件中,上述两种情况都是不可能的,所以可能没问题。同样值得注意。

    补充问题:为什么

    需要额外的反斜杠
    ESCAPED_QUOTES=`echo $SINGLE_QUOTES | sed 's|"|\\\\"|g'`
    

    答案:它与脚本中的那一行无关。它与你使用反引号(...)进行命令替换以及反引号内的反斜杠的特殊和常常不可预测的处理有关。 不推荐使用此语法。 Do not use it. (即使您在互联网上的某个随机示例中看到其他人使用它。)如果您使用推荐的$(...)语法进行命令替换,则会按预期工作:

    ESCAPED_QUOTES=$(echo $SINGLE_QUOTES | sed 's|"|\\"|g')
    

    (更多信息在上面链接的Bash FAQ中。)