如何将这些指令变成循环?

如何将这些指令变成循环?

所以我有一个主题文件夹其中包含以下主题:

  • 地理
  • 数学

这些主题是文件。每一张都包含一名学生的名字和他的分数。


例如,

对于地理

  • 马太 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"

这非常有效。但这样写并不是一个很好的做法。

因为如果我添加另一个学生,比如说帕特里克,我就必须手动添加他的地理和数学分数。


所以它会是:

##### 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、 ieMath或中路径名的“基本名称” Geography),后跟该主题中的标记($subjfile文件的第 2 列)。

这将被写入到"/home/student/" $1which is 下的路径名/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##*/}的值,即仅留下路径。对于学生来说,我们需要两者,因为我们仅使用but来进行输出重定向。$var*/Matthewgrep/home/student/Matthew

请注意,您的作业Geo_Matthew=$(grep "Matthew" "$GEOGRAPHY" | cut -d' ' -f2) > "$studentMatthew"中有一个额外的重定向,该作业不会创建任何输出,因此重定向仅截断$studentMatthew.您只需将 的输出重定向grep到文件并删除命令替换、变量Geo_Matthew和后面的echo.

使用 awk 或 Perl 脚本而不是 shell 脚本会更好,但上面是安排循环中命令的可能方法。

相关内容