使用管道在 bash 中划分的最佳方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 
原文地址: http://stackoverflow.com/questions/13182070/
Warning: these are provided under cc-by-sa 4.0 license.  You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Best way to divide in bash using pipes?
提问by Brian
I'm just looking for an easy way to divide a number (or provide other math functions). Let's say I have the following command:
我只是在寻找一种简单的方法来划分数字(或提供其他数学函数)。假设我有以下命令:
find . -name '*.mp4' | wc -l
How can I take the result of wc -l and divide it by 3?
如何将 wc -l 的结果除以 3?
The examples I've seen don't deal with re-directed out/in.
我见过的例子没有处理重定向的出/入。
回答by dogbane
Using bc:
使用bc:
$ bc -l <<< "scale=2;$(find . -name '*.mp4' | wc -l)/3"
2.33
In contrast, the bash shell only performs integer arithmetic.
相比之下,bash shell 只执行整数运算。
Awk is also very powerful:
awk 也很强大:
$ find . -name '*.mp4' | wc -l | awk '{print /3}'
2.33333
You don't even need wcif using awk:
wc如果使用,您甚至不需要awk:
$ find . -name '*.mp4' | awk 'END {print NR/3}'
2.33333
回答by F. Hauri
Edit 2018-02-22: Adding shell connector
编辑 2018-02-22:添加 shell connector
There is more than 1 way:
有不止一种方式:
Depending on precision required andnumber of calcul to be done! See shell connectorfurther!
取决于所需的精度和要完成的计算次数!见shell connector进一步!
Using bc(binary calculator)
使用bc(二进制计算器)
find . -type f -name '*.mp4' -printf \n | wc -l | xargs printf "%d/3\n" | bc -l
6243.33333333333333333333
or
或者
echo $(find . -name '*.mp4' -printf \n | wc -l)/3|bc -l
6243.33333333333333333333
or using bash, result in integer only:
或使用 bash,只产生整数:
echo $(($(find . -name '*.mp4' -printf \n| wc -l)/3))
6243
Using bashinterger builtin math processor
使用bash整数内置数学处理器
res=000$((($(find  . -type f -name '*.mp4' -printf "1+")0)*1000/3))
printf -v res "%.2f" ${res:0:${#res}-3}.${res:${#res}-3}
echo $res
6243.33
Pure bash
纯粹的bash
With recent 64bits bash, you could even use @glennHymanman's ideasof using globstar, but computing pseudo floating could be done by:
使用最近的 64 位 bash,您甚至可以使用@glennHymanman 的using想法globstar,但可以通过以下方式计算伪浮动:
shopt -s globstar
files=(**/*.mp4)
shopt -u globstar
res=$[${#files[*]}000/3]
printf -v res "%.2f" ${res:0:${#res}-3}.${res:${#res}-3}
echo $res
6243.33
There is no fork and $rescontain a two digit rounded floating value.
没有分叉并$res包含两位四舍五入的浮点值。
Nota: Care about symlinkswhen using globstarand **!
注意:使用and时要注意符号链接!globstar**
Introducing shell connector
介绍 shell connector
If you plan to do a lot of calculs, require high precision and use bash, you could use long running bcsub process:
如果您打算进行大量计算,需要高精度并使用bash,则可以使用长时间运行的bc子进程:
mkfifo /tmp/mybcfifo
exec 5> >(exec bc -l >/tmp/mybcfifo)
exec 6</tmp/mybcfifo
rm /tmp/mybcfifo
then now:
那么现在:
echo >&5 '12/34'
read -u 6 result
echo $result
.35294117647058823529
This subprocess stay open and useable:
这个子进程保持打开和可用:
ps --sid $(ps ho sid $$) fw
  PID TTY      STAT   TIME COMMAND
18027 pts/9    Ss     0:00 bash
18258 pts/9    S      0:00  \_ bc -l
18789 pts/9    R+     0:00  \_ ps --sid 18027 fw
Computing $PI:
计算$PI:
echo >&5 '4*a(1)'
read -u 6 PI
echo $PI
3.14159265358979323844
To terminate sub process:
终止子进程:
exec 6<&-
exec 5>&-
Little demo, about The best way to divide in bash using pipes!
小演示,关于使用管道在 bash 中划分的最佳方法!
Computing range {1..157} / 42( I will let you google for answer to the ultimate question of life, the universe, and everything;)
计算范围{1..157} / 42(我会让你谷歌搜索answer to the ultimate question of life, the universe, and everything;)
... and print 13 result by lines in order to reduce output:
...并按行打印 13 结果以减少输出:
printf -v form "%s" "%5.3f "{,}{,}{,,};form+="%5.3f\n";
By regular way
按常规方式
testBc(){
    for ((i=1; i<157; i++)) ;do
        echo $(bc -l <<<"$i/42");
    done
}
By using long running bcsub process:
通过使用长时间运行的bc子进程:
testLongBc(){ 
    mkfifo /tmp/mybcfifo;
    exec 5> >(exec bc -l >/tmp/mybcfifo);
    exec 6< /tmp/mybcfifo;
    rm /tmp/mybcfifo;
    for ((i=1; i<157; i++)) ;do
        echo "$i/42" 1>&5;
        read -u 6 result;
        echo $result;
    done;
    exec 6>&-;
    exec 5>&-
}
Let's see without:
让我们看看没有:
time printf "$form" $(testBc)
0.024 0.048 0.071 0.095 0.119 0.143 0.167 0.190 0.214 0.238 0.262 0.286 0.310
0.333 0.357 0.381 0.405 0.429 0.452 0.476 0.500 0.524 0.548 0.571 0.595 0.619
0.643 0.667 0.690 0.714 0.738 0.762 0.786 0.810 0.833 0.857 0.881 0.905 0.929
0.952 0.976 1.000 1.024 1.048 1.071 1.095 1.119 1.143 1.167 1.190 1.214 1.238
1.262 1.286 1.310 1.333 1.357 1.381 1.405 1.429 1.452 1.476 1.500 1.524 1.548
1.571 1.595 1.619 1.643 1.667 1.690 1.714 1.738 1.762 1.786 1.810 1.833 1.857
1.881 1.905 1.929 1.952 1.976 2.000 2.024 2.048 2.071 2.095 2.119 2.143 2.167
2.190 2.214 2.238 2.262 2.286 2.310 2.333 2.357 2.381 2.405 2.429 2.452 2.476
2.500 2.524 2.548 2.571 2.595 2.619 2.643 2.667 2.690 2.714 2.738 2.762 2.786
2.810 2.833 2.857 2.881 2.905 2.929 2.952 2.976 3.000 3.024 3.048 3.071 3.095
3.119 3.143 3.167 3.190 3.214 3.238 3.262 3.286 3.310 3.333 3.357 3.381 3.405
3.429 3.452 3.476 3.500 3.524 3.548 3.571 3.595 3.619 3.643 3.667 3.690 3.714
real    0m10.113s
user    0m0.900s
sys     0m1.290s
Wow! Ten secondson my raspberry-pi!!
哇!在我的树莓派上十秒钟!!
Then with:
然后用:
time printf "$form" $(testLongBc)
0.024 0.048 0.071 0.095 0.119 0.143 0.167 0.190 0.214 0.238 0.262 0.286 0.310
0.333 0.357 0.381 0.405 0.429 0.452 0.476 0.500 0.524 0.548 0.571 0.595 0.619
0.643 0.667 0.690 0.714 0.738 0.762 0.786 0.810 0.833 0.857 0.881 0.905 0.929
0.952 0.976 1.000 1.024 1.048 1.071 1.095 1.119 1.143 1.167 1.190 1.214 1.238
1.262 1.286 1.310 1.333 1.357 1.381 1.405 1.429 1.452 1.476 1.500 1.524 1.548
1.571 1.595 1.619 1.643 1.667 1.690 1.714 1.738 1.762 1.786 1.810 1.833 1.857
1.881 1.905 1.929 1.952 1.976 2.000 2.024 2.048 2.071 2.095 2.119 2.143 2.167
2.190 2.214 2.238 2.262 2.286 2.310 2.333 2.357 2.381 2.405 2.429 2.452 2.476
2.500 2.524 2.548 2.571 2.595 2.619 2.643 2.667 2.690 2.714 2.738 2.762 2.786
2.810 2.833 2.857 2.881 2.905 2.929 2.952 2.976 3.000 3.024 3.048 3.071 3.095
3.119 3.143 3.167 3.190 3.214 3.238 3.262 3.286 3.310 3.333 3.357 3.381 3.405
3.429 3.452 3.476 3.500 3.524 3.548 3.571 3.595 3.619 3.643 3.667 3.690 3.714
real    0m0.670s
user    0m0.190s
sys     0m0.070s
Less than one second!!
不到一秒!!
Hopefully, results are same, but execution time is very different!
希望结果相同,但执行时间却大不相同!
My shell connector
我的 shell connector
I've published a connector function: Connector-bash on GitHub.com and shell_connector.sh on my own site.
我已经发布了一个连接器函数:GitHub.com上的Connector-bash和我自己网站上的 shell_connector.sh。
source shell_connector.sh
newConnector /usr/bin/bc -l 0 0
myBc 1764/42 result
echo $result
42.00000000000000000000
回答by Seph
find . -name '*.mp4' | wc -l | xargs -I{} expr {} / 2
find . -name '*.mp4' | wc -l | xargs -I{} expr {} / 2
Best used if you have multiple outputs you'd like to pipe through xargs. Use{}as a placeholder for the expression term.
如果您有多个输出想要通过xargs. 使用{}作为表达长期的占位符。
回答by glenn Hymanman
Depending on your bash version, you don't even need find for this simple task:
根据您的 bash 版本,您甚至不需要 find 来完成这个简单的任务:
shopt -s nullglob globstar
files=( **/*.mp4 )
dc -e "3 k ${#files[@]} 3 / p"
This method will correctly handle the bizarre edgecase of filenames containing newlines.
此方法将正确处理包含换行符的文件名的奇怪边缘情况。

