これまでcat
報酬は役に立たないよく知られていて言及されている役に立たない使用echo
(この質問には関係ありません)。 「Bashで役に立たない使用上」があるべきかどうか疑問に思いますecho
。いくつかの非常に非科学的な測定によると、パイプはheredocsとherestringsよりはるかに遅いようです。
継承文書:
for reps in 1 2 3 do time for i in {1..1000} do cat <<'END' test string END done > /dev/null done real 0m1.786s user 0m0.212s sys 0m0.332s real 0m1.817s user 0m0.232s sys 0m0.332s real 0m1.846s user 0m0.256s sys 0m0.320s
ハースト
for reps in 1 2 3 do time for i in {1..1000} do cat <<< 'test string' done > /dev/null done real 0m1.932s user 0m0.280s sys 0m0.288s real 0m1.956s user 0m0.248s sys 0m0.348s real 0m1.968s user 0m0.268s sys 0m0.324s
リダイレクト
for reps in 1 2 3 do time for i in {1..1000} do echo 'test string' | cat done > /dev/null done real 0m3.562s user 0m0.416s sys 0m0.548s real 0m3.924s user 0m0.384s sys 0m0.604s real 0m3.343s user 0m0.400s sys 0m0.552s
一般に、heredocsとHerestringsの速度はほぼ同じです(これはいくつかのテストのうちの1つのデータセットにすぎません)。一方、リダイレクトは常に50%以上遅いです。私が何か間違って理解したのですか?それとも、これはBashから標準入力を読み取るコマンドの一般的な規則として使用できますか?
答え1
まず、パフォーマンスに焦点を当てます。私はDebianスクレープを実行しているx86_64プロセッサでわずかに異なるプログラムのベンチマークを実行しましたが、そうでなければほとんどアイドル状態でした。
herestring.bash
、herestringを使用して入力行を渡します。
#! /bin/bash
i=0
while [ $i -lt $1 ]; do
tr a-z A-Z <<<'hello world'
i=$((i+1))
done >/dev/null
heredoc.bash
、heredocを使用して入力行を渡します。
#! /bin/bash
i=0
while [ $i -lt $1 ]; do
tr a-z A-Z <<'EOF'
hello world
EOF
i=$((i+1))
done >/dev/null
echo.bash
、echo
入力ラインを渡すには、パイプを使用します。
#! /bin/bash
i=0
while [ $i -lt $1 ]; do
echo 'hello world' | tr a-z A-Z
i=$((i+1))
done >/dev/null
比較のために、ATT ksh93とダッシュの下でスクリプトの時間も測定しました(herestring.bash
ダッシュにはこの文字列がないため除く)。
中央値トリプルは次のとおりです。
$ time bash ./herestring.bash 10000
./herestring.bash 10000 0.32s user 0.79s system 15% cpu 7.088 total
$ time ksh ./herestring.bash 10000
ksh ./herestring.bash 10000 0.54s user 0.41s system 17% cpu 5.277 total
$ time bash ./heredoc.bash 10000
./heredoc.bash 10000 0.35s user 0.75s system 17% cpu 6.406 total
$ time ksh ./heredoc.bash 10000
ksh ./heredoc.sh 10000 0.54s user 0.44s system 19% cpu 4.925 total
$ time sh ./heredoc.bash 10000
./heredoc.sh 10000 0.08s user 0.58s system 12% cpu 5.313 total
$ time bash ./echo.bash 10000
./echo.bash 10000 0.36s user 1.40s system 20% cpu 8.641 total
$ time ksh ./echo.bash 10000
ksh ./echo.sh 10000 0.47s user 1.51s system 28% cpu 6.918 total
$ time sh ./echo.sh 10000
./echo.sh 10000 0.07s user 1.00s system 16% cpu 6.463 total
結論として:
- HeredocはHerestringよりも高速です。
echo
パイプラインは著しく高速になりましたが、それほど速くはありません。 (これはおもちゃプログラムであることを覚えておいてください。実際のプログラムでは、ほとんどの処理時間がtr
ここにある呼び出しに含まれています。)- 速度が必要な場合は、bashを捨てて代わりにdashまたはより良いkshを呼び出してください。 Bashのパフォーマンスは相対的な遅い速度を補完しませんが、kshはパフォーマンスと速度の両方を備えています。
パフォーマンスに加えて、明確さと移植性があります。<<<
ksh93/bash/zsh 拡張ですが、よくecho … |
知られていません<<
。 ksh88/pdksh または POSIX sh では機能しません。
より明確であると言える唯一の場所は<<<
区切り記号の内側です。
foo=$(tr a-z A-Z <<<'hello world')
比較済み
foo=$(tr a-z A-Z <<'EOF'
hello world
EOF
)
(ほとんどのシェルはそれを含む行の末尾にある角括弧を処理できません<<EOF
。)
答え2
ここで文書を使用するもう1つの理由(文書が十分でない場合)は、ストリームが消費されないとエコーが失敗する可能性があることです。 bashpipefail
オプションの使用を検討してください。
set -o pipefail
foo=yawn
echo $foo | /bin/true ; echo $? # returns 0
/bin/true
標準入力を使用しませんが、echo yawn
まだ完了です。しかし、echoに大量のデータを印刷するように要求すると、true
次のようになるまで完了しません。
foo=$(cat /etc/passwd)
# foo now has a fair amount of data
echo $foo | /bin/true ; echo $? # returns 0 sometimes 141
echo $foo$foo$foo$foo | /bin/true ; echo $? # returns mostly 141
141はSIGPIPE(128 + 13)です(bashがbash(1)に従ってこれを行うため、128が追加されました:
コマンドが致命的な信号Nで終了すると、bashは終了状態として128 + Nの値を使用します。
Heredocsにはこの問題はありません。
/bin/true <<< $foo$foo$foo$foo ; echo $? # returns 0 always
答え3
echoを使用する理由の1つは、heredocsとherestringsの末尾に追加された改行文字をある程度制御できることです。
3文字foo
の長さは3です。
$ echo -n foo | wc -c
3
ただし、ここでは3つの文字列が4つの文字です。
$ wc -c <<< foo
4
また、3桁の区切り記号:
$ wc -c << EOF
foo
EOF
4
4番目の文字は改行文字です0x0a
。
どういうわけかこれは、bashがサブシェルから出力を取得したときにこれらの改行を削除する方法に魔法のようです。
foo
これは4つの文字(および)を返すコマンドです\n
。 '\ n'はechoによって追加され、オプションを指定しない限り常に改行文字を追加します-n
。
$ echo foo
foo
$ echo foo | wc -c
4
ただし、これを変数に割り当てると、echoによって追加された末尾の改行は削除されます。
$ foo=$(echo foo)
$ echo "$foo" # here, echo adds a newline too.
foo
したがって、ファイルと変数を混合して計算に使用する場合(改行を追加するため、heredocsやherestringsを使用することはできません)。
foo=abc
echo -n 'abc' > something.txt
if [ $(wc -c <<< "$foo") -eq $(wc -c < something.txt) ] ; then
echo "yeah, they're the same!"
else
echo "foo and bar have different lengths (except, maybe not)"
fi
if文を読むように変更した場合
if [ $(echo -n "$foo" | wc -c) -eq $(wc -c < something.txt) ] ; then
その後、テストに合格します。