关于某个数字已被“包含”在另一个数字中的输出问题

关于某个数字已被“包含”在另一个数字中的输出问题

这就是我的脚本,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.

id987659876是不同的,那么为什么我会得到这个输出以及如何解决这个问题?

,如果我输入一个包含较少字符的健康中心,如下所示:

./adiciona_enfermeiros.sh "João Vieira" 98765 "CSPort" 0

我得到:

Error: The Health Center introduced already has a nurse in it.

但我希望脚本假设与或CSPort不在同一位置 需要帮助解决这两个问题!预先非常感谢:)CSPortoCSPorta

答案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"CSPorto01CSPorto.1

除了建议该问题的解决方案之外,这里还提供了一个示例,说明如何更好地利用 AWK 的功能。您的程序分为add_nurses.shshell 脚本和add_nurses.awkAWK 脚本。

#!/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存在于 或CSportoCSporta。切换-w到 grep 也应该可以解决这个问题。

a=$(awk -F "[:]" '{print $3}' nurses.txt | grep -cw "$3")

相关内容