这是我写的一个非常简单的bash脚本:
#!/bin/bash
ITEM_LIST=items.txt
LOG_FILE=log.log
TOTAL_ITEMS=$(wc -l ${ITEM_LIST} | awk '{ print $1 }')
let NOT_FOUND=0
cat ${ITEM_LIST} | while read item; do
grep "${item}" ${LOG_FILE} > /dev/null
FOUND=${?}
if [ ${FOUND} -ne 0 ]; then
let NOT_FOUND=NOT_FOUND+1
echo "Item not found [${item}] Item not found number: ${NOT_FOUND}"
fi
done
echo "Total items: ${TOTAL_ITEMS}"
echo "Total not found items: ${NOT_FOUND}"
我想检查日志文件中是否存在某些项目,计算不存在的项目数量,并打印某种报告(最后两次回显)。此时,我正在从cygwin bash shell运行它。
考虑这两个示例文件:
items.txt
first item
second item
third item
fourth item
fifth item
log.log
blahblah blah blah first item blah blah blah
second blah blah item
blah third item blah
脚本的输出:
[17:46:38]:/cygdrive/c/Temp/qpa# ./script2.sh
Item not found [second item] Item not found number: 1
Item not found [fourth item] Item not found number: 2
Total items: 4
Total not found items: 0
问题:
为什么脚本会打印“Total not found items:0”?它打印循环上每个回显的当前总数(均为NOT_FOUND变量)。
这个shell脚本中有一些不好的做法吗?在哪里以及为什么?
答案 0 :(得分:6)
你在这里使用的管道:
cat ${ITEM_LIST} | ...
之后将在子shell中执行while循环。但这意味着NOT_FOUND
变量不会在父shell中更新,而只会在您执行循环的子shell中更新。
在子shell实例的末尾包含echo命令:
cat ${ITEM_LIST} | {
while read item; do
grep "${item}" ${LOG_FILE} > /dev/null
FOUND=${?}
if [ ${FOUND} -ne 0 ]; then
let NOT_FOUND=NOT_FOUND+1
echo "Item not found [${item}] Item not found number: ${NOT_FOUND}"
fi
done
echo "Total items: ${TOTAL_ITEMS}"
echo "Total not found items: ${NOT_FOUND}"
}
Bash FAQ item中也解释了这个问题。希望这可以帮助。
正如常见问题解答所解释的那样,在特定情况下,您也可以将其重写为:
while read item; do
grep "${item}" ${LOG_FILE} > /dev/null
FOUND=${?}
if [ ${FOUND} -ne 0 ]; then
let NOT_FOUND=NOT_FOUND+1
echo "Item not found [${item}] Item not found number: ${NOT_FOUND}"
fi
done < ${ITEM_LIST}
在这种情况下首选第二个选项,因为它将摆脱一个“无用的猫”:)
答案 1 :(得分:0)
使用expr进行数学计算
NOT_FOUND=0; NOT_FOUND=`expr ${NOT_FOUND} + 1`; echo ${NOT_FOUND}
1
@litb是对的,您需要在主脚本中更新NOT_FOUND,而不是在管道命令生成的子shell中更新。