`echo -e“ \\\ SOME_TEXT”`にバックスラッシュが1つしか表示されないのはなぜですか?


19

Linuxシェルでのキャラクターエスケープの舞台裏で何が起こっているのかを説明していただけますか?私は次のことを試してみましたが、何がどのように(そしてどのように)起こっているのかを理解するのに成功しませんでした:

root@sv01:~# echo -e "\ Hello!"
\ Hello!
root@sv01:~# echo -e "\\ Hello!"
\ Hello!
root@sv01:~# echo -e "\\\ Hello!"
\ Hello!
root@sv01:~# echo -e "\\\\ Hello!"
\ Hello!
root@sv01:~# echo -e "\\\\\ Hello!"
\\ Hello!
root@sv01:~# echo -e "\\\\\\ Hello!"
\\ Hello!
root@sv01:~# echo -e "\\\\\\\ Hello!"
\\ Hello!
root@sv01:~# echo -e "\\\\\\\\ Hello!"
\\ Hello!
root@sv01:~# echo -e "\\\\\\\\\ Hello!"
\\\ Hello!
root@sv01:~# echo -e "\n Hello!"

 Hello!
root@sv01:~# echo -e "\\n Hello!"

 Hello!
root@sv01:~# echo -e "\\\n Hello!"
\n Hello!

そこで完全に迷子になったので、たとえば、3つのバックスラッシュが1つのバックスラッシュしか与えないのはなぜですか?最初の2つは1つにエスケープされ、3つ目はエスケープするものが見つからないのでスラッシュのままになります(最初の実験の行)が、3つ目は消えてしまいます。
なぜ4つから1つのバックスラッシュを取得してい\\\\ Helloますか?各ペアが1つのバックスラッシュ-> 2つのバックスラッシュを与えることを期待します。

そして、\ nエスケープするために最後のケースで3つのバックスラッシュが必要なのはなぜですか?それを得るために脱出の背景で何が起こっていますか?そしてそれは\\nケースとどう違うのですか?

前の行で何が起こっているかについての説明に感謝します。


echo -e動作はとにかく標準で定義されていません-pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.htmlを参照してください。出力は完全に実装定義の入力でのリテラルのバックスラッシュのどこがあります場合にのみ許されるオプションは、-n(標準規格に準拠した実装がありますことを意味しecho -e、印刷-eの出力にします)。
チャールズダフィー

...シェルがbashであることを100%確信していてそれでもecho -e安全ではありません:echo両方のオプションposixxpg_echo実行時オプションが有効になっている場合、または同等のビルド時オプションでコンパイルされている場合、標準に従って動作します。安全な練習は使用することがあるprintfようにする方法を記述した上記のリンクのアプリケーション使用法と根拠の項を参照-代わりprintfの代替として作用しますecho
チャールズダフィー

回答:


28

これはbashecho -e結合されているためです。からman 1 bash

引用符で囲まれていないバックスラッシュ(\)はエスケープ文字です。を除き、次の文字のリテラル値を保持します<newline>。[…]

二重引用符で文字を囲むことを除いて、全ての文字のリテラル値を保持し$、 `、 \:、[...] バックスラッシュは、次のいずれかの文字が続いた場合にのみ意味をその特別なを保持し$、`、 、"\または<newline>

ポイントは、二重引用符で囲まれたバックスラッシュが常に特別なわけではないということです。

echo一般的にはさまざまな実装がありますが、ビルトインbashです。ここで重要なことは、この動作です。

場合は-e有効になっている、以下の配列が認識されます。
\\
バックスラッシュ
[...]
\n
新ライン

これでデコードできます:

  1. echo -e "\ Hello!"–特別なこともbash、特別なこともありませんecho\滞在します。
  2. echo -e "\\ Hello!"–最初のもの\bash、2番目のものを\文字通り処理するように言っています。上記のようにecho取得\ Hello!して動作します。
  3. echo -e "\\\ Hello!"–最初のもの\bash、2番目のものを\文字通り処理するように言っています。echoを取得し\\ Hello!、(ので-e\\として認識し\ます。
  4. echo -e "\\\\ Hello!"–最初のもの\bash、2番目のものを\文字通り処理するように言っています。3番目は4番目についても同じことを言っています。echoを取得し\\ Hello!、(ので-e\\として認識し\ます。
  5. echo -e "\\\\\ Hello!"–最初のもの\bash、2番目のものを\文字通り処理するように言っています。3番目は4番目についても同じことを言っています。最後のものは特別ではありません。echoを取得し\\\ Hello!、(ので-e)イニシャルを\\として認識し\、最後\はそのままです。

等々。ご覧のとおり、最大4つの連続したバックスラッシュが結果に1つを与えます。だからこそ、3つを得るために(少なくとも)9つ必要です。9 = 4 + 4 + 1。

今では\n

  1. echo -e "\n Hello!"–には特別なことbashは何もありません。エコーは同じ文字列を取得し、(なぜなら-e\n改行として解釈します。
  2. echo -e "\\n Hello!"–とbash解釈\\\ます。echo取得\n Hello!し、結果は上記と同じです。
  3. echo -e "\\\n Hello!"bashイニシャル\\\; として解釈します echo取得し\\n Hello!、(ので-e)印刷する必要が\\あるリテラルとして解釈\します。

結果は'"(異なるbash動作による)の代わりに(異なる動作により)-e異なる場合がありechoます(異なる動作のため)。


1
どうもありがとうございました!だから、2つのエスケープステップがあります。bashによって実行されるステップ-eと、bashによってすでに判断されたテキストを判断する2番目のステップです、そうですか?それが正しければ、混乱はなくなります。あなたはおそらくどのようにsed振る舞うのか言及してもらえますか?それはエスケープテクニックに独自のビルドを持っていますか?だから私はそれがエコーのように振る舞うの-eですか?
モハメッドヌールディン

2
@MohammedNoureldinはい、2つのステップがあります。元の質問はそのままで構いませんsed。で複雑になりすぎないようにしましょう。ただし、(約sedのみ)別の質問をすることもできます。最初に独自の調査を行ってください。
カミルマシオロウスキ

3
@MohammedNoureldin sedは同じ基本原則に従います。bash はルールに従ってコマンドラインを解釈し、引用符とエスケープを解析(および削除)します。その結果は、に渡されるsedに従ってそれを解釈する、そのエスケープルール。ところで、で一重引用符で囲まれた文字列を使用することでこれを簡素化できますbash(bashによるエスケープ解釈が行われないため)-bashは一重引用符を削除し、その中にあるものを直接コマンドに渡します。
ゴードンデイヴィソン

echo -e "\\\n Hello!"ケースにはまだ小さな問題があります。ここで、bashはエスケープを行い、になり\\n-e結果の2つのバックスラッシュをエスケープ\\nしてからになり\nます。誰が解釈\nして新しい行にするのでしょうか?通常echo -e "\n Hello!"、bashは何もせず、改行として-e解釈\nします。しかし、最初に言及した状況では、解釈プロセスは解釈される前に行われました\n。説明してください。
モハメッドヌールディン

1
私のせいです、私は彼らの夜でそれについて2日間読んでいたので、どうやら私はケースをミックスし始めたようです、sed私は昨夜私を混乱させた何かを手に入れたと思います(おそらく昨日何か間違ったことをしました)が、今は再び同じしようとしたecho -esed、私は除外、感謝と同じことをしました!
モハメッドヌールディン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.