Quoting special characters with sed

后端 未结 2 1402
暖寄归人
暖寄归人 2021-01-16 07:12

I\'m trying to look in a variable passed to my program (the variable is $1) and to replace any special characters with quoted forms of said special character, in order to no

相关标签:
2条回答
  • 2021-01-16 07:37

    The problem with what you've done is that you haven't quoted your sed expressions. For example, write

    sed s/\*/\\*/
    

    either as

    sed 's/\*/\\*/'
    

    or

    sed s/\*/\\\\*/
    

    I'm not sure why do you need that elaborate function in order to escape special characters. You could define a function that would give back the escaped input string:

    myescape() { printf "%q" "$1"; }
    

    %q

    causes printf to output the corresponding argument in a format that can be reused as shell input.

    Another function for passing arguments to sed:

    myreplace() { sed "s/$1/$2/" <<< "$3"; }
    

    Now you could invoke it by saying:

    myreplace "$(myescape 'pattern')" "replacement" "original_string"
    

    Example:

    $ myescape() { printf "%q" "$1"; }
    $ myreplace() { sed "s/$1/$2/" <<< "$3"; }
    $ myreplace $(myescape 'a\^a*') 'test' 'aa\^a*aa[aaa]a'
    atestaa[aaa]a
    
    0 讨论(0)
  • 2021-01-16 07:46

    The purpose of the multiple invocations of sed is to place a literal backsplash before each occurrence of a set of characters. This can be done in one call to sed, but you need to be careful about how you specify the set.

    First, let's see what the general command will look like:

    newtarget=$( echo "$target" | sed -e 's/\([...]\)/\\\1/g'
    

    where ... will be replaced with the set of characters to escape. This commands uses parentheses to capture a single instance of one of those characters, the replaces it with a backsplash followed by the captured character. To specify the set of characters, use

    []*^+\.$[-]
    

    Two notes: first, the ] must come first so that it isn't mistaken for the end of the set, since [] is an invalid set. Second, - must come last, so that it isn't mistaken as the range operator (e.g., [a-z] is the set of lowercase letters, but [az-] is simply the three characters a, z, and -).

    Putting it all together:

     newtarget=$( echo "$target" | sed -e 's/\([]*^+\.$[-]\)/\\\1/g' )
    
    0 讨论(0)
提交回复
热议问题