printf
と聞きました echo
よりも優れています 。 printf
を使用しなければならなかった私の経験から、1つのインスタンスしか思い出せません。 echo
RHEL 5.8の一部のプログラムに一部のテキストをフィードするためには機能しませんでしたが、printf
やりました。しかし、明らかに他にも違いがあるので、それらが何であるか、そしてどちらを使用するかについて特定のケースがあるかどうかを尋ねたいと思います。
承認された回答:
基本的に、これは移植性(および信頼性)の問題です。
最初は、echo
オプションを受け入れず、何も拡張しませんでした。スペース文字で区切られ、改行文字で終了する引数を出力するだけでした。
さて、誰かがecho "nt"
のようなことができたらいいのにと思いました 改行文字またはタブ文字を出力するか、末尾の改行文字を出力しないオプションがあります。
その後、彼らは一生懸命考えましたが、その機能をシェルに追加する代わりに(perl
など) 二重引用符で囲まれている場合、t
実際にはタブ文字を意味します)、彼らはそれをecho
に追加しました 。
David Kornは間違いに気づき、新しい形式のシェル引用符を導入しました:$'...'
後でbash
によってコピーされました およびzsh
しかし、その時までには遅すぎました。
これで、標準のUNIX echo
2文字のを含む引数を受け取ります および
t
、出力する代わりに、タブ文字を出力します。そして、c
が表示されるとすぐに 引数では、出力を停止します(したがって、末尾の改行も出力されません)。
他のシェル/Unixベンダー/バージョンはそれを別の方法で行うことを選択しました:彼らは-e
を追加しました エスケープシーケンスを展開するオプション、および-n
末尾の改行を出力しないオプション。一部には-E
があります エスケープシーケンスを無効にするために、一部には-n
があります ただし、-e
ではありません 、1つのecho
でサポートされているエスケープシーケンスのリスト 実装は必ずしも他の人がサポートしているものと同じではありません。
Sven Mascheckには、問題の範囲を示す素敵なページがあります。
それらのecho
オプションをサポートする実装では、通常、--
はサポートされません。 オプションの終わりをマークする(echo
いくつかの非Bourneに似たシェルが組み込まれており、zshは--
をサポートしています。 ただし)、たとえば、"-n"
を出力するのは困難です。 echo
を使用 多くのシェルで。
bash
などの一部のシェル ¹またはksh93
²またはyash
($ECHO_STYLE
変数)、動作はシェルがどのようにコンパイルされたか、または環境(GNU echo
)にも依存します $POSIXLY_CORRECT
の場合、の動作も変更されます は環境内にあり、バージョンはzsh
のbsd_echo
オプション、一部のpdkshベースのposix
オプション、またはそれらがsh
として呼び出されるかどうか か否か)。つまり、2つのbash
echo
s、同じバージョンのbash
からでも 同じように動作することは保証されていません。
POSIXによると:最初の引数が-n
の場合 または、引数に円記号が含まれている場合、動作は指定されていません 。 bash
その点でのechoは、たとえばecho -e
という点ではPOSIXではありません。 -e<newline>
を出力していません POSIXが要求するように。 UNIX仕様はより厳密であり、-n
を禁止しています。 c
を含むいくつかのエスケープシーケンスの拡張が必要です 1つは出力を停止します。
多くの実装が準拠していないことを考えると、これらの仕様はここでは実際には役に立ちません。一部の認定でも macOSのようなシステムは準拠していません。
現在の現実を実際に表すために、POSIXは実際に次のように言う必要があります。最初の引数が^-([eEn]*|-help|-version)$
と一致する場合 拡張正規表現または任意の引数にバックスラッシュ(またはα
のようなバックスラッシュ文字のエンコーディングがエンコーディングに含まれている文字)が含まれている BIG5文字セットを使用するロケールでは、動作は指定されていません。
全体として、echo "$var"
が何であるかわかりません $var
を確認できない限り、出力されます バックスラッシュ文字を含まず、--
で始まらない 。 POSIX仕様では、実際にはprintf
を使用するように指示されています。 その場合は代わりに。
つまり、echo
は使用できないということです。 制御されていないデータを表示します。つまり、スクリプトを作成していて、外部入力(ユーザーからの引数、またはファイルシステムからのファイル名など)を受け取っている場合、echo
を使用することはできません。 表示します。
これで問題ありません:
echo >&2 Invalid file.
これはそうではありません:
echo >&2 "Invalid file: $file"
(一部の(UNIX非準拠)echo
では問題なく動作しますが bash
のような実装 xpg_echo
のとき オプションは、コンパイル時や環境を介した場合など、何らかの方法で有効にされていません。
file=$(echo "$var" | tr ' ' _)
ほとんどの実装ではOKではありません(yash
を除く) ECHO_STYLE=raw
を使用 (yash
という警告付き の変数は任意のバイトシーケンスを保持できないため、任意のファイル名を保持できません)およびzsh
のecho -E - "$var"
。
printf
一方、少なくともecho
の基本的な使用法に限定されている場合は、より信頼性が高くなります。 。
printf '%sn' "$var"
$var
のコンテンツを出力します 含まれている可能性のある文字に関係なく、改行文字が続きます。
printf '%s' "$var"
末尾の改行文字なしで出力します。
現在、printf
にも違いがあります 実装。 POSIXで指定されている機能のコアがありますが、多くの拡張機能があります。たとえば、%q
をサポートするものもあります 引数を引用しますが、その方法はシェルごとに異なり、uxxxx
をサポートするものもあります。 Unicode文字の場合。 printf '%10sn' "$var"
では動作が異なります マルチバイトロケールでは、printf %b '123'
には少なくとも3つの異なる結果があります
しかし、結局のところ、printf
のPOSIX機能セットに固執する場合 あまり凝ったことをしようとしないでください。問題はありません。
ただし、最初の引数は形式であるため、可変/制御されていないデータを含めないでください。
より信頼性の高いecho
printf
を使用して実装できます 、のように:
echo() ( # subshell for local scope for $IFS
IFS=" " # needed for "$*"
printf '%sn' "$*"
)
echo_n() (
IFS=" "
printf %s "$*"
)
echo_e() (
IFS=" "
printf '%bn' "$*"
)
サブシェル(ほとんどのシェル実装で追加のプロセスを生成することを意味します)は、local IFS
を使用して回避できます。 多くのシェルを使用するか、次のように記述します:
echo() {
if [ "$#" -gt 0 ]; then
printf %s "$1"
shift
if [ "$#" -gt 0 ]; then
printf ' %s' "[email protected]"
fi
fi
printf 'n'
}
メモ
1。どのようにbash
のecho
動作は変更できます。
bash
を使用 、実行時に、echo
の動作を制御するものが2つあります。 (enable -n echo
の横にあります またはecho
を再定義する 関数またはエイリアスとして):
xpg_echo
bash
オプションとbash
かどうか posixモードです。 posix
bash
の場合、モードを有効にできます sh
と呼ばれます またはPOSIXLY_CORRECT
環境内またはposix
を使用している オプション:
ほとんどのシステムのデフォルトの動作:
$ bash -c'echo -n "
Linux