我有一个包含以下10个数字的文件:
> cat numbers
9
11
32
88
89
90
95
104
118
120
>
我想打印出前面的数字,只要它比当前数字小至少5个数字。所以我希望输出如下:
11
32
90
95
104
120
我有一个脚本可以执行此操作:
> cat test.sh
#!/bin/bash
subtraction="5"
while read -r number; do
if [ -n "$previous_number" ] && (( $((number - subtraction)) >= previous_number )); then
echo "$previous_number"
fi
previous_number="$number"
done < "$1"
> ./test.sh numbers
11
32
90
95
104
>
但是,它不会打印120
。在这种情况下,最优雅/最合适的解决方案是什么?我应该在while循环后添加tail -1 "$1"
吗?
答案 0 :(得分:2)
使用awk
来完成这项工作更容易:
awk 'NR>1 && $1-p>=5{print p} {p=$1}' file
<强>输出:强>
11
32
90
95
104
btw 120
不会在输出中打印,因为前面的数字是118
,而不是<=5
到120
。
答案 1 :(得分:2)
如果其他人在阅读此内容时while read
真的没有迭代文件的最后一行,那么可能存在不同的问题:没有尾随换行符的输入文件
对于那个,可以按如下方式修改其代码:
while read -r number || [[ $number ]]; do
: "...logic here..."
done
这是正确的,因为如果没有尾随换行符,read
将返回false,因此循环体不会使用原始代码执行,但仍会填充$number
。
然而,对于这个特定的程序及其给出的具体输入,while read
成语如何处理输入的最后一行并没有任何错误;手头的输出遵循程序的逻辑编写和定义。
考虑以下版本,这使得发生的事情变得更加清晰:
#!/bin/bash
subtraction="5"
while read -r number; do
if [[ $previous_number ]] && (( (number - subtraction) >= previous_number )); then
printf '%q is at least %q away from %q\n' "$previous_number" "$subtraction" "$number"
else
printf '%q is not %q away from %q\n' "$previous_number" "$subtraction" "$number"
fi
previous_number="$number"
done <"$1"
它的输出是:
'' is not 5 away from 9
9 is not 5 away from 11
11 is at least 5 away from 32
32 is at least 5 away from 88
88 is not 5 away from 89
89 is not 5 away from 90
90 is at least 5 away from 95
95 is at least 5 away from 104
104 is at least 5 away from 118
118 is not 5 away from 120
...正如最后一行输出所示, 正在考虑120
,并决定不按照您定义的程序逻辑打印它。