Echo:

Echo:

printfそれよりも良いと聞いたがecho。私の経験では、RHEL 5.8のプログラムにいくつかのテキストを入力できなかったため、使用しなければならなかったprintfケースが1つしか覚えていません。しかし、明らかに異なる違いもあります。違いが何であるか、特定の状況に応じて異なる違いが使用されているかどうかを尋ねたいです。echoprintf

答え1

デフォルトでは、これは移植性(および安定性)の問題です。

最初はechoどのオプションも許可されず、何も拡張されませんでした。これがすることは空白文字で区切られ、改行文字で終わる出力引数だけです。

echo "\n\t"今、何人かの人々は、改行やタブを出力したり、オプションで末尾の改行を出力したりしないようなことをしたいと思うかもしれません。

それから彼らはもっと懸命に考えましたが、その機能をシェルに追加するのではなく(実際にはタブを意味するperl二重引用符の中の配置のように)。\techo

David Kornはこのエラーを認識し、新しい形式のシェル引用を導入しました。後で and によってコピーされ$'...'たが、その時は遅すぎた。bashzsh

標準UNIXは、2文字の合計を含む引数をecho受け取ると、それを出力せずに代わりにタブ文字を出力します。引数を確認すると出力は停止します(したがって、末尾の改行も出力されません)。\t\c

-e他のシェル/Unixベンダー/バージョンでは異なるアプローチを選択しました。つまり、エスケープシーケンスを拡張するオプションと、末尾の-n改行を出力しないオプションを追加しました。一部には-Eエスケープシーケンスを無効にする機能があり、一部はそうではありませんが、一部はそうではなく、ある-n実装-eでサポートされているエスケープシーケンスのリストがecho他の実装でサポートされているものと必ずしも同じではありません。

スヴェン・マチェクは問題の程度を示す素晴らしいページ

オプションをサポートする実装では、通常、オプションの終わりを表示するためechoのサポートはありません(Bourneに似ていない一部のシェルやおもちゃボックス(Android用のスタンドアロンユーティリティ))には、これを行う機能が組み込まれていますが、zshはサポートします this), 例えば多くのシェル では出力するのが難しいです。--echoechoecho-"-n"echo

bash1、ksh93²、yash(変数)などの一部のシェルでは、動作はシェルがコンパイルされた$ECHO_STYLE方法や環境によって異なります(環境でバージョン4を使用している場合はGNUechoの動作も変更され、一部はpdkshオプションによって呼び出されるかどうか)。 。したがって、同じバージョンの2つが同じように動作することを保証することはできません。$POSIXLY_CORRECTzshbsd_echoposixshbash echobash

POSIXは次のように言います。最初の引数にバックスラッシュが含まれる場合、-n動作は指定されません。bashたとえば、出力がPOSIXの要件に従わecho -eないため、echoはPOSIXではありません。-e<newline>UNIX仕様は、より厳密に出力を停止するエスケープシーケンスを-n含む、一部のエスケープシーケンスの拡張を禁止および要求します。\c

多くの実装が規制に準拠していないことを考慮すると、これらの仕様は実際には問題を解決しません。もいくつかあります認証済みmacOS 5などのシステムは互換性がありません。

現在の現実を正確に反映するため、POSIXは実際にこう言わなければなりません。:最初の引数が^-([eEn]*|-|-help|-version)$拡張正規表現と一致する場合、または引数にバックスラッシュ(またはαBIG5文字セットを使用するロケールなどのバックスラッシュ文字エンコーディングを含む文字エンコーディング)が含まれている場合、動作は指定されません。

全体的にバックスラッシュ文字が含まれていないで始まらないことをecho "$var"確認しないと、何が出力されるのかわかりません。 POSIX仕様は、実際にはこの場合は逆のアプローチを使用する必要があることを伝えます。$var-printf

これは、制御されていないデータを表示するために使用できないことを意味しますecho。つまり、スクリプトを作成していて外部入力(ユーザーからパラメータとして、またはファイルシステムのファイル名...)を受け取る場合をecho使用して表示することはできません。

いいね:

echo >&2 Invalid file.

これはない:

echo >&2 "Invalid file: $file"

(ただし、オプションが何らかの方法で有効になっていない場合(コンパイル時や環境を介して)など、echo一部の(UNIX準拠ではない)実装では正常に機能できます。bashxpg_echo

file=$(echo "$var" | tr ' ' _)ほとんどの実装では良くありません(例外はyashwith ECHO_STYLE=rawyash'の変数は任意のバイトシーケンスを保持できないため、任意のファイル名を保持できません)、zsh's echo -E - "$var"6です)。

printf一方、少なくとも基本的な使用に制限されている場合は、より安定していますecho

printf '%s\n' "$var"

$varコンテンツに改行文字がある場合、コンテンツに含まれる文字に関係なく出力されます。

printf '%s' "$var"

後行改行なしで出力されます。

printfこれで実装間にも違いがあります。 POSIXはコア機能を指定しますが、拡張機能はたくさんあります。たとえば、一部は%qパラメータを引用するためにaをサポートしていますが、これを行う方法はシェルによって異なり、一部は\uxxxxUnicode文字をサポートしています。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
     if [ "$#" -gt 0 ]; then
       printf ' %s' "$@"
     fi
  fi
  printf '\n'
}

ksh88、pdksh、および一部の派生物にはprintf組み込まれていません。そこで、print -r --(for echo)とprint -rn --(for echo -n/ \c)を使用して引数をスペースで区切って(後に改行が続く)、変更なしで印刷することを好むことができます-n(でも機能しますzsh)。


ノート

bash1. 行動を変える方法echo

実行時に動作を制御できる2つ(関数またはエイリアスで上書きまたは追加)がありますbash。まさにオプションとposixモードかどうか。環境で呼び出されるか、次のオプションを使用してモードを有効にできます。echoenable -n echoechoxpg_echo bashbashposixbashshPOSIXLY_CORRECTposix

ほとんどのシステムの基本動作:

$ bash -c 'echo -n "\0101"'
\0101% # the % here denotes the absence of newline character

xpg_echoUNIXが要求するようにシーケンスを拡張します。

$ BASHOPTS=xpg_echo bash -c 'echo "\0101"'
A

それでも-n次の-eことを尊重します-E

$ BASHOPTS=xpg_echo bash -c 'echo -n "\0101"'
A%

POSIXモードの使用xpg_echo:

$ 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

今回はbashPOSIXとUNIXの両方に準拠します。 POSIXモードではbash出力されないため、まだPOSIXと互換性がありません-e

$ env SHELLOPTS=posix bash -c 'echo -e'

$

--enable-xpg-echo-defaultxpg_echoとposixのデフォルト値は、スクリプトと--enable-strict-posix-defaultオプションを使用してコンパイル時に定義できますconfigure。これは通常最新バージョンのOS / Xです/bin/sh。実際にはそうではありません。 Solaris 11(オプションのパッケージ)に付属のOracleは、Solaris 10で構築されているようです(Solaris 10ではそうではありません)。/bin/bash/bin/bash--enable-xpg-echo-default

2. 行動をksh93変える方法echo

ksh93エスケープシーケンスが拡張され、オプションが認識されるかどうかは、およびecho/または環境変数の内容によって異なります。$PATH$_AST_FEATURES

$PATH含まれているコンポーネントに以前/5binまたはコンポーネントが含まれている場合、動作はSysV / UNIXモード(拡張シーケンス、許可されていないオプション)です。または、最初に検索するか、7が含まれている場合は、BSD 3モードで実行されます(拡張認識を有効にするため)。/xpg/bin/usr/bin/ucb/bsd$_AST_FEATURESUNIVERSE = ucb-e-n

builtin getconf; getconf UNIVERSEデフォルトはシステム、DebianのBSDによって異なります(最新バージョンの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?

ここでこのオプションを処理するためのBSDへの参照は少し誤解を招く可能性があります-e。これらの多様で互換性のない動作の大部分はechoAT&Tによって導入されました。

  • \n、、Programmer's Workbench UNIX(Unix V6ベース)、残り(\0ooo、... )はUnix System III\c\b\r参照番号
  • -nUnix V7(デニスリッチ)参照番号)
  • -eUnix V8(デニスリッチ)参照番号)
  • -Ebashそれ自体はもともと(CWRU / CWRU.chlog)から来た可能性があります。バージョン 1.13.5Brian Foxが1992年10月18日に追加し、GNUはecho10日後にリリースされたsh-utils-1.8に直接コピーしたと述べました。

BSDechoの組み込み機能は90年代初頭のAlmquistシェルをサポートしてきましたがsh、現在までスタンドアロンユーティリティはこれをサポートしていません(-eechoFreeBSDechoUnix V7のようにサポートしていますが、まだサポートされていません-e(最後の引数の終わりにのみ)。-n\c

BSDでは、ペア処理がs-eに追加されました。ksh93echo宇宙ksh93rの2006リリースでは、コンパイル時にこれを無効にすることができます。

4. GNU echo 8.31の動作変更

coreutils 8.31から開始(および今回提出してください)、echoGNUはデフォルトでエスケープシーケンスを拡張し、POSIXLY_CORRECTが環境に存在するときに組み込み関数の動作と一致するようになりますbash -o posix -O xpg_echoechoエラーレポート)。

5. アップルシステムecho

ほとんどのmacOSバージョンで利用可能OpenGroupからUNIX認証を取得

組み込みshプログラム(非常に古いバージョン)はデフォルトで有効になっているため互換性がありechoますが、スタンドアロンユーティリティはそうではありません。何も出力せずに代わりに出力します。bashxpg_echoechoenv echo -n-n<newline>env echo '\n'\n<newline><newline><newline>

これは、最初の引数がorで(1995年以降)、最後の引数がorで終わると改行出力を/bin/echo抑制するFreeBSDの機能ですが、UNIXで要求される他のバックスラッシュシーケンスはサポートしていません。-n\c\\

6.echo任意のデータをそのまま出力できる実装

/bin/echo厳密に言えば、上記のFreeBSD / macOSも含めることができます(組み込みシェルではありechoません)。ここで、zshsecho -E - "$var"またはyashs ECHO_STYLE=raw echo "$var"printf '%s\n' "$var")は次のように書くことができます。

/bin/echo "$var
\c"

そしてzshecho -nE - "$var")はprintf %s "$var"次のように書くことができます。

/bin/echo "$var\c"

サポート-Eまたは構成できる-n実装は、次のこともできます。

echo -nE "$var
"

等しいprintf '%s\n' "$var"

7._AST_FEATURESおよびASTUNIVERSE

_AST_FEATURES直接操作することはできず、コマンド実行中にAST構成設定を伝播するために使用されます。設定は(文書化されていない)APIを介して行われますastgetconf()。内部的には、ksh93組み込みgetconf関数(builtin getconf呼び出すかアクティブにするcommand /opt/ast/bin/getconf)はインターフェースです。astgetconf()

たとえば、設定を(SysVモードで実行するように)にbuiltin getconf; getconf UNIVERSE = att変更する必要があります。これにより、環境変数に 。UNIVERSEattecho$_AST_FEATURESUNIVERSE = att

答え2

printf書式設定オプションも使用できます。echo変数や(単純な)行の値を印刷するのに便利ですが、それ以上ではありません。printfデフォルトでは、Cバージョンでできることができます。

使用法と機能の例:

Echo:

echo "*** Backup shell script ***"
echo
echo "Runtime: $(date) @ $(hostname)"
echo

printf:

vech="bike"
printf "%s\n" "$vech"

源泉:

答え3

そうしたい場合は、1つの「利点」は、echo特定のエスケープシーケンスを解釈するように指示する必要がないことです。たとえば、\n解釈すると思います-e

printf "some\nmulti-lined\ntext\n"

(注:最後の項目は\n必須であり、オプションをecho提供しない限り暗示されます)-n

比較的

echo -e "some\nmulti-lined\ntext"

\n最後の内容を参照してくださいprintf。結局、味の問題です。必要あなたは何を使いますか:echoまたはprintf

答え4

欠点の1つは、組み込みprintfシェルがechoはるかに高速であるため、パフォーマンスです。これは、新しいコマンドの各インスタンスがかなりのWindowsオーバーヘッドを引き起こすCygwinにとって特に重要です。重いエコーを使用するプログラムを/bin/echoシェルのエコーに変えると、パフォーマンスがほぼ倍増しました。これは移植性とパフォーマンスのバランスです。常に有効にすることなく忘れてくださいprintf

関連情報