![关于某个数字已被“包含”在另一个数字中的输出问题](https://linux22.com/image/189511/%E5%85%B3%E4%BA%8E%E6%9F%90%E4%B8%AA%E6%95%B0%E5%AD%97%E5%B7%B2%E8%A2%AB%E2%80%9C%E5%8C%85%E5%90%AB%E2%80%9D%E5%9C%A8%E5%8F%A6%E4%B8%80%E4%B8%AA%E6%95%B0%E5%AD%97%E4%B8%AD%E7%9A%84%E8%BE%93%E5%87%BA%E9%97%AE%E9%A2%98.png)
这就是我的脚本,add_nurses.sh:
#!/bin/bash
sed -i '/^$/d' nurses.txt
if [ $# != 4 ] ; then
echo "Error: Syntax: $0 <id number>:<name>:<associated Health Center>:<number of vaccines done>:<availabiliy>"
else
a=$(awk -F "[:]" '{print $3}' nurses.txt | grep -c "$3")
b=$(awk -F "[:]" '{print $1}' nurses.txt | grep -c "$2")
if [[ "$a" -gt "0" ]] ; then
echo "Error: The Health Center introduced already has a nurse in it."
elif [[ "$b" -gt "0" ]] ; then
echo "Error: There is already a nurse registered with that id."
else
echo "$2:$1:$3:0:$4" >> nurses.txt
echo "Nurse added."
fi
fi
我想要这个脚本添加护士X到nurses.txt。但是,如果已经有一名护士在与 X 相同的位置注册,或者如果 X 所拥有的 ID 已被护士.txt 上的另一位护士占用,我不想将护士 X 添加到列表中。
我的护士.txt内容如下:
12345:Ana Correia:CSLisboa:0:0
98765:Joao Vieira:CSPorto:0:1
如果我像这样运行程序:
./add_nurses.sh "João Vieira" 98765 "CSPorto" 0
我得到这些参数的正确消息是:
Error: The Health Center introduced already has a nurse in it.
如果我将位置更改为具有相同字母数但与 不同的字符串,CSPorto
例如:
./add_nurses.sh "João Vieira" 98765 "CSPorta" 0
我还得到了正确的输出,即:
Error: There is already a nurse registered with that id.
但如果我这样输入:
./add_nurses.sh "João Vieira" 9876 "CSPorta" 0
它给了我错误的输出,即:
Error: There is already a nurse registered with that id.
id98765
和9876
是不同的,那么为什么我会得到这个输出以及如何解决这个问题?
还,如果我输入一个包含较少字符的健康中心,如下所示:
./adiciona_enfermeiros.sh "João Vieira" 98765 "CSPort" 0
我得到:
Error: The Health Center introduced already has a nurse in it.
但我希望脚本假设与或CSPort
不在同一位置 需要帮助解决这两个问题!预先非常感谢:)CSPorto
CSPorta
答案1
正如已经提到的,问题是你的方法也会找到子字符串。然而,整个事情非常脆弱且效率低下,因为您要多次读取文件并使用grep
它可以在线路上的任何位置找到匹配项。相反,我会在一次awk
调用中完成整个处理。像这样的东西:
#!/bin/bash
if [ $# != 4 ] ; then
echo "Error: Syntax: $0 <id number> <name> <associated Health Center> <number of vaccines done> <availabiliy>"
exit 1
fi
## Have awk print out 'var=value' pairs and 'source' them
## into your current shell so they will be available as
## variables in the current script.
. <(awk -v id="$2" -v center="$3" -F':' \
'{
if($1==id){i=1}
if($3==center){c=1}
} END{ print "idExists="i,"centerHasNurse="c}' nurses.txt)
## I am separating the two tests since they are not mutually exclusive
## this way, you will get separate messages when the id exists and when
## the nurse exists. Either error will cause the script to fail, but this
## way you will know if the id exists and the center has a nurse.
foundError=""
if [[ -n $idExists ]]; then
echo "Error: There is already a nurse registered with that id."
foundError=1
fi
if [[ -n $centerHasNurse ]]; then
echo "Error: The Health Center introduced already has a nurse in it."
foundError=1
fi
if [[ -n $foundError ]]; then
exit 1
fi
## If we got to this part, there were no errors and we can modify the file
echo "$2:$1:$3:0:$4" >> nurses.txt
echo "Nurse added."
答案2
正如其他人指出的那样,grep -c "$3"
执行grep -c "$2"
正则表达式搜索,默认情况下(grep
至少在 中),字符串和模式之间不是完全匹配(即从头到尾)。此外,当允许模式(在您的情况下为"$3"
and )包含特殊字符(例如与模式匹配)时,用正则表达式搜索代替相等性测试可能会导致不需要的结果。"$2"
CSPorto01
CSPorto.1
除了建议该问题的解决方案之外,这里还提供了一个示例,说明如何更好地利用 AWK 的功能。您的程序分为add_nurses.sh
shell 脚本和add_nurses.awk
AWK 脚本。
#!/bin/sh
if [ $# -ne 4 ]
then
printf '%s\n' "Error: Syntax: $0 <id number>:<name>:<associated Health Center>:<number of vaccines done>:<availabiliy>"
exit 1
fi
awk -v FS=':' -v OFS=':' -v name="$1" -v id="$2" -v center="$3" -v av="$4" \
-f add_nurses.awk nurses.txt
#!/bin/awk
$3 == center {
print "Error: The Health Center introduced already has a nurse in it."
err++
}
$1 == id {
print "Error: There is already a nurse registered with that id."
err++
}
END {
if (! err) {
print id,name,center,"0",av >>FILENAME
print "Nurse added."
}
}
(我不负责删除空行nurses.txt
)。
笔记:
- 单独的 AWK 脚本更易于阅读和维护(但这可能是个人喜好的问题)
- 您不需要正则表达式 (
[:]
) 作为awk
的字段分隔符 - 打印输入可能给出的所有错误是有意义的,而不是在第一个错误之后停止
- ...但是,与此同时,当输入明显格式错误时解析输入没有什么意义(因此检查 中的参数数量
add_nurses.sh
) - 在这种情况下,并不真正需要非标准 shell 功能:
[[ ... ]]
被替换为[ ... ]
;出于同样的原因,我使用了#!/bin/sh
答案3
我相信问题在于grep 9876
看到它9876
存在,但只有当数字作为单词存在时你才想看到它。如果您-w
在查找 ID 号时使用该开关,您应该会得到所需的响应。出于同样的原因,它被视为CSport
存在于 或CSporto
中CSporta
。切换-w
到 grep 也应该可以解决这个问题。
a=$(awk -F "[:]" '{print $3}' nurses.txt | grep -cw "$3")