基本的に、これは移植性(および信頼性)の問題です。
最初は、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に準拠していない)実装では問題なく動作します)。bashxpg_echo
file=$(echo "$var" | tr ' ' _)ほとんどの実装でOKではない(例外があることyashでECHO_STYLE=raw(警告付きyashの変数は任意のバイトシーケンスそうではない、任意のファイル名)と保持することはできませんzshs 'の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ます:オプションとbashposixモードであるかどうか。が呼び出された場合、または環境内にある場合、またはオプションをposix使用してモードを有効にできます。bashshPOSIXLY_CORRECTposix
ほとんどのシステムのデフォルトの動作:
$ 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_FEATURESUNIVERSE = ucb-e-n
デフォルトはシステム依存、Debian上のBSDです(builtin getconf; getconf UNIVERSEksh93の最近のバージョンの出力を参照):
$ 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、- \rUnixのシステムIIIで...)のRef。
- -nUnix V7で(デニスリッチーRefによる)
- -eUnix V8(デニスリッチー参照)
- -Eそれ自体はおそらく最初に由来したものです- bash(バージョン1.13.5の CWRU / CWRU.chlog では、1992-10-18にBrian Foxが追加し、- echo10日後にリリースされたsh-utils-1.8 でGNUがそれをコピーすることを言及しています)
一方でechoの組み込みshやBSD系を支えてきた-e彼らは90年代初頭にそれのためにAlmquistシェルを使用して開始した日から、スタンドアロンのechoこの日にユーティリティが(そこをサポートしていません。FreeBSDはecho、まだサポートされていない-e、それはサポートしていても、-n同じようUnix V7(そして\c最後の引数の最後のみ)。
取り扱い-eに追加されたksh93のechoBSDの中で時に宇宙と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?