l0b*_*0b0 21 performance bash pipe io-redirection
到现在为止,cat奖的无用使用已经众所周知,并且还提到了无用使用echo(与此问题无关)。我想知道是否应该有一个“无用的echoBash 奖”:根据一些非常不科学的测量,管道似乎比 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
Run Code Online (Sandbox Code Playgroud)字符串
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
Run Code Online (Sandbox Code Playgroud)重定向
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
Run Code Online (Sandbox Code Playgroud)通常,heredocs 和 herestrings 的速度大致相同(这只是来自多个测试的一个数据集),而重定向始终慢 50% 以上。我是否误解了什么,或者这可以用作在 Bash 中读取标准输入的命令的一般规则吗?
Gil*_*il' 14
首先,让我们专注于性能。我在运行 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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
为了比较,我还在 ATT ksh93 和 dash 下对脚本进行了计时(除了herestring.bash,因为 dash 没有 herestrings)。
这里是三倍的中位数:
$ 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
Run Code Online (Sandbox Code Playgroud)
结论:
echo并且管道明显更快,但并没有显着加快。(请记住,这是一个玩具程序:在真正的程序中,大部分处理时间都在tr此处的调用中。)除了性能之外,还有清晰度和便携性。<<<是一个 ksh93/bash/zsh 扩展,它不如echo … |或知名<<。它在 ksh88/pdksh 或 POSIX sh 中不起作用。
唯一<<<可以说明显更清晰的地方是在 heredoc 中:
foo=$(tr a-z A-Z <<<'hello world')
Run Code Online (Sandbox Code Playgroud)
对比
foo=$(tr a-z A-Z <<'EOF'
hello world
EOF
)
Run Code Online (Sandbox Code Playgroud)
(大多数 shell 无法处理在包含<<EOF.的行的末尾关闭括号。)
小智 6
使用 heredocs 的另一个原因(如果你没有足够的)是如果流没有被消耗,echo 可能会失败。考虑有 bash'pipefail选项:
set -o pipefail
foo=yawn
echo $foo | /bin/true ; echo $? # returns 0
Run Code Online (Sandbox Code Playgroud)
/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
Run Code Online (Sandbox Code Playgroud)
141 是 SIGPIPE (128 + 13)(添加 128 是因为 bash 根据 bash(1) 这样做:
当命令在致命信号 N 上终止时,bash 使用 128+N 的值作为退出状态。
Heredocs 没有这个问题:
/bin/true <<< $foo$foo$foo$foo ; echo $? # returns 0 always
Run Code Online (Sandbox Code Playgroud)