コマンド置換から末尾の改行文字はどこに行ったのですか?


15

次のコードは、状況を最もよく説明しています。最後の行が末尾の改行文字を出力しないのはなぜですか?各行の出力はコメントに表示されます。GNU bashバージョン4.1.5を使用しています

     echo -n $'a\nb\n'                  | xxd -p  # 610a620a  
           x=$'a\nb\n'   ; echo -n "$x" | xxd -p  # 610a620a
     echo -ne "a\nb\n"                  | xxd -p  # 610a620a
x="$(echo -ne "a\nb\n")" ; echo -n "$x" | xxd -p  # 610a62

4
まれに、必要な場合の回避策:tmp=$(somecommand; echo a); tmp=${tmp%a}
ジル「SO-悪であるのをやめる」


1
@Gilles:上記のあなたの例について:tmp=$(somecommand; echo a)...これは確かにポイントを家に駆り立てました...例を見たまで、私の傾向はまだ使用することになっていたでしょうecho -n a...しかし、もちろん、必要はありません! 、-nコマンド置換は導入された末尾の改行をいずれの場合でも削除するためです!...ありがとう
...-Peter.O

回答:


18

コマンド置換機能 $()(およびその従妹)は、特に後続の改行を削除します。これは文書化された動作であり、コンストラクトを使用するときは常にそれに注意する必要があります。

テキスト本文内の改行は置換演算子によって削除されませんが、シェルで単語分割を行うときにも削除される場合があるため、引用符を使用したかどうかによって結果が異なります。これら2つの使用法の違いに注意してください。

$ echo -n "$(echo -n 'a\nb')"
a
b

$ !! | xxd -p
610a62

$ echo -n  $(echo -n 'a\nb')
a b

$ !! | xxd -p   
612062

2番目の例では、出力は引用符で囲まれず、改行は単語分割として解釈され、出力にスペースとして表示されます!


1
Calebに感謝します。引用符を付けない場合、空白を単一のスペースに変更することを認識していました。そのため、引用符を付けていても末尾の改行が消えることに最も驚いていました。 「通常」の動作のためには、あるコマンドの置換リンクのために、まあ...改行を落とすセラビ...と感謝
Peter.O

6

コマンド置換を使用する場合、シェルはサブシェルでコマンドを実行し、それらの標準出力を返します。このプロセスでは、IFS文字が引用符で囲まれていない場合、IFS文字の重要性が失われます。これは、コマンドが単純な分割単語を返すため、末尾の単語が削除されるためです。例えば:

$ echo "$(echo -e '\n')" | wc
 1       0       1

$ echo -e '\n' | wc
2       0       2

より実際的にpwdは、ディレクトリ名の間に改行がある場合でも機能しますが、機能し$(pwd)ません。

通常の回避策は、コマンドの最後に何かを追加し、その後それを削除することです。


1
あなたの例が意味を作るためにしてくれてありがとうフィロマスが...ところで、あなたは最初の例は、構文的に間違って..です(「wcが」引数として文字列を受け付けない)、最初のものが考えられecho "$(echo -e '\n')" | wc、その出力1   0   1に比べて、2   0   2
Peter.O

@fred:おっと、タイプミスです。
フィロマス

1
「スペースに変換」は適切な説明ではなく、いくつかの分割が関係しています。特に、IFSからスペースを削除できますが、これらはセパレータとして機能しません。さらに、あなたの例は特別なケースのカテゴリーに分類され、との間に違いが$(pwd)あり"$(pwd)"ます。カレブの答えをご覧ください。
ステファンギメネス

PS ..通常の回避策のあなたの提案は、私がこれを解決するために必要なものです
。.– Peter.O

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