bash backtickオペレーターに出力の改行を保持させるにはどうすればよいですか?


36

バックティック置換でbashが改行を食べないようにする方法はありますか?

例えば:

var=`echo line one && echo line two`
echo $var

line one line two

私が欲しいのは

var=`echo line one && echo line two` # plus some magic
echo $var

line one
line two

回答:


54

バックティックの置換の問題ではなく、echo;の問題です。制御文字を機能させるには、変数を引用する必要があります。

$ var=`echo line one && echo line two`
$ echo "$var"
line one
line two

だから、bashはコマンドラインの変数を展開しながら改行を削除しますか?そして、その動作は変数を引用することで無効にできますか?
遅い毒

7
bash引用を通知する必要があり、コマンドを実行する前に、パラメータの拡張を行い、bashあなたは、単一の文字列ではなく4単語を印刷すること(lineonelineおよびtwo)。試してください:echo a <many spaces> becho "a <many spaces> b"。見てみましょうこの回答あまりにも。
-cYrus

5

@cyrusが正しいとしても、実際には質問全体に答えているわけではなく、何が起こっているのかの説明もありません。

それで、それを通して歩きましょう。

文字列の改行

最初に予想されるバイトシーケンスを決定します。

$ { echo a; echo b; } | xxd
0000000: 610a 620a                                a.b.

次に、コマンド置換(セクション3.5.4)を使用して、このバイトシーケンスのキャプチャを試みます。

$ x=$( echo a; echo b; )

次に、単純なエコーを実行してバイトシーケンスを確認します。

$ echo $x | xxd
0000000: 6120 620a                                a b.

したがって、最初の改行はスペースに置き換えられ、2番目の改行はそのまま残されたようです。しかし、なぜ ?

ここで実際に何が起こっているか見てみましょう:

まず、bashはシェルパラメーター拡張を実行します(セクション3.5.3)

「$」文字は、パラメーター展開、コマンド置換、または算術展開を導入します。展開されるパラメータ名またはシンボルは中かっこで囲むことができます。これらはオプションですが、名前の一部として解釈される可能性のある直後の文字から展開される変数を保護する役割を果たします。

その後、bashはワード分割を行います(セクション3.5.7)

シェルは、単語分割の二重引用符内では発生しなかったパラメーター展開、コマンド置換、および算術展開の結果をスキャンします。

シェルは、$ IFSの各文字を区切り文字として扱い、他の展開の結果をこれらの文字の単語に分割します。IFSが設定されていない場合、またはその値が正確に...

次に、bashはそれを単純なコマンドとして扱います(セクション3.2.1)

単純なコマンドは、最も頻繁に遭遇する種類のコマンドです。これは、空白で区切られた一連の単語であり、シェルの制御演算子の1つで終了します(定義を参照)。通常、最初の単語は実行するコマンドを指定し、残りの単語はそのコマンドの引数です。

空白の定義(セクション2-定義)

空白スペースまたはタブ文字。

最後に、bashはecho(セクション4.2-Bash組み込みコマンド)内部コマンドを呼び出します

...スペースで区切られ、改行で終了する引数を出力します。...

要約すると、改行はワード分割によって削除され、エコーは2つの引数「a」と「b」を取得し、スペースで区切って改行で終わる出力を行います。

@cyrusが提案したこと(および-nでエコーからの改行を抑制する)を行うと、結果が良くなります。

$ echo -n "$x" | xxd
0000000: 610a 62                                  a.b

文字列の最後の改行

まだ完璧ではありませんが、末尾の改行はなくなりました。コマンド置換(セクション3.5.4)を詳しく見る:

Bashは、コマンドを実行し、コマンド置換をコマンドの標準出力に置き換え、末尾の改行を削除することにより、展開を実行します。

改行が消える理由が明らかになったので、bashはだまされて改行を保持できます。これを行うには、最後に追加の文字列を追加し、変数を使用するときに削除します。

$ x=$( echo a; echo b; echo -n extra )
$ echo -n "${x%extra}" | xxd
0000000: 610a 620a                                a.b.

TL; DR

出力の最後に余分な部分を追加し、変数を引用します。

$ cat /no/file/here 2>&1 | xxd
0000000: 6361 743a 202f 6e6f 2f66 696c 652f 6865  cat: /no/file/he
0000010: 7265 3a20 4e6f 2073 7563 6820 6669 6c65  re: No such file
0000020: 206f 7220 6469 7265 6374 6f72 790a        or directory.
$ cat /no/file/here 2>&1 | cksum
3561909523 46
$ 
$ var=$( cat /no/file/here 2>&1; rc=${?}; echo extra; exit ${rc})
$ echo $?
1
$ 
$ echo -n "${var%extra}" | xxd
0000000: 6361 743a 202f 6e6f 2f66 696c 652f 6865  cat: /no/file/he
0000010: 7265 3a20 4e6f 2073 7563 6820 6669 6c65  re: No such file
0000020: 206f 7220 6469 7265 6374 6f72 790a        or directory.
$ echo -n "${var%extra}" | cksum
3561909523 46

0

私は、cYrusの答えについてのコメントに私の小さな追加を入れたでしょうが、私が思う答えについてはまだコメントできません。したがって、完全性のために、cYrusの彼の答えの一部を複製します。

あなたのコードの最初の行で起こることは、実際に、バックティックの置換が、文書化されているように、置換されたコマンドの出力の末尾の改行を食べるということです。しかし、2行の間にある改行は食べません。

コードの2行目で行われるのは、1行目と2行目の2つの引数でエコーが実行されることです。展開された変数を引用すると、それが修正echo "$var"されます。これにより、1行目と2行目の間に改行が保持されます。そしてecho、デフォルトで末尾の改行を追加して、すべてが問題ないようにします。

コマンド置換の出力ですべての末尾の改行を保持したい場合、回避策は出力に別の行を追加することです。これはコマンド置換後に削除できますこちらを参照してください

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