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


65

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

'single quote phrase' "double quote phrase"

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

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

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


「もちろん、これは正しい結果を生み出しません」の+1。bash私を怒らせようとしています。
ロルフ

回答:


88

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

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

から man bash

$ 'string'という形式の単語は特別に扱われます。単語は文字列に展開され、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

5
やりすぎ。ほとんどの場合、文字列リテラル構文を使用する必要はありません。
fpmurphy


12

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\\\"\""

10

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

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

既に開いているもの(')を終了し、エスケープされたもの(\')を配置してから、もう1つ(')を開きます。

代わりに:

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

既に開いているもの(')を終了し、別の引用符("'")に引用符を入れてから、別の引用符()を開き'ます。

関連:シングルクォート文字列内のシングルクォートをエスケープする方法は?stackoverflow SEで


1

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

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

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

#!/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"'\'''

-3

echo 'I \' ma student 'は機能しません。ただし、次のように機能します。

echo $ 'I \' ma student 'bashのmanページから:

バックスラッシュが先行する場合でも、単一引用符は単一引用符の間に出現しない場合があります。.... $ 'string'という形式の単語は特別に扱われます。単語は文字列に展開され、ANSI C標準で指定されているようにバックスラッシュでエスケープされた文字が置き換えられます。


6
これにより、既存の回答に何も追加されません。
ジェイソンライアン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.