
我在终端中运行此命令:
grep "bla bla blah" blah* | echo "Blah: $(wc -l) / $(ls | wc -l) * 100"
我得到这个输出:
Blah: 44 / 89 * 100
我期望看到什么:
49.4
有没有办法仅使用 bash 命令来获得所需的输出?我不喜欢我计划通过管道输出的脚本。
答案1
你的代码说要打印一个字符串。它没有在任何地方表明该字符串实际上是您想要计算的算术表达式。所以你不能合理地期望你的表达式被评估。
您的代码不是最优的。$(wc -l)
将计算 所返回的匹配数grep
,但有一种更简单的方法:grep -c
改为运行。$(ls | wc -l)
是计算当前目录中非点文件的不可靠方法,因为的输出ls
不可靠;$(set -- *; echo $#)
是执行此操作的一种可靠方法(假设至少有一个匹配文件;如果该假设可能不成立,请使用$(set -- *; if [ -e "$1" ]; then echo $#; else echo 0; fi
,但请注意,这将导致除以零,低于该值您应该以某种方式将其视为错误条件)。所以你可以这样编写你的代码:
matches=$(grep -c "bla bla blah" blah*)
files=$(set -- *; echo $#)
echo "Blah: $matches / $files * 100"
或者您可以内联两个中间值的计算:
echo "Blah: $(grep -c "bla bla blah" blah*) / $(set -- *; echo $#) * 100"
现在,要执行算术,您可以使用 shell 的内置函数算术展开,但它仅限于整数运算,因此/
运算符将向下舍入到最接近的整数。
echo "Blah: $(($matches * 100 / $files))"
在 ksh93、zsh 和 yash 中(但在其他 shell 中除外),如果表达式中存在强制浮点的内容(例如浮点常量),您将获得浮点算术。 Bourne shell、ksh88、pdksh、bash、ash 中不存在此功能。
echo "Blah: $(($matches * 100.0 / $files))"
这bc
实用程序以任意精度对十进制数执行运算。
echo "Blah: $(echo "scale=2; $matches * 100 / $files" | bc)"
另一个可以执行浮点计算的标准实用程序(可用的数学函数较少)是awk
。
echo "$matches" "$files" | awk '{print "Blah:", $1 * 100 / $2}'
答案2
首先,您还没有指定您的外壳。我假设您正在使用bash
,但请在以后说明。
同样非常重要的是你不解析 的输出ls
。有很好的文档说明为什么不这样做这里。
还,什么您是否正在尝试获取百分比输出?您似乎并没有试图在最后计算百分比。现在我只是做了你列出的精确计算。
这是一个小脚本,应该能够在没有提到的问题的情况下执行此操作:
#!/bin/bash
_die() {
printf '%s\n' "${@:2}"
exit "$1"
}
(( $# )) || _die 1 "Usage: ${0##*/} pattern <dir>"
[[ $2 ]] && _dir=$2 || _dir=.
[[ -d ${_dir} ]] || _die 2 "Directory does not exist: ${_dir}"
for _file in "${_dir}"/*; do
[[ -f ${_file} ]] && _files+=( "${_file}" )
done
(( ${#_files[@]} )) || _die 3 'No files matched by glob, not attempting to divide by 0.'
# We pass the same files found to grep instead of reglobbing to avoid a race condition.
while IFS= read -r _number_of_matches; do
(( _total_matches )) && (( _total_matches+=_number_of_matches )) || _total_matches=${_number_of_matches}
done < <(grep -hc "$1" "${_files[@]}")
(( _total_matches )) || _die 4 "Nothing matched by expression: $1"
printf 'Blah: %s\n' "$(bc <<< "${_total_matches}/${#_files[@]}")"
请记住,它bc
不可移植。如果您不介意使用整数算术,则可以使用 shell 来计算并返回它,而不是bc
使用$((
.
答案3
像这样的东西吗?
echo "scale=2;100*`grep 'bla bla bla' bla* | wc -l`/`cat bla* | wc -l`" | bc