だから私にテーマフォルダこれには次のトピックが含まれます。
- 地理学
- 数学
これらのトピックはファイルです。各シートには学生の名前とスコアが含まれています。
例えば、
地理学のために
- マタイ 15章
- エレナ14
そして数学:
- マタイ10章
- エレナ19
私も一つ持っている学生フォルダ現在は空です。このフォルダの目的は、次のものを置くことです。
- ファイル名として学生名。
- すべての科目で学生が獲得したスコアです。
だからこれは私のコードです:
#### Subjects folder #####
GEOGRAPHY="/home/subject/geography"
MATH="/home/subject/math"
##### Registration student #####
studentMatthew="/home/student/Matthew"
Geo_Matthew=$(grep "Matthew" "$GEOGRAPHY" | cut -d' ' -f2) > "$studentMatthew"
Math_Matthew=$(grep "Matthew" "$MATH" | cut -d' ' -f2) > "$studentMatthew"
studentElena="/home/student/Elena"
Geo_Elena=$(grep "Elena" "$GEOGRAPHY" | cut -d' ' -f2) > "$studentElena"
Math_Elena=$(grep "Elena" "$MATH" | cut -d' ' -f2) > "$studentElena"
##### SHOW RESULT #####
echo "Geography" >> "$studentMatthew" "$Geo_Matthew"
echo "Math" >> "$studentMatthew" "$Geo_Matthew"
echo "Geography" >> "$studentElena" "$Geo_Elena"
echo "Math" >> "$studentElena" "$Math_Elena"
これは非常にうまく機能します。しかし、このように書くのは良い考えではありません。
私が別の学生を追加する場合は、Patrickと言ってください。手動地理と数学のスコアを追加します。
だからそれは次のようになります:
##### Registration Patrick #####
studentPatrick="/home/student/Patrick"
Geo_Patrick=$(grep "Patrick" "$GEOGRAPHY" | cut -d' ' -f2) > "$studentPatrick"
Math_Patrick=$(grep "Patrick" "$MATH" | cut -d' ' -f2) > "$studentPatrick"
##### SHOW RESULT PATRICK #####
echo "Geography" >> "$studentPatrick" "$Geo_Patrick"
echo "Math" >> "$studentPatrick" "$Math_Patrick"
そしてそれは非常に重複するでしょう...
だから私は知りたいです。
このコードをループにリファクタリングする方法はありますか?では、新しい生徒を追加したら、手動で書き直す必要はありませんか?
答え1
for subjfile in /home/subject/*; do
awk -v subj="$(basename "$subjfile")" '{ print subj, $2 >>"/home/student/" $1 }' "$subjfile"
done
これはすべてのテーマファイルを繰り返します。値は、利用可能なテーマに応じて等にすることができ$subjfile
ます。/home/subject/Math
/home/subject/Geography
プログラムはawk
順番に各ファイルを開き、トピック名($subjfile
パスMath
名の「basename」などGeography
)とそのトピックのタグ($subjfile
ファイルの列2)を印刷します。
"/home/student/" $1
これは、あるパス名に書き込まれます/home/student
。$1
はい最初ファイルの列は$subjfile
学生の名前です。
このコードは、student
スクリプトが実行を開始したときにディレクトリが空であると仮定します(またはスクリプトがディレクトリにファイルを追加すると仮定します)。
指定されたデータ(名前の1つのスペルエラーを含む)を実行すると、次の場所に3つのファイルが生成されます/home/student
。
$ cat Elena
Geography 14
Math 19
$ cat Mattew
Geography 15
$ cat Matthew
Math 10
学生名は以下のファイルから選択され、/home/subject
スクリプトにハードコードされません。また、さまざまなテーマは、/home/subject
ディレクトリで利用可能なファイルによって異なります。
以下に触れることなくこれを行いますかawk
?
for subjfile in /home/subject/*; do
subject=$( basename "$subjfile" )
while read -r name marks; do
printf '%s %d\n' "$subject" "$marks" >>"/home/student/$name"
done <"$subjfile"
done
答え2
私の考えでは、あなたは次のことをしました。
# loop over all files in the student directory
for studentfile in /home/student/*; do
# take just the name of the student (the file name without the path)
studentname="${studentfile##*/}"
# uncomment the next line to clear the student files before populating them
# > "$studentfile"
# loop over all subject files
for subject in /home/subject/*; do
# again, remove the path
subject="${subject##*/}"
grep "$studentname" "$subject" | cut -d' ' -f2 >> "$studentfile"
done
done
生徒と科目のファイル名がファイルで使用されているラベルとまったく同じで、各生徒のファイルがすでに存在しているとします。
拡張は、最長の接頭辞一致が削除された値を使用します${var##*/}
。つまり、パスだけを残します。学生の場合は出力リダイレクトにのみ使用されるため、両方が必要です。$var
*/
Matthew
grep
/home/student/Matthew
Geo_Matthew=$(grep "Matthew" "$GEOGRAPHY" | cut -d' ' -f2) > "$studentMatthew"
ジョブに出力を生成しない追加のリダイレクトがあるため、リダイレクトは出力$studentMatthew
をgrep
ファイルにリダイレクトし、コマンドの置換、変数、およびGeo_Matthew
次を削除するだけですecho
。
シェルスクリプトの代わりにawkまたはPerlスクリプトを使用する方が良いですが、上記の方法はループ内でコマンドをスケジュールするための可能な方法です。