printf
それよりも良いと聞いたがecho
。私の経験では、RHEL 5.8のプログラムにいくつかのテキストを入力できなかったため、使用しなければならなかったprintf
ケースが1つしか覚えていません。しかし、明らかに異なる違いもあります。違いが何であるか、特定の状況に応じて異なる違いが使用されているかどうかを尋ねたいです。echo
printf
答え1
デフォルトでは、これは移植性(および安定性)の問題です。
最初はecho
どのオプションも許可されず、何も拡張されませんでした。これがすることは空白文字で区切られ、改行文字で終わる出力引数だけです。
echo "\n\t"
今、何人かの人々は、改行やタブを出力したり、オプションで末尾の改行を出力したりしないようなことをしたいと思うかもしれません。
それから彼らはもっと懸命に考えましたが、その機能をシェルに追加するのではなく(実際にはタブを意味するperl
二重引用符の中の配置のように)。\t
echo
David Kornはこのエラーを認識し、新しい形式のシェル引用を導入しました。後で and によってコピーされ$'...'
たが、その時は遅すぎた。bash
zsh
標準UNIXは、2文字の合計を含む引数をecho
受け取ると、それを出力せずに代わりにタブ文字を出力します。引数を確認すると出力は停止します(したがって、末尾の改行も出力されません)。\
t
\c
-e
他のシェル/Unixベンダー/バージョンでは異なるアプローチを選択しました。つまり、エスケープシーケンスを拡張するオプションと、末尾の-n
改行を出力しないオプションを追加しました。一部には-E
エスケープシーケンスを無効にする機能があり、一部はそうではありませんが、一部はそうではなく、ある-n
実装-e
でサポートされているエスケープシーケンスのリストがecho
他の実装でサポートされているものと必ずしも同じではありません。
スヴェン・マチェクは問題の程度を示す素晴らしいページ。
オプションをサポートする実装では、通常、オプションの終わりを表示するためecho
のサポートはありません(Bourneに似ていない一部のシェルやおもちゃボックス(Android用のスタンドアロンユーティリティ))には、これを行う機能が組み込まれていますが、zshはサポートします this), 例えば多くのシェル では出力するのが難しいです。--
echo
echo
echo
-
"-n"
echo
bash
1、ksh93
²、yash
(変数)などの一部のシェルでは、動作はシェルがコンパイルされた$ECHO_STYLE
方法や環境によって異なります(環境でバージョン4を使用している場合はGNUecho
の動作も変更され、一部はpdkshオプションによって呼び出されるかどうか)。 。したがって、同じバージョンの2つが同じように動作することを保証することはできません。$POSIXLY_CORRECT
zsh
bsd_echo
posix
sh
bash
echo
bash
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準拠ではない)実装では正常に機能できます。bash
xpg_echo
file=$(echo "$var" | tr ' ' _)
ほとんどの実装では良くありません(例外はyash
with 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
Unicode文字をサポートしています。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
)。
ノート
bash
1. 行動を変える方法echo
。
実行時に動作を制御できる2つ(関数またはエイリアスで上書きまたは追加)がありますbash
。まさにオプションとposixモードかどうか。環境で呼び出されるか、次のオプションを使用してモードを有効にできます。echo
enable -n echo
echo
xpg_echo
bash
bash
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%
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
今回はbash
POSIXとUNIXの両方に準拠します。 POSIXモードではbash
出力されないため、まだPOSIXと互換性がありません-e
。
$ env SHELLOPTS=posix bash -c 'echo -e'
$
--enable-xpg-echo-default
xpg_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_FEATURES
UNIVERSE = 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
。これらの多様で互換性のない動作の大部分はecho
AT&Tによって導入されました。
\n
、、Programmer's Workbench UNIX(Unix V6ベース)、残り(\0ooo
、... )はUnix System III\c
\b
\r
参照番号。-n
Unix V7(デニスリッチ)参照番号)-e
Unix V8(デニスリッチ)参照番号)-E
bash
それ自体はもともと(CWRU / CWRU.chlog)から来た可能性があります。バージョン 1.13.5Brian Foxが1992年10月18日に追加し、GNUはecho
10日後にリリースされたsh-utils-1.8に直接コピーしたと述べました。
BSDecho
の組み込み機能は90年代初頭のAlmquistシェルをサポートしてきましたがsh
、現在までスタンドアロンユーティリティはこれをサポートしていません(-e
echo
FreeBSDecho
Unix V7のようにサポートしていますが、まだサポートされていません-e
(最後の引数の終わりにのみ)。-n
\c
BSDでは、ペア処理がs-e
に追加されました。ksh93
echo
宇宙ksh93rの2006リリースでは、コンパイル時にこれを無効にすることができます。
4. GNU echo 8.31の動作変更
coreutils 8.31から開始(および今回提出してください)、echo
GNUはデフォルトでエスケープシーケンスを拡張し、POSIXLY_CORRECTが環境に存在するときに組み込み関数の動作と一致するようになりますbash -o posix -O xpg_echo
(echo
エラーレポート)。
5. アップルシステムecho
ほとんどのmacOSバージョンで利用可能OpenGroupからUNIX認証を取得。
組み込みsh
プログラム(非常に古いバージョン)はデフォルトで有効になっているため互換性がありecho
ますが、スタンドアロンユーティリティはそうではありません。何も出力せずに代わりに出力します。bash
xpg_echo
echo
env 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
ません)。ここで、zsh
secho -E - "$var"
またはyash
s ECHO_STYLE=raw echo "$var"
(printf '%s\n' "$var"
)は次のように書くことができます。
/bin/echo "$var
\c"
そしてzsh
(echo -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
変更する必要があります。これにより、環境変数に 。UNIVERSE
att
echo
$_AST_FEATURES
UNIVERSE = 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
答え4
欠点の1つは、組み込みprintf
シェルがecho
はるかに高速であるため、パフォーマンスです。これは、新しいコマンドの各インスタンスがかなりのWindowsオーバーヘッドを引き起こすCygwinにとって特に重要です。重いエコーを使用するプログラムを/bin/echo
シェルのエコーに変えると、パフォーマンスがほぼ倍増しました。これは移植性とパフォーマンスのバランスです。常に有効にすることなく忘れてくださいprintf
。