숫자가 다른 숫자에 "포함"되어 있는 출력 문제에 대해

숫자가 다른 숫자에 "포함"되어 있는 출력 문제에 대해

이것은 내 스크립트입니다.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를 nurse.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.

id 98765와는 9876다릅니다. 그러면 이 출력이 나타나는 이유는 무엇이며 이 문제를 해결하는 방법은 무엇입니까?

반품, 다음과 같이 더 적은 문자로 보건소에 들어가면:

./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"수행하는 것은 기본적으로( 적어도 in) 문자열과 패턴(즉, 처음부터 끝까지)이 정확히 일치하지 않습니다. 또한 동일성 테스트를 정규식 검색으로 대체하면 패턴(및 귀하의 경우) 에 특수 문자(예: 패턴과 일치)가 포함될 때 원치 않는 결과가 발생할 수 있습니다 .grep -c "$2"grep"$3""$2"CSPorto01CSPorto.1

문제에 대한 해결책을 제안하는 것 외에도 AWK의 기능을 더 잘 활용하는 방법에 대한 예가 있습니다. 프로그램은 add_nurses.sh쉘 스크립트와 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).
  • 이 경우에는 비표준 쉘 기능이 실제로 필요하지 않습니다. 내가 사용한 [[ ... ]]것과 [ ... ]같은 이유로 ;#!/bin/sh

답변3

grep 9876문제는 그것이 존재한다는 것을 보는 것이라고 생각 9876하지만 숫자가 단어로 존재하는 경우에만 보고 싶습니다. -wID 번호를 조회할 때 이 스위치를 사용 하면 원하는 응답을 얻을 수 있습니다. 같은 이유로 또는 CSport에 존재하는 것으로 간주됩니다 . grep으로 전환하면 이 문제도 해결됩니다.CSportoCSporta-w

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

관련 정보