이 명령을 루프로 바꾸려면 어떻게 해야 합니까?

이 명령을 루프로 바꾸려면 어떻게 해야 합니까?

그래서 나한테는테마 폴더여기에는 다음 주제가 포함되어 있습니다.

  • 지리학
  • 수학

이러한 주제는 파일입니다. 각 시트에는 학생의 이름과 점수가 포함되어 있습니다.


예를 들어,

지리학을 위해

  • 마태복음 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스크립트가 실행되기 시작할 때 디렉터리가 비어 있다고 가정합니다(또는 스크립트가 디렉터리에 파일을 추가할 것이라고 가정합니다).

주어진 데이터(이름 중 하나의 철자 오류 포함)를 실행하면 다음 위치에 세 개의 파일이 생성됩니다 /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 스크립트를 사용하는 것이 더 좋지만 위의 방법은 루프에서 명령을 예약하는 가능한 방법입니다.

관련 정보