나는 항상 bash 대신 dash를 사용하는 유일한 이점은 dash가 더 작기 때문에 부팅시 대시의 많은 인스턴스가 더 빨리 시작된다는 것입니다.
그러나 나는 약간의 연구를 해왔고 어떤 사람들은 더 빨리 달릴 것이라는 희망으로 모든 스크립트를 마이그레이션하는 것을 발견 했으며 우분투 위키의 DashAsBinSh 기사에서도 이것을 발견했습니다 .
기본 쉘을 전환하는 주요 이유는 효율성 이었습니다 . bash는 대화식 사용에 적합한 뛰어난 기능을 갖춘 뛰어난 쉘입니다. 실제로 여전히 기본 로그인 쉘입니다. 그러나 대시와 비교 하여 시작 하고 작동 하는 것은 다소 크고 느립니다 .
요즘 나는 시스템에서 많은 것들을 위해 많은 bash 스크립트를 사용하고 있으며, 내 문제는 24/7 지속적으로 실행되는 특정 스크립트를 가지고 있으며 약 200 명의 어린이가 생성되어 컴퓨터를 10 °로 가열합니다. 일반적인 사용법보다 C가 더 많습니다.
많은 bashism을 가진 다소 큰 스크립트이므로 POSIX 또는 다른 쉘로 이식하는 데 시간이 많이 걸리고 POSIX는 실제로 개인적인 용도로는 중요하지 않습니다. 그러나이 중 일부를 줄일 수 있다면 가치가 있습니다. CPU 사용량. 내가 좋아하는 외부 바이너리 호출처럼, 고려해야 할 다른 일들도 알고 sed
같은 간단한 bashism에 대한 ${foo/bar}
, 또는 grep
대신에가 =~
.
TL; DR 은 대시와 비교 하여 시작 하고 작동하는 데 실제로 bash가 더 느립니까? bash보다 더 효율적인 다른 유닉스 쉘이 있습니까?
답변
쉘 시퀀스 :
아마도 쉘의 성능을 벤치마킹하는 유용한 방법은 매우 작고 간단한 평가를 반복적으로 수행하는 것입니다. 쉘은 읽어야하기 때문에 루프하는 것이 아니라 입력 을 반복하는 것이 중요하다고 생각 합니다 <&0
.
나는 @cuonglm이 이미 게시 한 테스트를 보완 할 것이라고 생각 했습니다. 호출했을 때 쉘 프로세스가 얼마나 빨리로드되는지를 보여주는 것과는 달리 단일 쉘 프로세스의 성능을 보여주기 때문입니다. 이런 식으로 우리 사이에서 동전의 양면을 덮습니다.
데모를 용이하게하는 기능은 다음과 같습니다.
sh_bench() ( #dont 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
개행 읽기마다 변수를 한 번 증가 시키거나, 약간의 최적화로 가능하면 개행 읽기마다 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 그리고 다른 많은 테스트를 수행했으며 (자세한 내용 은 채팅 참조) 결과는 다음과 같이 요약 될 수 있습니다.
- 속도가 필요하다면 dash 로 확실히 가십시오. 다른 쉘보다 훨씬 빠르며 bash 보다 약 4 배 빠릅니다 .
- 하지만 비지 박스 의 쉘보다 훨씬 속도가 느려질 수 있습니다 대시 는 자신의 유저 랜드 유틸리티의 대부분을 가지고 있기 때문에, 몇 가지 테스트에서는 빠를 수와 같은
grep
,sed
,sort
, 등, 일반적으로 사용되는 GNU만큼 많은 기능을 가지고 있지 않는 유틸리티, 그러나 작업을 많이 얻을 수 있습니다. - 속도가 관심있는 모든 것이 아닌 경우 ksh (또는 ksh93 )는 속도와 기능 사이의 최상의 타협으로 간주 될 수 있습니다. 속도는 작은 mksh 와 비교할 때 bash 보다 빠르며 부동 소수점 산술 과 같은 고유 한 기능도 있습니다 .
- bash 는 단순성, 안정성 및 기능성으로 유명 하지만 대부분의 테스트에서 모든 쉘 중 가장 느리고 마진이 큽니다.
답변
벤치 마크를 해보자.
로 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
각 반복은 쉘을 시작하고 no-op operator- colon으로 아무것도 수행하지 않고 종료합니다.
결과에서 알 수 있듯이 시작 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
.
답변
인증 된 UNIX (Mac OS X 10.10.3)에서 다양한 쉘의 시작 타이밍은 다음과 같습니다. 루프를 제어하기 위해 tcsh를 사용하는 테스트를 다시 작성하여 테스트중인 쉘이 루프를 제어하는 것이 아니 었습니다. 각 쉘에 대해 루프는 타이밍 전에 5 번 실행되어 쉘 실행 파일과 스크립트가 캐시에 있는지 확인합니다.
보시다시피, 확실한 승자는 없지만 확실한 패자가 있습니다. 어쨌든 bash 4는 bash 3보다 분명히 느리다. 대시는 잘 수행하지만 ksh93이 이제 오픈 소스이기 때문에 모든 것을 위해 그것을 사용하지 않을 이유가 없습니다 (라이센스를 오해하는 경우 사과) : ksh93은 빠르고 견고합니다. 그리고 UNIX-land (GNU / Linux-land가 아닌 경우)의 사실상의 표준; POSIX 쉘 기능의 수퍼 세트를 제공합니다 (POSIX 쉘은 ksh88을 기반으로 함). tcsh에 비해 지연되지만 대화식 쉘로서 bash와 같습니다. 그리고 패자는 물론 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
답변
여기에 많은 답변에 불공평 한 테스트 사례가 너무 많습니다. 두 개의 쉘을 테스트하는 경우 각각에 대해 올바른 구문을 사용하십시오. 그리고 bash에서 더블 브라켓은 싱글 브라켓보다 훨씬 빠르고 안정적이므로 속도 차이가 훨씬 적습니다. 또한 최적화 된 bashism을 사용하면 이러한 속도 차이도 줄어 듭니다. 내 시스템에서 bash는 bashism을 많이 사용하여 지옥처럼 실행됩니다. 그리고 대시의 posix 등가가 여기에서 느려집니다. 대시가 항상 bash보다 여러 배 빠르다는 것은 올바르지 않습니다. 실제로 누가 대시가 가장 빠를 수 있는지에 대해 posix 명령 행을 비교하는 것은 상당히 불공평합니다. 내 견해로는 posix는 구식입니다. 호환성 측면에서 요즘 관련 시스템을 찾기가 어렵고 bash 쉘을 사용하지 않았습니다.
각 쉘에서 최상의 명령 행을 사용하여 특정 작업을 완료하는 것이 좋은 비교입니다. 하나의 쉘만이 실제로 이점을 가질 때 정확히 동일한 명령 행일뿐만 아니라. 이와 같은 비교는 신뢰할 수 없으며 경쟁사의 실제 성능을 보여주지 못했습니다. 나는 매일 사용하는 작업에서 많은 사용 사례에서 어떤 쉘이 더 빠르다는 것을 알았습니다.
예를 들어 a
문자열의 모든 문자를 문자 로 바꾸려면 b
bash "${varname//a/b}"
에서 대시로 쓰는 동안 다음과 같이 외부 도구를 호출해야합니다 "$(echo "$varname" | sed 's/a/b/g')"
. 수백 번 반복 해야하는 경우 bashism을 사용하면 속도가 2 배 빨라질 수 있습니다.