shell command Substitutionが末尾の改行文字を飲み込むのはなぜですか?


25

次の例と、最近の質問 bashのように、末尾の改行文字はどこに消えましたか?、「なぜ」それが起こるのか知りたい

  x="$(echo -ne "a\nb\n")" ; echo -n "$x" | xxd -p 
# Output is: 610a62 
# The trailing newline from the 'echo' command
#   has been "deleted" by Command Substitution

私は、シェルアクション、つまりコマンド置換から、置換しているコマンド出力からいくつかのデータを実際に削除するための非常に重要な理由
があるはずだと思います... しかし、私はこれを回避することができませんそれがすることになっているもののアンチテーゼ... コマンドの出力をスクリプトプロセスに戻す... 1つの文字を保持することは奇妙に思えますが、それには理にかなった理由があると思います...その理由が何かを知りたいと思っています。 。


回答:


22

シェルはもともと完全なプログラミング言語であることを目的としていなかったためです。

\n一部のコマンド出力から末尾を削除することは非常に困難です。ただし、表示目的では、ほとんどすべてのコマンドの出力は\nで終わるため、別のコマンドで使用する場合は、簡単に削除する必要があります。$()建設による自動撤去が選択された解決策でした。

だから、多分あなたは答えとしてこの質問を受け入れるでしょう:

\nこれが次のコマンドで自動的に行われなかった場合、末尾を削除する簡単な方法を見つけることができますか?

> echo The current date is "$(date)", have a good day!

書式設定された日付に表示される可能性のある二重スペースの破壊を防ぐには、引用符が必要であることに注意してください。


1
あなたの言うことが本当なら、私は絶対にun然とするでしょう。ある場合はshopt、あなたの説明デフォルトの動作を変更するには、その後、私は再び幸せになると思います...私はそれは難しいバッシュ/ Linuxは/ Unixはという理由だけで、「標準出力をキャプチャする」などの重要な機能を汚染することを考えるように見つけることdateはありません。 with / without '\ n'オプション...明らかな修正は、bash(または他のシェル)がshoptこれを持っていることです...知っていますか?..そして、この問題の理由と理由を説明する参照リンクはありますか?...そして、なぜdate\ nオプションがないのか。
Peter.O

2
コマンド置換は、1979年のUnixの「第7版」のBourneシェルの最初のバージョンに登場しました。すでに大きな革命であり、「\ n」を追跡することを気にしない人はいなかったと思います。はい、10分以内にマンページを読むことができ、それまでコマンド置換について何も変わっていないようです。好ましい$()代替構文を除きます。
ステファンギメネス

ありがとう..これはレガシーな問題かもしれないと思っていたので、コマンド置換をもっと注意深く見始める方が良いという事実に間違いなく形を整えています。今日まで、私は祈りの翼で生き延びていたに違いありません。末尾の\ nを保持したいので、次のようにコーディングする必要があります:( { echo -n "The current date is "; var="$(date; echo -e x)"; var="${var%x}"; echo -n "$var"; echo ", have a good day!"; }..だからそうです:)
Peter.O

PSは、私の上記のコメントを再:もちろん、単にdate動作しますが、私はちょうど使用dateの一例として、任意のコマンド...
Peter.O

日付に関するあなたの「質問」は、コマンド置換がそれを行う理由を理解するための最も強い約束でしたので、これは私の質問に対する「最良の」答えでした...そして私は確かに他の良い答えも必要としました..
Peter.O

19

それは標準の一部です:

実行することで、コマンド置換を拡大するものとシェルコマンドをサブシェル環境では、(参照のシェルの実行環境とコマンド置換(のテキスト置き換え)コマンド削除、コマンドの標準出力をプラス囲む「$()」またはバッククォートを)置換の最後にある1つ以上の<newline>のシーケンス。

もちろん、標準がこのように書かれているのは、おそらくそれがどのようにksh行われたかなどですが、標準であり、文書化された動作です。気に入らない場合は、Perlなどを使用して、後続の改行を保持してください。


素敵な要約..ありがとう..そしてリンクは確かに助けました
-Peter.O

4
それは、Bourneシェルがそれを行った方法であり、それ以来、他のすべてのシェルが標準であるためです。
ジル「SO-悪であるのをやめる」

6

まあ、それは私には理にかなっています。改行は、通常のコマンド出力の最初の場所にのみ存在するため、コマンドが新しい行で完了するとプロンプトが表示されます。改行はほとんどの場合、元の出力の一部ではなく、画面をきれいにするためにあります。コマンドからの出力を解析しているとき、通常、最後の改行は面倒です。wcコマンドが2行のテキストを出力するのはなぜですか?ああ、そうではなく、改行が続くものを出力します。解析wcするとき、2行の出力があるという事実を心配したくありません-実際にはありません。1行しかないのです。


@EightBitTony:私の質問は、端末で何かを表示することとはまったく関係ありません。それは非常に簡単です。表示する改行がある場合、改行が表示されます。ここで問題になるのは\n、元のstdoutストリームのa がコマンド置換によって削除されることです。すなわち。データが「引用符」でラップされている場合でも、元のデータ(非常に重要なデータ)の末尾の改行が削除されます。Word Splittingがどのように、そしてなぜ動作するのかは理にかなっていますが、Command Substitutionが改行末尾の改行のみを削除する理由はまったくわかりません。
Peter.O

1
あなたが言ったことは私の見解を変えません。多くの場合、出力の最後の改行は、データの一部としてではなく、表示目的でのみ存在します。
EightBitTony

私はあなたの意見に同意し、すべてを一緒にしています...はい、出力の最後の改行便宜上のものです...しかし、私の問題はそれとは何の関係もありません...私は尋ねています:なぜコマンド置換が強制的にそれを削除するのですか? ?...これらは2つの異なる問題です。たぶん私の質問は「組み込みの回避策はありますか?」。末尾のダミー文字を追加してこの問題をコーディングしなければならないので、うんざりします!...必要に応じてそれを行いますが、bashに悩まされたのはこれが初めてです(そして、私はショック状態にあります:) ..とてもうまくいきます...
Peter.O

別の答えで述べたように、それは標準の一部です。私にとっては、データを後処理するとき、便利な改行ではなく、データのみを表示したいので、それがそのように行われると思います。これは、シェルがパイプ内のデータを処理していることを期待し、改行がデータではないためです。これ以上、これを議論する必要があります。
EightBitTony

おかげで..私は今、アイデアをかなりよく持っています..コマンド置換が、それらを維持するのではなく、単に末尾の改行をドロップすることに傾いているようです..その動きには私が「感じていない」いくつかの知恵があるはずです「それでも、ファイル名に含まれるすべての小文字を圧倒的に使用するのは少し奇妙で不必要だと思っていましたが、先日は実際には非常に快適なシステムだと思っていました。 (より深く)コマンド置換の動作の韻と理由を参照してください、
いつか...-Peter.O

1

私は同じ問題に遭遇していましたが、以下の例を見つけました。引用は状況を助けたようです、少なくとも私にとってはそうでした:

http://tldp.org/LDP/abs/html/commandsub.html

dir_listing=`ls -l`
echo $dir_listing     # unquoted

# Expecting a nicely ordered directory listing.

# However, what you get is:
# total 3 -rw-rw-r-- 1 bozo bozo 30 May 13 17:15 1.txt -rw-rw-r-- 1 bozo
# bozo 51 May 15 20:57 t2.sh -rwxr-xr-x 1 bozo bozo 217 Mar 5 21:13 wi.sh

# The newlines disappeared.


echo "$dir_listing"   # quoted
# -rw-rw-r--    1 bozo       30 May 13 17:15 1.txt
# -rw-rw-r--    1 bozo       51 May 15 20:57 t2.sh
# -rwxr-xr-x    1 bozo      217 Mar  5 21:13 wi.sh

2
ここで何が起こっていますか。$str文字列を含む変数があるとします"a b c"。あなたは合格した場合$strecho引用符(echo $str)、echo受信しますabと、c3つの別々の引数として。シェルは、引数の間の空白を気にしません。echo次に、これらの引数をスペースで区切って出力します"a b c"。変数をecho引用符(echo "$str")で囲んで渡すと、シェルはその変数を1つの引数と見なし、その引数echoとして受け取るため、空白は縮小されません。同じことが改行にも当てはまります。

1
元のポスターが抱えている問題は、彼のコマンドの末尾の改行(最後の改行のみ)が消えていることです。-nフラグを渡さない限りecho、出力に末尾の改行を追加するため、例の両方のエコーには末尾の改行があります。ただし、echo -n $dir_listingまたはを試してみるとecho -n "$dir_listing"、末尾の改行が引用符付きまたは引用符なしで印刷されていないことがわかります$dir_listing。これは、問題がコマンド置換にあることを示しています。

2
TLDPはひどくシェルスクリプトについて学ぶために時代遅れな場所。代わりにWooledge Bash Wikiを試してください。mywiki.wooledge.org/BashGuide
ワイルドカード

-1

echo "hello "(引用符なしで)なぜスペースを飲み込んでしまうのですか?IFS文字の値は、シェルによって区切り文字と見なされるため、末尾の文字列(何も区切らない)は削除されます。コマンド置換は、サブシェルでコマンドを実行するだけなので、同じロジックに従います。


@Philomath:を介して表示される場合、両方x="hello  "と後続のスペースx="hello     "すべて失われますecho $x...ただし、Command Substitutonの最後の改行のみが失われます。
Peter.O

奇妙な、私は(XXDを検証する)私はbashの違いが表示されない
フィロマス

私はこれをチェックします...後続の改行をすべて削除します...その印象を得たときにIFSを試していたので、それをキャンセルしましょう:) ..しかし、質問はまだ残っています...それは基本的な部分です複数のスペースを単一のスペースに凝縮し、先頭と末尾の空白を完全に削除するための単語分割..それ理解できますが、コマンド置換では、すべての空白ではなく\ n だけを削除する理由を理解していません単語の分割を使用)、そしてなぜ最後だけが終了するのか?
Peter.O

4
IFSコマンド置換の終わりで改行を削除することとは関係ありません。
ジル 'SO-悪であるのをやめる'
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.