web-dev-qa-db-ja.com

シェルで引用符をエスケープする方法は?

Bashで文字をエスケープすることに問題があります。別のユーザーでコマンドを実行しているときに、一重引用符と二重引用符をエスケープしたいのですが。この質問のために、画面に以下をエコーし​​たいとします。

'single quote phrase' "double quote phrase"

別のユーザーに切り替える必要がある場合、すべての特殊文字をエスケープするにはどうすればよいですか。

Sudo su USER -c "echo \"'single quote phrase' \"double quote phrase\"\""

もちろん、これは正しい結果を生み出しません。

82
m33lky

次の文字列リテラル構文を使用できます。

> echo $'\'single quote phrase\' "double quote phrase"'
'single quote phrase' "double quote phrase"

man bashから

$ 'string'形式の単語は特別に扱われます。 Wordは文字列に展開され、バックスラッシュでエスケープされた文字はANSI C標準で指定されたとおりに置き換えられます。バックスラッシュエスケープシーケンスが存在する場合は、次のようにデコードされます。

          \a     alert (bell)
          \b     backspace
          \e
          \E     an escape character
          \f     form feed
          \n     new line
          \r     carriage return
          \t     horizontal tab
          \v     vertical tab
          \\     backslash
          \'     single quote
          \"     double quote
          \nnn   the eight-bit character whose value is the octal value nnn (one to three digits)
          \xHH   the eight-bit character whose value is the hexadecimal value HH (one or two hex digits)
          \cx    a control-x character
110
SiegeX

シェルで引用符をエスケープする簡単な例:

$ echo 'abc'\''abc'
abc'abc
$ echo "abc"\""abc"
abc"abc

既に開いているものを終了することで行われます(')、エスケープされたもの(\')、次に別のものを開きます(')。

または:

$ echo 'abc'"'"'abc'
abc'abc
$ echo "abc"'"'"abc"
abc"abc

既に開いているものを終了することで行われます(')、別の引用符("'")、次に別のものを開きます(')。

関連: 単一引用符で囲まれた文字列内の単一引用符をエスケープする方法? stackoverflow SEで

17
kenorb

POSIXシェルでは、文字列に変数、コマンド、履歴の展開がなく、改行がないと仮定して、次の基本的な処方に従います。

  1. 一般的な文字列を一重引用符で囲むには、次の操作を実行します。

    1. 一重引用符以外の文字のシーケンスを、先頭と末尾に単一引用符を追加した同じシーケンスに置き換えます:'aaa' ==> ''aaa''

    2. 既存単一引用符ごとにバックスラッシュでエスケープする:' ==> \'
      特に、 ''aaa'' ==> \''aaa'\'

  2. 一般的な文字列を二重引用符で囲むには、次の操作を実行します。

    1. 先頭と末尾に二重引用符を追加します:aaa ==> "aaa"

    2. すべての二重引用符とすべてのバックスラッシュ文字をバックスラッシュでエスケープします:" ==> \", \ ==> \\

いくつかの例:

''aaa""bbb''ccc\\ddd''  ==>  \'\''aaa""bbb'\'\''ccc\\ddd'\'\'
                        ==>  "''aaa\"\"bbb''ccc\\\\ddd''"

あなたの例は次のように展開できます:

#!/bin/sh

echo \''aaa'\'' "bbb"'
echo "'aaa' \"bbb\""

Sudo su enzotib -c 'echo \'\'\''aaa'\''\'\'\'' "bbb"'\'
Sudo su enzotib -c 'echo "'\''aaa'\'' \"bbb\""'

Sudo su enzotib -c "echo \\''aaa'\\'' \"bbb\"'"
Sudo su enzotib -c "echo \"'aaa' \\\"bbb\\\"\""
12
enzotib

受け入れられた回答は、単純な(1レベルの)引用に有効です。

$ echo $'\'single quote phrase\' "double quote phrase"'
'single quote phrase' "double quote phrase"

表示されるコマンドを機能させるには、2回引用する必要があります。
このスクリプトはすべての作業を実行できます:

#!/bin/bash

quote () { 
    local quoted=${1//\'/\'\\\'\'};
    printf "'%s'" "$quoted"
}

read -r line <<-\_line_to_quote_
'single quote phrase' "double quote phrase"
_line_to_quote_

quote "$line"; echo
quote "echo $(quote "$line")"; echo

スクリプトを実行して取得します。

$ script
''\''single quote phrase'\'' "double quote phrase"'
'echo '\'''\''\'\'''\''single quote phrase'\''\'\'''\'' "double quote phrase"'\'''

最初の行は単純なエコーで機能します。

$ echo ''\''single quote phrase'\'' "double quote phrase"'
'single quote phrase' "double quote phrase"

2行目は、二重引用符で囲まれたコマンドに対して機能します。

Sudo su USER -c 'echo '\'''\''\'\'''\''single quote phrase'\''\'\'''\'' "double quote phrase"'\'''
2
user79743