これは私のスクリプトです。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.
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
1回の呼び出しで完全な処理を行います。このような:
#!/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")