私はMakefile(該当する場合はUbuntu 20.04で)を作成していますecho
。
test.txt:
@echo -e 'hello\nworld'
@echo -e 'hello\nworld' > test.txt
を実行すると、make
stdoutでもtest.txtと同じ内容が表示されると予想されますが、実際にはそうではありません。標準出力からこれを取得します。
hello
world
しかし、これはtest.txtにあります。
-e hello
world
一方-e
、Makefileから次の2行を削除すると、標準出力が表示されます。
hello\nworld
test.txtから:
hello
world
これにより、リダイレクトが検出され、他の動作が見えるかどうか疑問に思いますecho
。ただし、シェルで手動で実行する場合はそうではありません/bin/echo -e 'hello\nworld' > test.txt
(通常、予想どおり別々の行に合計が生成されますhello
)。world
私は行を追加して、Makefileが組み込みシェルではなく/bin/echoを使用していることを確認しました@echo --version
。
ここで何が起こっているのでしょうか?
答え1
echo
そこから出力するにはUNIX互換の実装が必要です-e<space>hello<newline>world<newline>
。
要件を満たしていない方は資格がありません。多くの場合、そうではありません。つまり、ポータブルを使用することはほとんど不可能ですecho
。printf
使用すべき。の一部(ほとんど)バージョンでは、オプションがすべて有効になっている場合にのみ互換性bash
があります。これはおそらく予想される動作です。echo
posix
xpg_echo
echo
echo
GNUに付属のスタンドアロンユーティリティも同様です。これは、coreutils
環境でsetを使用して呼び出す場合$POSIXLY_CORRECT
にのみ互換性があり、まったく新しいバージョンです。
make
通常、sh
各タスクラインのコマンドラインを解釈するために実行します。
make
しかし、最適化として、GNU実装は、コードが十分に単純であり、それを解釈するためにシェルを呼び出す必要がないと思う場合は、コマンドを直接実行できます。
これはecho --version
与えられた理由を説明し/bin/echo
ますが、echo ... > file
リダイレクトを実行するにはシェルが必要です。
strace -fe execve make
以下を使用して実行された内容を確認できます(make
Linuxでない場合はシステムでtruss
/ ...そのエントリを使用)。tusc
ここでは/bin/echo
互換性がありませんが、sh
組み込まれてecho
います。
printf
echo
拡張スタイルのエスケープシーケンスが必要な場合は、ここで使用してください。
printf '%b\n' 'hello\nworld'
その中に滞在パラメータ、Cスタイルエスケープシーケンスの理解(printf
(echo)および(C)8進数シーケンスのエコスタイルエスケープシーケンスと区別されます)\0xxx
\xxx
printf 'hello\nworld\n'
ここでも次のことができます。
printf '%s\n' hello world
これは、複数のパラメータを別々の行に出力する一般的で移植可能な方法です。
もう一つの方法は、以下を追加することです。
SHELL = bash
コマンドラインを解釈する代わりに、Makefile
formake
呼び出しbash
(インストールされていると仮定)を使用します。またはに電話してください。$PATH
sh
make
make <target> SHELL=bash
bash
ますます多くのシステムがデフォルトでインストールされているため、これは必ずしも移植性が高くなるわけではありませんが、一部のシステム(Solarisなど)は基本的に標準的な方法で実行されるようにbash
構築されています。echo
SHELL
他に設定すると、/bin/sh
上記のGNU最適化を無効にする副作用があるため、またはを使用すると、bashへの依存関係を追加せずに呼び出し間で一貫した動作を得ることができます。make
make <target> SHELL=sh
make <target> SHELL=/bin//sh