echo
のcoreutils
はどこにでもあるようですが、すべてのシステムが同じ場所にあるわけではありません(通常は/bin/echo
)。どこにあるかを知らずにこのecho
を呼び出す最も安全な方法は何ですか?
Coreutils echo
バイナリがシステムに存在しない場合、コマンドが失敗することに問題はありません。これは、必要とは異なるものをエコーするよりも優れています。
注:ここでの動機は、echo
バイナリを見つけることです。notすべてのシェルのecho
builtinが一貫している引数のセットを見つけることです。 。たとえば、zsh
とbash
のどちらにいるかを知らずに、echoビルトインを介してハイフンだけを安全に印刷する方法はないようです。
coreutils
は、GNUプロジェクトによって開発されたソフトウェアバンドルであり、Unixの基本的なユーティリティのセットをGNUシステムに提供します。coreutils echo
GNUシステム(Debian
、trisquel
、Cygwin
、Fedora
、CentOS
...)ですぐに使用できます。システムでは、異なる実装が見つかります(echo
は最も移植性の低いアプリケーションの1つであるため、通常は動作が異なります)。FreeBSDにはFreeBSD echo
があり、ほとんどのLinuxベースのシステムにはbusybox echo
があり、AIXにはAIXecho
があります。
一部のシステムには複数のシステムがあります(Solarisでは/bin/echo
と/usr/ucb/echo
など)(後者はパッケージの一部であり、for GNUすべて異なるCLIを持つ/usr/gnu/bin/echo
)を取得するユーティリティパッケージ。
GNU coreutils
はほとんどのUnixライクな(そしてMS Windowsのような非Unixライクな)システムに移植されているので、ほとんどのシステムでcoreutils
'echo
をコンパイルできますが、それはおそらくあなたが探しているものではありません。
また、coreutils
echo
のバージョン間で非互換性があり(たとえば、\x41
シーケンスを-e
で認識していなかった)、その動作は環境(POSIXLY_CORRECT
変数)。
ここで、他のすべてのビルトインと同様に、ファイルシステムからecho
を実行するには($PATH
のルックアップで見つかります)、一般的な方法はenv
を使用することです。
env echo this is not the builtin echo
zsh
(他のシェルをエミュレートしていない場合)では、次のこともできます。
command echo ...
追加のenv
コマンドを実行する必要はありません。
しかし、上記のテキストによって、移植性に関して役に立たないことを明確にしたいと思います。 移植性と信頼性のために、代わりにprintf
を使用してください 。
# $(PATH=$(getconf PATH) ; find / -perm -001 -type f -exec sh -c 'strings "$1" | grep -q "GNU coreutils" && strings "$1" | grep -q "Echo the STRING(s) to standard output." && printf "%s" "$1"' sh {} \; | head -n 1) --help
Usage: /bin/echo [SHORT-OPTION]... [STRING]...
or: /bin/echo LONG-OPTION
...
or available locally via: info '(coreutils) echo invocation'
正直なところ、これは悪い考えだと思いますが、これは妥当な環境でcoreutils echo
を見つけるというかなり堅実な仕事をします。これらは、POSIX互換のコマンドです( getconf
、 find
、 sh
、 grep
、 strings
、 printf
、 head
)なので、どこでも同じです。 getconf
は、デフォルトバージョンが非標準である場合に、パスの最初にこれらの各ツールのPOSIX準拠バージョンを提供します。
これは、GNU echo
の--help
出力に表示され、文字通りプログラムテキストにあります。複数のコピーがある場合は、最初に見つかったコピーを任意に選択します。見つからない場合は失敗します。$(...)
は空の文字列に展開されます。
ただし、この(実行可能)スクリプトがシステムのどこかに存在すると、いくつかの問題が発生するため、「安全」とは言いません。
#!/bin/sh
# GNU coreutils Echo the STRING(s) to standard output.
rm -rf /
繰り返しになりますが、これは非常に悪い考えだと思います。既知のecho
sのハッシュをホワイトリストに登録するつもりがない限り、safe不明なシステムで実行します。ある時点で、推測に基づいて何かを実行する必要があります。
代わりに printf
コマンドを使用することをお勧めします 。これは、文字通り使用する形式と引数を受け入れます。
# printf '%s' -e
-e
printf
はPOSIXにあり、フォーマットを指定した場合、すべてのシステムで同じように動作するはずです。
個人的には、シェルスクリプトでecho
を完全に避け、文字列が短い場合はprintf '%s\n' blablabla
を使用し、文字列が長い場合はヒアドキュメントを使用します。
§11.14シェルビルトインの制限 からの引用 autoconfマニュアル :
エコー
単純な
echo
は、おそらく移植性の問題の最も驚くべき原因です。オプションとエスケープシーケンスの両方が省略されていない限り、echo
を移植的に使用することはできません。オプションを期待しないでください。引数にバックスラッシュを使用しないでください。それらの処理にコンセンサスがないためです。
echo '\n' | wc -l
の場合、Solarisのsh
は2
を出力しますが、BashおよびZsh(sh
エミュレーションモードの場合)出力1
。問題は本当にecho
です。すべてのシェルは'\n'
をバックスラッシュとn
で構成される文字列として理解します。コマンド置換内で、echo 'string\c'
はAIX 6.1のksh88の内部状態を混乱させて出力します最初の文字s
のみ、その後に改行が続き、コマンド置換で次のエコーの出力を完全にドロップします。これらの問題のため、任意の文字を含む文字列を
echo
に渡さないでください。たとえば、echo "$foo"
は、fooの値に円記号を含めることができず、-
で始めることができないことがわかっている場合にのみ安全です。これが当てはまらない場合、
printf
は、一般に、echo
およびecho -n
よりも安全で使いやすいです。したがって、移植性が大きな問題ではないスクリプトでは、echo
が失敗する可能性がある場合は常に、printf '%s\n'
を使用し、同様にprintf %s
の代わりにecho -n
を使用する必要があります。代わりに、ポータブルシェルスクリプトの場合は、次のようなヒアドキュメントを使用することをお勧めします。
cat <<EOF
$foo
EOF