【问题标题】:Replacing special characters in a shell script using sed使用 sed 替换 shell 脚本中的特殊字符
【发布时间】:2013-12-23 17:08:00
【问题描述】:

我正在尝试编写一个 shell 脚本来替换我使用 sed 选择的任何字符/字符串。我的第一次尝试除了特殊字符外。我一直在尝试使用 sed 来修复特殊字符,以便它们也将被搜索或替换。我决定为了测试目的而简化脚本,只处理一个冒犯的角色。但是,我仍然遇到问题。

编辑脚本

#! /bin/sh
oldString=$1
newString=$2
file=$3

oldStringFixed=$(echo "$oldString" | sed 's/\\/\\\\/g')
oldStringFixed=$(echo "$oldStringFixed" | sed 's/\[/\\\[/g')
oldStringFixed=$(echo "$oldStringFixed" | sed 's/\]/\\\]/g')
oldStringFixed=$(echo "$oldStringFixed" | sed 's/\^/\\\^/g')
oldStringFixed=$(echo "$oldStringFixed" | sed 's/\*/\\\*/g')
oldStringFixed=$(echo "$oldStringFixed" | sed 's/\+/\\\+/g')
oldStringFixed=$(echo "$oldStringFixed" | sed 's/\./\\\./g')
oldStringFixed=$(echo "$oldStringFixed" | sed 's/\$/\\\$/g')
oldStringFixed=$(echo "$oldStringFixed" | sed 's/\-/\\\-/g')

sed -e "s/$oldStringFixed/$newString/g" "$file" > newfile.updated
mv newfile.updated "$file"#! /bin/sh

如果不清楚,我正在尝试在 oldString 中搜索 [ 字符,并将其替换为转义版本并将结果分配给 oldStringFixed(我需要反引号吗?)。下面两行是我认为可以正常工作的原始脚本的略微修改版本。

当我回显固定字符串时,没有任何显示,sed 输出错误

sed: can't read [: No such file or directory

谁能解释我的第一条 sed 行有什么问题?

编辑:

感谢 Jite,脚本运行得更好。但是,我仍然有用空格替换单引号字符的问题,即'*'。上面是新版本。

【问题讨论】:

  • specias char 比“[”之类的要多得多。 \ * + ?对于 OldString 和 \ & / 对于 newString
  • 非常类似于this问题。

标签: shell sed sh


【解决方案1】:

我建议两个改进:

  1. 不要像你一样将调用堆栈到sed,而是将它们全部打包到一个函数中,如下面的escape_string

  2. 您可以为 sed 替换命令使用花哨的分隔符,以避免与 / 相关的问题成为所涉及的字符串的一部分。

通过这些更改,您的脚本如下所示:

#! /bin/sh
oldString="$1"
newString="$2"
file="$3"

escape_string()
{
   printf '%s' "$1" | sed -e 's/[][\\^*+.$-]/\\\1/g'
}

fancyDelim=$(printf '\001')

oldStringFixed=$(escape_string "$oldString")
sed -e "s$fancyDelim$oldStringFixed$fancyDelim$newString${fancyDelim}g" "$file" \
  > newfile.updated
mv newfile.updated "$file"

【讨论】:

  • 你可以很容易地概括为s/[][\\^*+.$-]/\\\1/g(我不知道你为什么要包含连字符,所以我建议你把它去掉)。
  • 太好了,我添加了您的更改!
  • 这对我不起作用,我得到“sed: -e expression #1, char 21: invalid reference \1 on `s' command's RHS”
  • @BenFarmer 当字符串中没有特殊字符时,这不起作用。如果您有一个不包含特殊字符的常规字符串,则 \1 将没有值(匹配 1),因此这将失败。如果值可能不包含匹配项,则不能使用枚举匹配项。
【解决方案2】:

变化:

oldStringFixed= `sed 's/\[/\[/g' "$oldString"\`

到:

oldStringFixed=$(echo "$oldString" | sed 's/\[/\\\[/g')

问题一:=后面有空格,分配shell变量时不允许使用。

问题 2:sed 需要一个文件作为输入,而不是字符串。不过,您可以像我的解决方案一样通过管道传输它。

问题3:你需要先转义反斜杠\\,然后你需要转义你的字符\[,总计\\\[:)

旁注:我将 `` 更改为 $()​​,因为后者是推荐的实践(由于嵌套,另一个主题)。

【讨论】:

  • 感谢您的帮助。您的更改效果很好,我添加了额外的 sed 语句来处理其他问题字符。但是,当我尝试用“*”之类的空格替换单引号字符时,输出不正确。无论如何,这可以解决吗?
  • 都可以修复。坦率地说,对于这种情况,我会编写一个文件sed.script,其中包含要执行的所有命令,每行一个,然后只使用一次sed -f sed.script,而不是多次重新调用sed。这也意味着您不必将脚本转义到 shell — 它让生活更轻松。
  • @user3074091 我不明白你的问题。请用示例输入和您期望的输出更新您的问题,希望我们能给出答案。
【解决方案3】:

替换包含特殊字符的值,请尝试将 sed 与 "|" 一起使用,而不是 "/"

例如:sed -i 's|'$original_value'|'$new_value'|g'

哪里 original_value="comprising_special_char_/" new_value="comprising_new_special_char:"

【讨论】:

    【解决方案4】:

    对我来说,试图让 sed 为一般情况执行此操作只是一场噩梦。我放弃了,写了一个简短的 Python 代码来代替 sed:

    #!/usr/bin/python
    # replace.py
    import sys
    
    # Replace string in a file (in place)
    match=sys.argv[1]
    replace=sys.argv[2]
    filename=sys.argv[3]
    
    print "Replacing strings in",filename
    
    with open(filename,"r") as f:
      data = f.read().replace(match,replace)
    
    with open(filename,"w") as f:
      f.write(data)
    

    然后可以像这样使用:

    #!/bin/bash
    orig='<somethinghorrible>'
    out='<replacement>'
    python replace.py "$orig" "$out" myfile.txt
    

    【讨论】:

      【解决方案5】:

      你可以用它来替换 " 为 \" sed 's/\"/\\\"/g' filename

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-05-14
        • 2021-03-06
        • 2019-09-07
        • 2021-06-11
        • 1970-01-01
        • 2013-11-18
        • 2023-03-22
        • 1970-01-01
        相关资源
        最近更新 更多