シェル全体のバックスラッシュの処理


9

どのようにechoしてprintf御馳走バックスラッシュでzshbashおよび他のシェル?

下ではzshの私は、次の動作を取得します:

$ echo "foo\bar\baz"
foaaz
$ echo "foo\\bar\\baz"
foaaz
$ echo 'foo\bar\baz'
foaaz
$ echo 'foo\\bar\\baz'
foo\bar\baz

下ではbashの、物事はもう少し一貫性のあるように見えます。

bash$ echo "foo\bar\baz"
foo\bar\baz
bash$ echo 'foo\bar\baz'
foo\bar\baz
bash$

しかし、もっと具体的に:どのように私は、次のようなバックスラッシュを含む文字列渡すことができ\\foo\bar\somethingました:

  • echo
  • printf
  • print

まったく同じ文字列を取得しますか?zshbash)?

次に、zshの関数の別の実験を示します。

function foo
{
    echo -E '$1'
}

$ foo \\here\is\some\path
$1

どうすれば印刷するだけ\\here\is\some\pathですか?

更新(注:これは現在、Stephaneのコメントで回答されています)

私はzsh 5.0.2で以下を試しました:

function foo
{
    printf '$s\n' $1 
}

foo '\\some\path'

しかし、これは印刷し$sますか?


3
使用するとprintfecho点で移植性がありません。
ヨルダン2013年

あなたは "foo"関数:で置き換え'"それを:foo '\\ here \ is \ some \ path'で呼び出します(そうでなければ、呼び出し側のシェルは、関数に到達する前に '\'を解釈する機会を得ます)
Olivier Dulac

2
使用'$s\n'すべきであったときに使用した関数'%s\n'
cjm 2013年

回答:


12

zsh echobashUNIXモードのように、標準的な方法で動作します。つまり\b、UNIX仕様で要求されているように、ASCII BS文字に拡張されます。

echo任意の文字列を表示するために使用しないでくださいprintf

printf '%s\n' "$1"

print -r -- "$1"動作しますが、ksh/ zsh固有です。

echo -E - "$1"連携zshし、私はいくつかのBSDを信じています。

cat << EOF
$1
EOF

printfコマンドがなかった数十年からのものでさえ、ボーンのようなシェルで動作しますが、それは新しいプロセスを生み出しますprintf

ちなみに、バックスラッシュはシェル(すべてのシェルを除くrc)に固有であるため、シェルのコマンドラインでエスケープする必要があります。

$ foo '\\foo\bar'

foo \\foo\bar失われたバックスラッシュを再発明できない"\foo\bar"文字列を渡しfooます。


ステファンに感謝します。奇妙なことに、この構造printf '%s\n' "$var"はコマンドライン(zsh 5.0.2、つまり最新のもの)では機能しますが、関数内では機能しません(OPの私の更新を参照)。どうして?
Amelio Vazquez-Reina

1
それprintf '%s\n'printf '$s\n'あなたが欲しくないのです。(注)以外のシェルの変数を引用する必要があることzsh"$1"ではない$1)と、標準的な関数定義の構文があるfoo() { ...; }任意のシェルもののしかし、bash許可foo() any-command、およびfunction foo { .... }あるksh構文。
ステファンChazelas

@マーカス、それは別の質問への答えです。
ステファンChazelas

1

新しい答え:read -r var

-r  raw input - disables interpretion of backslash escapes and line-continuation in the read data

表示するには:

printf "%s" "$var"
echo "$var"

うまくいくはずです。

したがって、foo関数の場合:

function foo
{
    read -r var
    echo -E "var is : ${var}"
}

$ foo 
\\here\is\some\path
var is : \\here\is\some\path

以下の古い答え(答えないが、多分役に立つ^^)

それぞれ\\\に置き換えて、シェルに「それが文字通り\欲しい」と伝えます。それ以外の場合(たとえば、zshでは、例では)、\b「1バックスペース」などを意味する可能性があります。

たとえば、sedを使用できます。

sed -e 's,\\,\\\\,g' < the_original > the_escaped_backslaches_version

(sedに同じことを伝えるために「\」をエスケープする必要がある方法を参照してください:「それはリテラル "\"が欲しい」)(そして、シェルが解釈するのを避けるために、「」ではなく「」で囲むことに注意してくださいそのほとんども)


ありがとうございましたが、タイトルで述べたとおり、バックスラッシュがエスケープされないようにしたいと思います。
Amelio Vazquez-Reina

おっと、編集します^^
Olivier Dulac

ありがとう!しかしread -r var、からの入力を待つよう STDINです。引数として渡した場合はどうなりますか?(例:foo \\here\is\some\path
Amelio Vazquez-Reina

シェルはバックスラッシュを解釈しています。そのため、引数をreadに移動する必要があります。私の「foo」の例を参照してください。
Olivier Dulac 2013年

1
iow:シェルによる文字列の「非標準」処理が必要です。シェルを起動してプログラムを実行するのではなく、プログラムをより簡単に(より広範囲に)希望どおりに準拠させることができます。あなたが望むように動作します。したがって、プログラムが起動したら、 "read -r"を使用して、起動するシェルコマンドラインではなく、引数(エスケープしたくない "\"を含むもの)を渡します。
Olivier Dulac 2013年

1

バックスラッシュエスケープ文字あるため(通常、リテラル値が必要な場合はエスケープする必要があるため)、一般的にはそうすることができません。BASHはこの目的のために単一引用符を提供しますが、単一引用符付き文字列内で単一引用符をエスケープすることはできません。

用としてecho矛盾、それが内蔵されている(ある程度)シェル全体に動作が異なる場合があります。たとえば、BASH組み込みには、-eバックスラッシュシーケンスを解釈するように指示するオプションがあります。これを使用すると、Zシェルで見た動作を取得できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.