改行を含む変数を印刷するときに、最後の改行が削除されるのはなぜですか?

改行を含む変数を印刷するときに、最後の改行が削除されるのはなぜですか?

file.txt の内容 (奇妙な点はなく、POSIX で定義されたテキスト ファイル)

iguana
gecko
anole

サンプルスクリプト:

#!/bin/sh

string="$(cat file.txt)"

printf '%s' "$string"

サンプル出力:

[coolguy@somemachine ~]$ ./script.sh
iguana
gecko
anole[coolguy@somemachine ~]$

最後の改行はどうなりましたか? 最後の改行以外はすべて保存されるのはなぜですか? すでに改行がある場合は、echo を使用して改行を追加する必要はないようです。

答え1

印刷ではなく、コマンド置換がそれを行います。それが定義されています。POSIXの説明:

シェルはサブシェル環境でコマンドを実行し、コマンド置換をコマンドの標準出力に置き換えることによってコマンド置換を展開する。置換の最後にある1つ以上の{改行}文字のシーケンスを削除する

削除されることに注意してください全て末尾の改行は 1 つだけではなく複数必要です。

よくあるケースでは、コマンド置換を使用して、 などの 1 行の出力を取得しますosrev=$(uname -r)。ユーティリティは通常、コマンドラインでのユーザーの利便性のために末尾に改行を出力します。ただし、シェル スクリプトでは、その文字列を別の文字列 (たとえば、ファイル名: ) の一部として使用したい場合があります。filename=blahblah-$osrev.datその場合、末尾の改行は厄介なだけです。

そしてもちろん、プレーンではechoいず​​れの場合でも最後の改行が追加されます。


ファイルの内容をそのまま変数に格納したい場合、一般的な回避策は、コマンド置換で余分な文字を追加し、後でそれを削除することです。

printf "foo\nbar\n\n" > file
string=$(cat file; echo x)
string=${string%x}
printf '%q\n' "$string"

両方の末尾の改行が存在することを示す を出力します$'foo\nbar\n\n'


データをどのように処理するかによって、他の方法があるかもしれません。たとえば、ファイルを 1 行ずつ処理したい場合は、while readループや Bash の などです。mapfile

関連情報