How to escape single quotes within single quoted strings

前端 未结 23 2150
说谎
说谎 2020-11-21 06:20

Let\'s say, you have a Bash alias like:

alias rxvt=\'urxvt\'

which works fine.

However:



        
相关标签:
23条回答
  • 2020-11-21 06:42

    Here are my two cents -- in the case if one wants to be sh-portable, not just bash-specific ( the solution is not too efficient, though, as it starts an external program -- sed ):

    • put this in quote.sh ( or just quote ) somewhere on your PATH :
    # this works with standard input (stdin)
    quote() {
      echo -n "'" ;
      sed 's/\(['"'"']['"'"']*\)/'"'"'"\1"'"'"'/g' ;
      echo -n "'"
    }
    
    case "$1" in
     -) quote ;;
     *) echo "usage: cat ... | quote - # single-quotes input for Bourne shell" 2>&1 ;;
    esac
    
    

    An example:

    $ echo -n "G'day, mate!" | ./quote.sh -
    'G'"'"'day, mate!'
    

    And, of course, that converts back:

    $ echo 'G'"'"'day, mate!'
    G'day, mate!
    

    Explanation: basically we have to enclose the input with quotes ', and then also replace any single quote within with this micro-monster: '"'"' ( end the opening quote with a pairing ', escape the found single quote by wrapping it with double quotes -- "'", and then finally issue a new opening single quote ', or in pseudo-notation : ' + "'" + ' == '"'"' )

    One standard way to do that would be to use sed with the following substitution command:

    s/\(['][']*\)/'"\1"'/g 
    

    One small problem, though, is that in order to use that in shell one needs to escape all these single quote characters in the sed expression itself -- what leads to something like

    sed 's/\(['"'"']['"'"']*\)/'"'"'"\1"'"'"'/g' 
    

    ( and one good way to build this result is to feed the original expression s/\(['][']*\)/'"\1"'/g to Kyle Rose' or George V. Reilly's scripts ).

    Finally, it kind of makes sense to expect the input to come from stdin -- since passing it through command-line arguments could be already too much trouble.

    ( Oh, and may be we want to add a small help message so that the script does not hang when someone just runs it as ./quote.sh --help wondering what it does. )

    0 讨论(0)
  • 2020-11-21 06:43

    Here is an elaboration on The One True Answer referenced above:

    Sometimes I will be downloading using rsync over ssh and have to escape a filename with a ' in it TWICE! (OMG!) Once for bash and once for ssh. The same principle of alternating quotation delimiters is at work here.

    For example, let's say we want to get: Louis Theroux's LA Stories ...

    1. First you enclose Louis Theroux in single quotes for bash and double quotes for ssh: '"Louis Theroux"'
    2. Then you use single quotes to escape a double quote '"'
    3. The use double quotes to escape the apostrophe "'"
    4. Then repeat #2, using single quotes to escape a double quote '"'
    5. Then enclose LA Stories in single quotes for bash and double quotes for ssh: '"LA Stories"'

    And behold! You wind up with this:

    rsync -ave ssh '"Louis Theroux"''"'"'"'"''"s LA Stories"'
    

    which is an awful lot of work for one little ' -- but there you go

    0 讨论(0)
  • 2020-11-21 06:44

    I don't see the entry on his blog (link pls?) but according to the gnu reference manual:

    Enclosing characters in single quotes (‘'’) preserves the literal value of each character within the quotes. A single quote may not occur between single quotes, even when preceded by a backslash.

    so bash won't understand:

    alias x='y \'z '

    however, you can do this if you surround with double quotes:

    alias x="echo \'y "
    > x
    > 'y
    
    0 讨论(0)
  • 2020-11-21 06:44

    Here is another solution. This function will take a single argument and appropriately quote it using the single-quote character, just as the voted answer above explains:

    single_quote() {
      local quoted="'"
      local i=0
      while [ $i -lt ${#1} ]; do
        local ch="${1:i:1}"
        if [[ "$ch" != "'" ]]; then
          quoted="$quoted$ch"
        else
          local single_quotes="'"
          local j=1
          while [ $j -lt ${#1} ] && [[ "${1:i+j:1}" == "'" ]]; do
            single_quotes="$single_quotes'"
            ((j++))
          done
          quoted="$quoted'\"$single_quotes\"'"
          ((i+=j-1))
        fi
        ((i++))
      done
      echo "$quoted'"
    }
    

    So, you can use it this way:

    single_quote "1 2 '3'"
    '1 2 '"'"'3'"'"''
    
    x="this text is quoted: 'hello'"
    eval "echo $(single_quote "$x")"
    this text is quoted: 'hello'
    
    0 讨论(0)
  • 2020-11-21 06:45

    If you're generating the shell string within Python 2 or Python 3, the following may help to quote the arguments:

    #!/usr/bin/env python
    
    from __future__ import print_function
    
    try:  # py3
        from shlex import quote as shlex_quote
    except ImportError:  # py2
        from pipes import quote as shlex_quote
    
    s = """foo ain't "bad" so there!"""
    
    print(s)
    print(" ".join([shlex_quote(t) for t in s.split()]))
    

    This will output:

    foo ain't "bad" so there!
    foo 'ain'"'"'t' '"bad"' so 'there!'
    
    0 讨论(0)
  • 2020-11-21 06:50

    I just use shell codes.. e.g. \x27 or \\x22 as applicable. No hassle, ever really.

    0 讨论(0)
提交回复
热议问题