基本的に、これは移植性(および信頼性)の問題です。
最初は、echo
オプションを受け入れず、拡張もしませんでした。実行されていたのは、スペース文字で区切られた引数を出力し、改行文字で終了することだけでした。
さて、誰かがecho "\n\t"
改行文字やタブ文字を出力したり、末尾の改行文字を出力しないオプションがあればいいと思いました。
その後、彼らはより難しいと考えましたが、その機能をシェルに追加する代わりに(perl
二重引用符の中に\t
実際にはタブ文字を意味するように)、それをに追加しましたecho
。
デイビット・コーンは間違いを実現し、シェルの引用符の新しい形の導入:$'...'
後でコピーされたbash
とzsh
、それはその時によってあまりにも遅かったし。
標準のUNIX echo
が2つの文字\
とを含む引数を受け取るとt
、それらを出力する代わりに、タブ文字を出力します。そして\c
、引数を見るとすぐに出力を停止します(したがって、末尾の改行も出力されません)。
他のシェル/ Unixベンダー/バージョンは異なる-e
方法を選択しました。エスケープシーケンスを展開する-n
オプションと、末尾の改行を出力しないオプションを追加しました。-E
エスケープシーケンスを無効にするものもあれば、-n
そうでないものもありますが-e
、あるecho
実装でサポートされているエスケープシーケンスのリストは、別の実装でサポートされているものと必ずしも同じではありません。
Sven Mascheckには、問題の範囲を示すすてきなページがあります。
echo
オプションをサポートする実装で--
は、オプションの終わりをマークするためのaのサポートは通常ありません(echo
一部の非Bourneのようなシェルのビルトインはサポート-
しますが、zshはサポートします)。たとえば、で出力"-n"
することecho
は困難です多くのシェル。
以下のようないくつかのシェルにbash
¹またはksh93
²またはyash
($ECHO_STYLE
変数)、行動も、シェルがコンパイルされたか、環境(GNU方法によって異なりますecho
「場合の動作も変更され$POSIXLY_CORRECT
た環境でとバージョンである4、zsh
そのとs」はbsd_echo
、オプションいくつかのpdkshベースのposix
オプションまたはそれらが呼び出されるかどうかsh
)。そのbash
echo
ため、同じバージョンの2 であっても、同じbash
動作をすることは保証されません。
POSIXによれば、最初の引数がである-n
か、いずれかの引数にバックスラッシュが含まれている場合、動作は指定されていません。bash
その点でのechoは、たとえばPOSIXが要求echo -e
するとおりに出力さ-e<newline>
れないという点で、POSIXではありません。UNIX仕様はより厳密であり、出力を停止する-n
エスケープシーケンスを含むいくつかのエスケープシーケンスの拡張を禁止および要求してい\c
ます。
多くの実装が準拠していないことを考えると、これらの仕様はここで実際に助けになりません。macOS 5のような認定システムでさえ、準拠していません。
現在の現実を実際に表すために、POSIXは実際に言う必要があります:最初の引数が^-([eEn]*|-help|-version)$
拡張正規表現に一致するか、いずれかの引数にバックスラッシュ(またはα
、BIG5文字セットを使用するロケールのようにエンコーディングにバックスラッシュ文字のエンコーディングが含まれる文字)が含まれる場合、動作は不特定。
全体として、バックスラッシュ文字が含まれecho "$var"
て$var
おらず、先頭がでないことを確認できない限り、何が出力されるかわかりません-
。その場合、POSIX仕様では実際にprintf
代わりに使用するように指示されています。
つまり、echo
制御されていないデータを表示するために使用することはできません。つまり、スクリプトを記述していて、外部入力(引数としてユーザーから、またはファイルシステムからのファイル名...)を取得している場合、それを使用echo
して表示することはできません。
これで結構です:
echo >&2 Invalid file.
これではありません:
echo >&2 "Invalid file: $file"
(オプションがコンパイル時または環境を介して何らかの方法で有効にされていない場合、のecho
ような一部の(UNIXに準拠していない)実装では問題なく動作します)。bash
xpg_echo
file=$(echo "$var" | tr ' ' _)
ほとんどの実装でOKではない(例外があることyash
でECHO_STYLE=raw
(警告付きyash
の変数は任意のバイトシーケンスそうではない、任意のファイル名)と保持することはできませんzsh
s 'のecho -E - "$var"
6)。
printf
、一方で、少なくともの基本的な使用法に限定されている場合は、より信頼性が高くなりecho
ます。
printf '%s\n' "$var"
$var
含まれる文字に関係なく、改行文字が続くコンテンツを出力します。
printf '%s' "$var"
末尾の改行文字なしで出力します。
現在、printf
実装にも違いがあります。POSIXで指定されている機能の中核がありますが、多くの拡張機能があります。たとえば%q
、引数を引用するa をサポートするものもありますが、その実行方法はシェルごとに異なり\uxxxx
、ユニコード文字をサポートするものもあります。printf '%10s\n' "$var"
マルチバイトロケールでは動作が異なります。少なくとも3つの異なる結果があります。printf %b '\123'
しかし、最終的には、POSIXの機能セットに固執し、それを使いprintf
過ぎないようにしようとしないと、問題はなくなります。
ただし、最初の引数は形式であるため、変数/制御されていないデータを含めることはできません。
echo
を使用してprintf
、より信頼性の高い実装が可能です:
echo() ( # subshell for local scope for $IFS
IFS=" " # needed for "$*"
printf '%s\n' "$*"
)
echo_n() (
IFS=" "
printf %s "$*"
)
echo_e() (
IFS=" "
printf '%b\n' "$*"
)
サブシェル(ほとんどのシェル実装で余分なプロセスを生成することを意味します)はlocal IFS
、多くのシェルで使用するか、次のように記述することで回避できます。
echo() {
if [ "$#" -gt 0 ]; then
printf %s "$1"
shift
fi
if [ "$#" -gt 0 ]; then
printf ' %s' "$@"
fi
printf '\n'
}
ノート
1. bash
のecho
動作を変更する方法。
を使用するbash
と、実行時にecho
(関数またはエイリアスとして、または関数またはエイリアスとしてenable -n echo
再定義する)の動作を制御する2つのことがecho
ありxpg_echo
bash
ます:オプションとbash
posixモードであるかどうか。が呼び出された場合、または環境内にある場合、またはオプションをposix
使用してモードを有効にできます。bash
sh
POSIXLY_CORRECT
posix
ほとんどのシステムのデフォルトの動作:
$ bash -c 'echo -n "\0101"'
\0101% # the % here denotes the absence of newline character
xpg_echo
UNIXが必要とするシーケンスを展開します。
$ BASHOPTS=xpg_echo bash -c 'echo "\0101"'
A
それはまだ光栄で-n
あり、-e
(そして-E
):
$ BASHOPTS=xpg_echo bash -c 'echo -n "\0101"'
A%
xpg_echo
し、POSIXモード:
$ env BASHOPTS=xpg_echo POSIXLY_CORRECT=1 bash -c 'echo -n "\0101"'
-n A
$ env BASHOPTS=xpg_echo sh -c 'echo -n "\0101"' # (where sh is a symlink to bash)
-n A
$ env BASHOPTS=xpg_echo SHELLOPTS=posix bash -c 'echo -n "\0101"'
-n A
今回bash
は、POSIXとUNIXの両方に準拠しています。POSIXモードでbash
は、出力-e
されないため、POSIX準拠ではないことに注意してください。
$ env SHELLOPTS=posix bash -c 'echo -e'
$
xpg_echoおよびposixのデフォルト値は、スクリプトの--enable-xpg-echo-default
および--enable-strict-posix-default
オプションを使用してコンパイル時に定義できconfigure
ます。これは通常、OS / Xの最近のバージョンがをビルドするために行うこと/bin/sh
です。しかし、彼らの正しい考えのUnix / Linuxの実装/配布は、通常はそうしませ/bin/bash
ん。実際、それは真実ではありません/bin/bash
。OracleがSolaris 11(オプションパッケージ)に同梱されて--enable-xpg-echo-default
いるのは、(Solaris 10ではそうではない)でビルドされているようです。
2. ksh93
のecho
動作を変更する方法。
ではksh93
、echo
エスケープシーケンスを展開してオプションを認識するかどうかは$PATH
、$_AST_FEATURES
環境変数や環境変数の内容によって決まります。
またはコンポーネントの前または前の$PATH
コンポーネントが含まれている場合、SysV / UNIXのように動作します(シーケンスを展開し、オプションを受け入れません)。最初に見つかった場合、または7が含まれている場合、BSD 3の方法で動作します(拡張を有効にするため、認識します)。/5bin
/xpg
/bin
/usr/bin
/ucb
/bsd
$_AST_FEATURES
UNIVERSE = ucb
-e
-n
デフォルトはシステム依存、Debian上のBSDです(builtin getconf; getconf UNIVERSE
ksh93の最近のバージョンの出力を参照):
$ ksh93 -c 'echo -n' # default -> BSD (on Debian)
$ PATH=/foo/xpgbar:$PATH ksh93 -c 'echo -n' # /xpg before /bin or /usr/bin -> XPG
-n
$ PATH=/5binary:$PATH ksh93 -c 'echo -n' # /5bin before /bin or /usr/bin -> XPG
-n
$ PATH=/5binary:$PATH _AST_FEATURES='UNIVERSE = ucb' ksh93 -c 'echo -n' # -> BSD
$ PATH=/ucb:/foo/xpgbar:$PATH ksh93 -c 'echo -n' # /ucb first -> BSD
$ PATH=/bin:/foo/xpgbar:$PATH ksh93 -c 'echo -n' # /bin before /xpg -> default -> BSD
3. echo -eのBSD?
-e
オプションの処理に関するBSDへの参照は、ここでは少し誤解を招く可能性があります。これらの異なる互換性のないecho
動作のほとんどは、AT&Tですべて導入されました。
\n
、\0ooo
、\c
プログラマのワークベンチ(UnixのV6に基づいて)UNIX、および残りの(で\b
、\r
UnixのシステムIIIで...)のRef。
-n
Unix V7で(デニスリッチーRefによる)
-e
Unix V8(デニスリッチー参照)
-E
それ自体はおそらく最初に由来したものですbash
(バージョン1.13.5の CWRU / CWRU.chlog では、1992-10-18にBrian Foxが追加し、echo
10日後にリリースされたsh-utils-1.8 でGNUがそれをコピーすることを言及しています)
一方でecho
の組み込みsh
やBSD系を支えてきた-e
彼らは90年代初頭にそれのためにAlmquistシェルを使用して開始した日から、スタンドアロンのecho
この日にユーティリティが(そこをサポートしていません。FreeBSDはecho
、まだサポートされていない-e
、それはサポートしていても、-n
同じようUnix V7(そして\c
最後の引数の最後のみ)。
取り扱い-e
に追加されたksh93
のecho
BSDの中で時に宇宙と2006年にリリースされksh93rバージョンでコンパイル時に無効にすることができます。
4. 8.31でのGNUエコーの動作変更
coreutils 8.31(およびこのcommit)以降、GNU echo
はPOSIXLY_CORRECTが環境にある場合、デフォルトでエスケープシーケンスを展開し、bash -o posix -O xpg_echo
のecho
組み込みの動作に一致するようになりました(バグレポートを参照)。
5. macOS echo
macOSのほとんどのバージョンは、OpenGroupからUNIX認定を受けています。
彼らのsh
組み込みはecho
、それはだとして準拠しbash
て構築された(非常に古いバージョン)xpg_echo
はデフォルトで有効になっていますが、彼らのスタンドアロンecho
のユーティリティではありません。env echo -n
何も出力しない代わりに-n<newline>
、env echo '\n'
出力\n<newline>
の代わりに<newline><newline>
。
これ/bin/echo
は、最初の引数が-n
(1995年以降)最後の引数がで終わる場合に改行出力を抑制する\c
が、UNIXで必要な他のバックスラッシュシーケンスをサポートしないFreeBSDのものです\\
。
6. echo
任意のデータを逐語的に出力できる実装
厳密には、あなたもFreeBSDの/ MacOSのことを数えることができる話す/bin/echo
(ない自分の殻の上のecho
組み込みが)どこzsh
のecho -E - "$var"
かyash
のはECHO_STYLE=raw echo "$var"
(printf '%s\n' "$var"
)に記述できます。
/bin/echo "$var
\c"
サポートする実装-E
および-n
(またはに設定することができますが)も行うことができます。
echo -nE "$var
"
そしてzsh
のecho -nE - "$var"
(printf %s "$var"
)を書くことができます
/bin/echo "$var\c"
7. _AST_FEATURES
およびASTUNIVERSE
_AST_FEATURES
直接操作されることを意味しない、コマンド実行間でASTの構成設定を伝播するために使用されます。設定は、(ドキュメント化されていない)astgetconf()
APIを介して行われることを意図しています。内部ksh93
では、getconf
ビルトイン(を使用して、builtin getconf
またはを使用して有効化command /opt/ast/bin/getconf
)は、astgetconf()
たとえばbuiltin getconf; getconf UNIVERSE = att
、UNIVERSE
設定をatt
(echo
特にSysVの動作をさせる)に変更します。そうすると、$_AST_FEATURES
環境変数にが含まれていることに気付くでしょうUNIVERSE = att
。
echo -e
?