代码之家  ›  专栏  ›  技术社区  ›  Tom

SED使用包含“$”的$var换行[重复]

  •  0
  • Tom  · 技术社区  · 6 年前

    在bash脚本中,我有一个外部(从用户接收)字符串,应该在sed模式中使用它。

    REPLACE="<funny characters here>"
    sed "s/KEYWORD/$REPLACE/g"
    

    我怎么能逃脱 $REPLACE 字符串,以便安全地接受 sed

    注: KEYWORD 是没有匹配项等的哑子字符串。它不是由用户提供的。

    0 回复  |  直到 7 年前
        1
  •  252
  •   Pianosaurus    7 年前

    警告 :确实如此 想想新线。有关更深入的答案,请参见 this SO-question 相反。(谢谢,Ed Morton&Niklas Peter)

    注意逃避一切是个坏主意。Sed需要许多字符转义到 得到 它们的特殊意义。例如,如果在替换字符串中转义一个数字,它将转为反向引用。

    正如Ben Blank所说,替换字符串中只需要转义三个字符(转义本身,正斜杠表示语句结束,而&表示全部替换):

    sed -e 's/[\/&]/\\&/g'

    如果你需要逃离 KEYWORD

    sed -e 's/[]\/$*.^[]/\\&/g'

    记住,如果你使用的不是 / 作为分隔符,您需要将上面表达式中的斜杠替换为正在使用的字符。有关解释,请参阅彼得克拉夫的评论。

    编辑: 由于之前没有考虑到一些拐角情况,上面的命令已经更改了好几次。有关详细信息,请检查编辑历史记录。

        2
  •  84
  •   a_horse_with_no_name    9 年前

    / 作为分隔符:

    sed 's#"http://www\.fubar\.com"#URL_FUBAR#g'
    

        3
  •  46
  •   Mark Stosberg    9 年前

    replace子句中专门处理的三个文字字符是 / (结束条款), \ (用于转义字符、反向引用和c.),以及 & (将匹配项包含在替换项中)。因此,您只需转义这三个字符:

    sed "s/KEYWORD/$(echo $REPLACE | sed -e 's/\\/\\\\/g; s/\//\\\//g; s/&/\\\&/g')/g"
    

    $ export REPLACE="'\"|\\/><&!"
    $ echo fooKEYWORDbar | sed "s/KEYWORD/$(echo $REPLACE | sed -e 's/\\/\\\\/g; s/\//\\\//g; s/&/\\\&/g')/g"
    foo'"|\/><&!bar
    
        4
  •  33
  •   Gurpartap Singh    13 年前

    基于Pianosaurus的正则表达式,我制作了一个bash函数,它可以同时跳过关键字和替换。

    function sedeasy {
      sed -i "s/$(echo $1 | sed -e 's/\([[\/.*]\|\]\)/\\&/g')/$(echo $2 | sed -e 's/[\/&]/\\&/g')/g" $3
    }
    

    以下是使用方法:

    sedeasy "include /etc/nginx/conf.d/*" "include /apps/*/conf/nginx.conf" /etc/nginx/nginx.conf
    
        5
  •  16
  •   fedorqui    10 年前

    现在有点晚了。。。但有一种更简单的方法可以做到这一点。只需更改分隔符(即分隔字段的字符)。所以,代替 s/foo/bar/ 你写的 s|bar|foo

    下面是简单的方法:

    sed 's|/\*!50017 DEFINER=`snafu`@`localhost`\*/||g'
    

    结果的输出没有那个讨厌的DEFINER子句。

        6
  •  10
  •   Dennis Estenson    9 年前

    结果你问错了问题。我也问错了问题。它错的原因是第一句话的开头:“在我的 猛击 脚本。

    我有同样的问题,也犯了同样的错误。如果您使用bash,则不需要使用sed进行字符串替换(而且 使用bash内置的replace特性的cleaner)。

    而不是像这样,例如:

    function escape-all-funny-characters() { UNKNOWN_CODE_THAT_ANSWERS_THE_QUESTION_YOU_ASKED; }
    INPUT='some long string with KEYWORD that need replacing KEYWORD.'
    A="$(escape-all-funny-characters 'KEYWORD')"
    B="$(escape-all-funny-characters '<funny characters here>')"
    OUTPUT="$(sed "s/$A/$B/g" <<<"$INPUT")"
    

    INPUT='some long string with KEYWORD that need replacing KEYWORD.'
    A='KEYWORD'
    B='<funny characters here>'
    OUTPUT="${INPUT//"$A"/"$B"}"
    
        7
  •  1
  •   fedorqui    10 年前

    使用awk-它更干净:

    $ awk -v R='//addr:\\file' '{ sub("THIS", R, $0); print $0 }' <<< "http://file:\_THIS_/path/to/a/file\\is\\\a\\ nightmare"
    http://file:\_//addr:\file_/path/to/a/file\\is\\\a\\ nightmare
    
        8
  •  0
  •   Alex    16 年前

    ls | awk '{ print "awk " "'"'"'"  " {print $1,$2,$3} " "'"'"'"  " " $1 ".old_ext > " $1 ".new_ext"  }' > for_the_birds
    

    这看起来太过分了,但不知怎么的,引号的组合可以保持'印刷为文字'。如果我没记错的话,这些变量就被这样的引号包围着:“$1”。试试看,让我知道它是怎么和SED一起工作的。

        9
  •  0
  •   Axel    7 年前

    我对sedeasy函数进行了改进,它将与tab这样的特殊字符分离。

    function sedeasy_improved {
        sed -i "s/$(
            echo "$1" | sed -e 's/\([[\/.*]\|\]\)/\\&/g' 
                | sed -e 's:\t:\\t:g'
        )/$(
            echo "$2" | sed -e 's/[\/&]/\\&/g' 
                | sed -e 's:\t:\\t:g'
        )/g" "$3"
    }
    

    $1 $2 用引号括起来以避免shell扩展并保留制表符或双空格。

    附加管道 | sed -e 's:\t:\\t:g' (我喜欢 : (作为标记)在 \t .

        10
  •  -1
  •   NeronLeVelu    11 年前

    so(单位:ksh)

    Var=">New version of \"content' here <"
    printf "%s" "${Var}" | sed "s/[&\/\\\\*\\"']/\\&/g' | read -r EscVar
    
    echo "Here is your \"text\" to change" | sed "s/text/${EscVar}/g"
    
        11
  •  -1
  •   The Hungry Dictator    8 年前

    如果您只是想在sed命令中替换变量值,那么只需删除 例子:

    sed -i 's/dev-/dev-$ENV/g' test to sed -i s/dev-/dev-$ENV/g test
    
        12
  •  -2
  •   Mark Stosberg    9 年前

    如果您碰巧生成了一个随机密码以传递给 sed 替换模式,然后选择小心随机字符串中的哪一组字符。如果您选择通过将值编码为base64而生成的密码,则只有base64中既有可能也有特殊字符 塞德

    # password 32 characters log, minus any copies of the "/" character.
    pass=`openssl rand -base64 32 | sed -e 's/\///g'`;
    
        13
  •  -5
  •   Javonne Martin    7 年前

    一个更简单的方法是在手动之前构建字符串并将其用作 sed

    rpstring="s/KEYWORD/$REPLACE/g"
    sed -i $rpstring  test.txt
    
    推荐文章