我有一个名为file.txt的文本文件,其中包含以下条目:-
healthy
healthy
healthy
healthy
healthy
unhealthy
initial
healthy
initial
healthy
现在我使用下面的命令在这个文件中计算了健康、初始和不健康的数量:-
grep -c healthy file.txt
grep -c unhealthy file.txt
grep -c initial file.txt
现在我需要shell脚本中的一个循环条件,它可以为我完成以下操作:-
while [ $(grep -c "healthy" file.txt) -lt 6 -a $(grep -c "unhealthy" file.txt) != 0 -a $(grep -c "initial" file.txt) != 0 ]
do
bla bla bla
done
基本上,我要做的就是,对于这个动态文件,它的条目会随着其他脚本的一部分而不断变化,只要文件中的健康计数小于6,不健康的计数是大于0的任何值,初始计数是大于0的值,那么就会发生循环,然后执行其他退出循环的操作。我没有得到正确的语法。这里的任何帮助都将不胜感激。
发布于 2019-08-02 10:57:34
The short answer
在上面的评论中进行了讨论后,OP和我确定了所提出的循环中唯一的真正问题是grep -c healthy
也将匹配unhealthy
,但除此之外,该循环已经按预期工作。
就像在grep -c '\bhealthy'
中一样,\b
应该用来表示单词边界,从而产生循环:
while [ $(grep -c '\bhealthy' file.txt) -lt 6 -a $(grep -c "unhealthy" file.txt) != 0 -a $(grep -c "initial" file.txt) != 0 ]
do
bla bla bla
done
编辑:正如@IanW在评论中指出的,你也可以使用grep -c -w word
而不是添加\b
,这将类似于在每个单词之前和之后添加\b
。
使其成为面向未来的
同样值得重复的是@CharlesDuffy上面的建议,避免使用-a
和-o
,因为它们被标记为过时,而更喜欢[ ... ] && [ ... ]
。对于长期稳定的代码来说,这是一个很好的选择。
所以现在这个循环看起来像这样:
while [ $(grep -c '\bhealthy' file.txt) -lt 6 ] && [ $(grep -c "unhealthy" file.txt) != 0 ] && [ $(grep -c "initial" file.txt) != 0 ]
do
bla bla bla
done
或使其成为bash特定的
最后,我想指出的是,如果这将专门在bash
中执行,而不是在sh
中执行,[[ ... ]]
会更快,因为它是由bash本身解释的,而不是调用程序test
,[
是它的别名。[[ ... ]]
是我个人的偏好,但与POSIX标准命令不同的是,它将来可能会崩溃,并且不是与所有shell都兼容。但它支持一种我认为更好的语法,而且通常更易于使用,特别是不需要总是引用变量。有关该主题的有趣讨论,请参阅double vs single square brackets in bash。
所以我自己更喜欢的格式是:
while [[ $(grep -c '\bhealthy' file.txt) -lt 6 && $(grep -c "unhealthy" file.txt) != 0 && $(grep -c "initial" file.txt) != 0 ]]
do
bla bla bla
done
发布于 2019-08-02 11:06:58
你搞错了。这应该是你的起点:
$ awk '{c[$1]++} END{for (i in c) print i, c[i]}' file
healthy 7
initial 2
unhealthy 1
wrt你想要采取行动的条件,你可以直接写出来:
$ awk '
{ c[$1]++ }
END { exit ( (c["healthy"] <= 6) && (c["unhealthy"] > 0) && (c["initial"] > 0) ? 1 : 0 ) }
' file
$ echo $?
0
$ awk '
{ c[$1]++ }
END { exit ( (c["healthy"] <= 8) && (c["unhealthy"] > 0) && (c["initial"] > 0) ? 1 : 0 ) }
' file
$ echo $?
1
并将它们用作:
while awk '...' file; do
your stuff
done
无论您想要做什么,都同样是琐碎的、高效的、可移植的和健壮的。
发布于 2019-08-02 06:46:41
你的文件有多大?如果它非常大,并且您使用grep
扫描它三次,这可能会使您的脚本变得不必要地慢。
您可以使用AWK对文件中的一次匹配进行计数:
read -r u_count h_count i_count <<< <(awk '{arr[$1]++} END {print arr["unhealthy"] arr["healthy"] arr["initial"]}'
while (( u_count < 6 && h_count != 0 && i_count != 0 ))
只要数据文件看起来像您发布的示例,或者即使这些单词后面有其他空格分隔字段,这种方法就会起作用。如果这些单词不是每行的第一个,那么可以适当地修改AWK脚本。
除非这些计数在循环中发生变化,否则您可能只想使用if
而不是while
。
https://stackoverflow.com/questions/57316169
复制相似问题