私はいつもbashの代わりにダッシュを使用する唯一の利点は、ダッシュが小さいので、多くのダッシュインスタンスが起動時により早く開始されることだと思いました。
しかし、調査をしてみると、一部の人々はより速く実行されることを望んですべてのスクリプトをダッシュに移行するという事実を発見しました。記事でもこの内容を発見しました。ダッシュUbuntu Wikipediaから:
基本シェルを切り替える主な理由は効率。 bashはインタラクティブな使用に適した優れた機能を備えたシェルであり、実際にはまだデフォルトのログインシェルです。しかし、規模はかなり大きくてスロースタートそして運営するダッシュと比較。
最近私は私のシステムの多くの仕事にbashスクリプトをたくさん使っています。私の問題は、年中無休の24時間連続で実行する特定のスクリプトがあり、このスクリプトが一緒にマイコンピュータをダウンさせる約200の添え字を生成することです。最大10℃以上加熱されます。通常の使用時より
bashismがたくさん含まれているかなり大きなスクリプトなので、これをPOSIXや他のシェルに移植するのにかなりの時間がかかります(POSIXは個人的な用途にとってそれほど重要ではありません)。しかし、一部を減らすことができれば価値があるでしょう。 CPU使用量です。たとえば、sed
単純なbashismを呼び出すために外部バイナリを呼び出すなど、考慮する必要がある他のものがあることを知っています。${foo/bar}
grep
=~
長い話を短くbashの起動速度は本当に遅いです。そして運営するダッシュと比べると?より強力なUnixシェルはありますか?効率的なバッシュより?
答え1
シェル順序:
おそらくシェルのパフォーマンスをベンチマークする便利な方法は、非常に小さくて簡単な評価を多数繰り返すことです。私は単にループを繰り返さないことが重要だと思います。入力する、シェルが読む必要があるからです<&0
。
私はこれがテストを補完すると思った@cuonglm 投稿しましたこれは、呼び出し時にシェルプロセスがどれだけ早くロードされるかを示すのではなく、呼び出し後の単一のシェルプロセスのパフォーマンスを示すためです。このように、我々は私たちの間のコインの両面を覆います。
簡単に実演できる機能は次のとおりです。
sh_bench() ( #don't copy+paste comments
o=-c sh=$(command -v "$1") ; shift #get shell $PATH; toss $1
[ -z "${sh##*busybox}" ] && o='ash -c' #cause its weird
set -- "$sh" $o "'$(cat <&3)'" -- "$@" #$@ = invoke $shell
time env - "$sh" $o "while echo; do echo; done|$*" #time (env - sh|sh) AC/DC
) 3<<-\SCRIPT
#Everything from here down is run by the different shells
i="${2:-1}" l="${1:-100}" d="${3:-
}"; set -- "\$((n=\$n\${n:++\$i}))\$d" #prep loop; prep eval
set -- $1$1$1$1$1$1$1$1$1$1 #yup
while read m #iterate on input
do [ $(($i*50+${n:=-$i})) -gt "$(($l-$i))" ] || #eval ok?
eval echo -n \""$1$1$1$1$1"\" #yay!
[ $((n=$i+$n)) -gt "$(($l-$i))" ] && #end game?
echo "$n" && exit #and EXIT
echo -n "$n$d" #damn - maybe next time
done #done
#END
SCRIPT #end heredoc
各改行を読むたびに変数を1回増やすか(可能であれば)、少しの最適化で各改行を読むたびに変数を50倍増やします。変数が増加するたびにに印刷されますstdout
。これは一種のseq
十字架のように動作しますnl
。
これが行うことを非常に明確にするために、上記の関数のset -x;
前に挿入した後にいくつかの切り捨てられた出力があります。time
time env - /usr/bin/busybox ash -c '
while echo; do echo; done |
/usr/bin/busybox ash -c '"'$(
cat <&3
)'"' -- 20 5 busybox'
したがって、各シェルはまず次のように呼び出されます。
env - $shell -c "while echo; do echo; done |..."
3<<\SCRIPT
...読み取り中に繰り返す必要がある入力を生成しますcat
。一方、|pipe
次のように自分自身を呼び出します。
"...| $shell -c '$(cat <<\SCRIPT)' -- $args"
だから初期の電話通話に加えてenv
(cat
実際には前の行から呼び出されたためです);呼び出された時点から終了するまで、他のプロセスは呼び出されません。少なくともそれが本当であることを願っています。
数字の前に...
移植性についていくつかのメモを取る必要があります。
posh
嫌い$((n=n+1))
で頑固$((n=$n+1))
mksh
printf
ほとんどの場合、組み込み機能はありません。初期テストでは、遅延が多く発生し、/usr/bin/printf
実行されるたびに呼び出されました。したがって、上記のような状況が発生しますecho -n
。おそらく私の記憶ではもっと多いかもしれません...
とにかく数字を見ると次のようになります。
for sh in dash busybox posh ksh mksh zsh bash
do sh_bench $sh 20 5 $sh 2>/dev/null
sh_bench $sh 500000 | wc -l
echo ; done
これにより、すべての作業を完了できます。
0dash5dash10dash15dash20
real 0m0.909s
user 0m0.897s
sys 0m0.070s
500001
0busybox5busybox10busybox15busybox20
real 0m1.809s
user 0m1.787s
sys 0m0.107s
500001
0posh5posh10posh15posh20
real 0m2.010s
user 0m2.060s
sys 0m0.067s
500001
0ksh5ksh10ksh15ksh20
real 0m2.019s
user 0m1.970s
sys 0m0.047s
500001
0mksh5mksh10mksh15mksh20
real 0m2.287s
user 0m2.340s
sys 0m0.073s
500001
0zsh5zsh10zsh15zsh20
real 0m2.648s
user 0m2.223s
sys 0m0.423s
500001
0bash5bash10bash15bash20
real 0m3.966s
user 0m3.907s
sys 0m0.213s
500001
誰=多分?
それでも、これはかなりランダムなテストですが、入力読み出し、算術評価、および変数拡張をテストします。包括的ではありませんが、おそらくそれに近いです。
編集者: Teresa e Junior:@mikeservと私は他の多くのテストを行いました(参照私たちのチャット詳細)結果を次のように要約できることを確認しました。
- 速度が必要な場合は必ず選択してくださいスプリント、これは他のシェルよりはるかに高速です。強く打つ。
- しかし、忙しい箱殻はおそらく良いと思います。スプリント、一般的に使用されるGNUユーティリティほど多くの機能はありませんが、それほど多くの作業を行うことができる、、などの独自の
grep
ユーザー空間ユーティリティが多いため、一部のテストではより速い場合があります。 。sed
sort
- 速度があなたのすべてではない場合ケシ(またはクッシュ 93)は、速度と機能性の間の最良の妥協点と見なすことができます。小さいものに比べて速度が速いムケシ、これよりも優れています。強く打つで、次のようないくつかのユニークな機能もあります。浮動小数点演算。
- しかし、強く打つ単純さ、安定性、機能性としてよく知られていますが、ほとんどのテストでは、すべてのシェルの中で最も遅く、速度も非常に多様でした。
答え2
ベンチマークテストをしましょう。
そしてbash
:
$ strace -cf bash -c 'for i in $(seq 1 1000); do bash -c ":"; done'
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
99.12 0.376044 188 2004 1002 wait4
0.74 0.002805 3 1002 clone
0.03 0.000130 0 4037 read
0.03 0.000119 0 15026 rt_sigprocmask
0.03 0.000096 0 15040 6017 stat
0.01 0.000055 0 8011 open
0.01 0.000024 0 5013 getegid
0.01 0.000021 0 16027 rt_sigaction
0.00 0.000017 0 9020 5008 access
0.00 0.000014 0 1001 1001 getpeername
0.00 0.000013 0 1001 getpgrp
0.00 0.000012 0 5013 geteuid
0.00 0.000011 0 15025 mmap
0.00 0.000011 0 1002 rt_sigreturn
0.00 0.000000 0 1 write
0.00 0.000000 0 8017 close
0.00 0.000000 0 7011 fstat
0.00 0.000000 0 8012 mprotect
0.00 0.000000 0 2004 munmap
0.00 0.000000 0 18049 brk
0.00 0.000000 0 1 pipe
0.00 0.000000 0 1 dup2
0.00 0.000000 0 1001 getpid
0.00 0.000000 0 1002 execve
0.00 0.000000 0 1001 uname
0.00 0.000000 0 1001 getrlimit
0.00 0.000000 0 5013 getuid
0.00 0.000000 0 5013 getgid
0.00 0.000000 0 1001 getppid
0.00 0.000000 0 1002 arch_prctl
0.00 0.000000 0 1001 time
------ ----------- ----------- --------- --------- ----------------
100.00 0.379372 158353 13028 total
そしてdash
:
$ strace -cf bash -c 'for i in $(seq 1 1000); do dash -c ":"; done'
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
73.88 0.008543 4 2004 1002 wait4
25.35 0.002932 3 1002 clone
0.62 0.000072 0 9026 rt_sigprocmask
0.10 0.000011 0 1002 rt_sigreturn
0.05 0.000006 0 15027 rt_sigaction
0.00 0.000000 0 1037 read
0.00 0.000000 0 1 write
0.00 0.000000 0 2011 open
0.00 0.000000 0 2017 close
0.00 0.000000 0 2040 17 stat
0.00 0.000000 0 2011 fstat
0.00 0.000000 0 8025 mmap
0.00 0.000000 0 3012 mprotect
0.00 0.000000 0 1004 munmap
0.00 0.000000 0 3049 brk
0.00 0.000000 0 3020 3008 access
0.00 0.000000 0 1 pipe
0.00 0.000000 0 1 dup2
0.00 0.000000 0 1001 getpid
0.00 0.000000 0 1 1 getpeername
0.00 0.000000 0 1002 execve
0.00 0.000000 0 1 uname
0.00 0.000000 0 1 getrlimit
0.00 0.000000 0 13 getuid
0.00 0.000000 0 13 getgid
0.00 0.000000 0 1013 geteuid
0.00 0.000000 0 13 getegid
0.00 0.000000 0 1001 getppid
0.00 0.000000 0 1 getpgrp
0.00 0.000000 0 1002 arch_prctl
0.00 0.000000 0 1 time
------ ----------- ----------- --------- --------- ----------------
100.00 0.011564 60353 4028 total
繰り返しごとに 1 つのシェルのみが始まり、ランダム演算子では何もしません。コロンを押して終了します。
結果は、起動時よりはるかに高速であることを示していますdash
。以下より小さく、少ない数の共有ライブラリに依存します。bash
dash
bash
$ du -s /bin/bash
956 /bin/bash
$ du -s /bin/dash
108 /bin/dash
$ ldd /bin/bash
linux-vdso.so.1 => (0x00007fffc7947000)
libtinfo.so.5 => /lib/x86_64-linux-gnu/libtinfo.so.5 (0x00007f5a8110d000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f5a80f09000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f5a80b7d000)
/lib64/ld-linux-x86-64.so.2 (0x00007f5a81352000)
$ ldd /bin/dash
linux-vdso.so.1 => (0x00007fff56e5a000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb24844c000)
/lib64/ld-linux-x86-64.so.2 (0x00007fb2487f3000)
起動時間と動作方法についてです。別のベンチマークをしましょう。
$ time dash -c 'for i in $(seq 1 1000000);do [ 1 = 1 ];done'
real 0m2.684s
user 0m2.728s
sys 0m0.100s
$ time bash -c 'for i in $(seq 1 1000000);do [ 1 = 1 ];done'
real 0m6.996s
user 0m6.820s
sys 0m0.376s
簡単なテスト後も1 = 1
まだdash
はるかに高速ですbash
。
答え3
以下は、認証されたUNIX(Mac OS X 10.10.3)のさまざまなシェルのいくつかの起動順序です。テスト中のシェルがループを制御するシェルではないように、tcshを使用してループを制御するようにテストを書き直しました。各シェルに対して、ループはタイミングの前に5回実行され、シェル実行可能ファイルとスクリプトがキャッシュにあることを確認します。
ご覧のとおり、確実な勝者はありませんが、確実な敗者はあります。とにかくbash 4はbash 3よりはるかに遅いです。 Dashはうまく機能しますが、ksh93がオープンソースであることを考えると、これをすべての目的に使用しない実際的な理由はありません(ライセンスの詳細を間違って理解した場合はお詫び申し上げます)。 ksh93は迅速で信頼性が高く、UNIXの世界では事実上の標準です(if GNU / Linuxゾーンにはありません)、POSIXシェル機能の親セットを提供します(私が知る限り、POSIXシェルはksh88に基づいています)。インタラクティブシェルはbashと同じですが、tcshよりも遅くなります。敗者はもちろんzshです。
/bin/bash is v3.2.57(1)
/usr/local/bin/bash is v4.3.33(1)
dash is v0.5.8
ksh is v93u+
mksh is vR50f
pdksh is v5.2.14
/opt/heirloom/5bin/sh is from SysV
yash is v2.37
zsh is v5.0.5
% cat driver.csh
#!/bin/tcsh
foreach s ( $* )
echo
echo "$s"
foreach i ( `seq 1 5` )
./simple_loop.csh "$s"
end
/usr/bin/time -p ./simple_loop.csh "$s"
end
% cat simple_loop.csh
#!/bin/tcsh
set shell = `which ${1}`
foreach i ( `seq 1 1000` )
${shell} -c ":"
end
% ./driver.csh /bin/bash /usr/local/bin/bash dash ksh mksh pdksh /opt/heirloom/5bin/sh yash zsh
/bin/bash
real 4.21
user 1.44
sys 1.94
/usr/local/bin/bash
real 5.45
user 1.44
sys 1.98
dash
real 3.28
user 0.85
sys 1.11
ksh
real 3.48
user 1.35
sys 1.68
mksh
real 3.38
user 0.94
sys 1.14
pdksh
real 3.56
user 0.96
sys 1.17
/opt/heirloom/5bin/sh
real 3.46
user 0.92
sys 1.11
yash
real 3.97
user 1.08
sys 1.44
zsh
real 10.88
user 3.02
sys 5.80
答え4
ここにある多くの回答には、不公正なテストケースが多すぎます。 2 つのシェルをテストする場合は、各シェルに対して正しい構文を使用してください。 Bashでは、デュアルブラケットはシングルブラケットよりも高速で安定しているため、速度差ははるかに小さくなります。最適化されたbashismを使用することも可能です。これにより、これらの速度差も小さくなります。私のシステムでは、bashはひどく実行され、bashismをたくさん使用しています。そしてダッシュのposix等価物はここでより遅いです。 dashは常にbashよりも数倍速いので、これは間違っています。実際、ダッシュが常に最速の2つのposixコマンドラインを比較するのはかなり不公平です。私の考えでは、posixは真剣に古いです。そして互換性の点で、今は関連するシステムを見つけるのは本当に難しく、bashシェルを使用しません。
良い比較は、各シェルで可能な限り最高のコマンドラインを使用して特定のタスクを実行することです。まったく同じコマンドラインであるだけでなく、1つのシェルしかないという利点があります。これらの比較は信頼できず、競合他社の実際のパフォーマンスを示していません。日常業務では、多くのユースケースでどのシェルが速いかを確認します。
たとえば、a
文字列内のすべての文字をb
文字に置き換えるには、bashで作成できますが、ダッシュ"${varname//a/b}"
では次の外部ツールを呼び出す必要があります"$(echo "$varname" | sed 's/a/b/g')"
。何百回も繰り返す必要がある場合は、bashismを使用すると速度が2倍になります。