このコマンドをループに置き換えるにはどうすればよいですか?

このコマンドをループに置き換えるにはどうすればよいですか?

だから私にテーマフォルダこれには次のトピックが含まれます。

  • 地理学
  • 数学

これらのトピックはファイルです。各シートには学生の名前とスコアが含まれています。


例えば、

地理学のために

  • マタイ 15章
  • エレナ14

そして数学:

  • マタイ10章
  • エレナ19

私も一つ持っている学生フォルダ現在は空です。このフォルダの目的は、次のものを置くことです。

  1. ファイル名として学生名。
  2. すべての科目で学生が獲得したスコアです。

だからこれは私のコードです:

#### 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*/Matthewgrep/home/student/Matthew

Geo_Matthew=$(grep "Matthew" "$GEOGRAPHY" | cut -d' ' -f2) > "$studentMatthew"ジョブに出力を生成しない追加のリダイレクトがあるため、リダイレクトは出力$studentMatthewgrepファイルにリダイレクトし、コマンドの置換、変数、およびGeo_Matthew次を削除するだけですecho

シェルスクリプトの代わりにawkまたはPerlスクリプトを使用する方が良いですが、上記の方法はループ内でコマンドをスケジュールするための可能な方法です。

関連情報