이것은 내 스크립트입니다.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
하지만 스크립트가 두 문제에 대해 도움이 필요하지 않거나 동일한 위치를 가정하기를 원합니다 ! 미리 감사드립니다 :)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"
수행하는 것은 기본적으로( 적어도 in) 문자열과 패턴(즉, 처음부터 끝까지)이 정확히 일치하지 않습니다. 또한 동일성 테스트를 정규식 검색으로 대체하면 패턴(및 귀하의 경우) 에 특수 문자(예: 패턴과 일치)가 포함될 때 원치 않는 결과가 발생할 수 있습니다 .grep -c "$2"
grep
"$3"
"$2"
CSPorto01
CSPorto.1
문제에 대한 해결책을 제안하는 것 외에도 AWK의 기능을 더 잘 활용하는 방법에 대한 예가 있습니다. 프로그램은 add_nurses.sh
쉘 스크립트와 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
). - 이 경우에는 비표준 쉘 기능이 실제로 필요하지 않습니다. 내가 사용한
[[ ... ]]
것과[ ... ]
같은 이유로 ;#!/bin/sh
답변3
grep 9876
문제는 그것이 존재한다는 것을 보는 것이라고 생각 9876
하지만 숫자가 단어로 존재하는 경우에만 보고 싶습니다. -w
ID 번호를 조회할 때 이 스위치를 사용 하면 원하는 응답을 얻을 수 있습니다. 같은 이유로 또는 CSport
에 존재하는 것으로 간주됩니다 . grep으로 전환하면 이 문제도 해결됩니다.CSporto
CSporta
-w
a=$(awk -F "[:]" '{print $3}' nurses.txt | grep -cw "$3")