如何将不存在的值替换为0?

时间:2019-01-29 06:26:47

标签: bash shell scripting

所以我有一个主题文件夹,位于 / home / subject 中,其中包含诸如:

  • 地理
  • 数学

这些主题是文件。 并且每一个都包含带有标记的学生姓名


例如,它将是

对于地理

  • 问题15
  • Elena 14

和数学

  • 马太福音10
  • Elena 19

我还有一个 student文件夹,位于 / home / student 中,目前为空。 这个文件夹的目的是放在其中:

  1. 学生的姓名作为文件的名称;
  2. 该学生获得的所有子项目的分数。

这是我的代码

rm /home/student/*
for subjectFile in /home/subject/*; do
awk -v subject="$(basename "$subjectFile")" '{ print subject, $2 >>"/home/student/" $1 }' "$subjectFile"
done

此循环遍历主题文件夹内的所有主题文件。 $ subjectFile值类似于:

  • / home / subject / Math
  • / home / subject / Geograpy
  • / home / subject /(MySubject)
  • 等等。=>取决于可用的主题。

然后,获取每个主题文件的基本名称:

  • 数学
  • 地理
  • (...)

然后在通过主题文件第一列获得的我的学生姓名中打印第二列的结果,标记号:因此,在本示例中,对于主题< strong>地理,我会得到 Matthew

我也不想简单地无限追加结果,但是每次运行此脚本时覆盖以前的结果,所以我输入了:rm / home / student / *,以擦除任何结果学生档案,然后再进行追加。

这很好用。


但是我有一个请求,

如果未定义该学生的学科标记,我该如何使其用0代替?? 一个学生没有针对某个特定学科获得任何分数,而其他人则获得了分数?


例如:

对于地理

  • 问题15

和数学

  • 马太福音10
  • Elena 19

对于 Elena , 这将在学生文件夹的内部创建一个Elena文件:

  • 地理0
  • 数学19

2 个答案:

答案 0 :(得分:2)

使用纯

进行简单分发

尝试:这将在/tmp中创建一棵小树:

cd /tmp && tar -zxvf <(base64 -d <<eof
H4sIAFUFUFwAA+3XXU6EMBQF4D6ziu7A/l2uLsBHE7eAYwUMghlKnNm9EKfEEHUyBpg4nu+lJJDQ
5HBK226KpqmuxJJUj4mGUTOpz2MktHXG9RdEWiitrWUhadFZHXRtyLZSiidflbsfnjt2/49qP/Jv
u4dnvwnLfAcn5K9JuT5/w0zIfw2T/F+yUMz+jiHg1Lnv87c09j9l0+dvU3JCqtln8oV/nv9dFkLh
36RWyW3l60zqm+S+KCspNSfnnhwsbtJ/X+dV2c68BBzvfzr2nw33/XeWUvR/DWP/WcYFgOICcI0F
4OJN+p/7Jt9mr8V+znec8P8/7P8cK4v+r2HsP8X6u1h/Qv0vX+x/6B59ff7znyFNw/5fGZz/AQAA
AAAAAAAAAAB+7R1PsalnACgAAA==
eof
)

这将创建(并且由于tar命令中的-v标志而在终端中打印):

school/
school/subject/
school/subject/math
school/subject/english
school/subject/geography
school/student/

快速概述:

cd /tmp/school/subject/
grep . * | sort -t: -k2

将呈现:

geography:Elena 14
english:Elena 15
math:Elena 19
math:Matthew 10
geography:Matthew 15
english:Matthew 17 
geography:Phil  15
math:Phil  17
english:Phil  18

构建学生统计文件:

cd /tmp/school
rm student/*
for file in subject/*;do
    subj=${file##*/}
    while read student note ;do
        echo >>student/${student,,} ${subj^} $note
    done < $file
done

注意::使用${VARNAME^}高位第一个字符,使用${VARNAME,,}低位所有字符串。因此,文件名是小写字母,并且主题在学生文件中变为大写。

那么现在:

ls -l student
total 12
-rw-r--r-- 1 user user 32 jan 29 08:57 elena
-rw-r--r-- 1 user user 32 jan 29 08:57 matthew
-rw-r--r-- 1 user user 32 jan 29 08:57 phil

cat student/phil
English 18
Geography 15
Math 17

然后,现在:搜索缺少的符号

for file in student/*;do
    for subj in subject/*;do
        subj=${subj##*/}
        grep -q ^${subj^}\  $file || echo ${subj^} 0 >> $file
      done
  done

可以对此进行测试(这将在所有文件中随机删除0或1个标记):

for file in subject/*;do
    ((val=1+(RANDOM%4)))
    ((val<4)) && sed ${val}d -i $file
  done

然后运行:

cd /tmp/school
rm student/*
for file in subject/*;do
    subj=${file##*/}
    while read student note ;do
        echo >>student/${student,,} ${subj^} $note
    done < $file
done
for file in student/*;do
    for subj in subject/*;do
        subj=${subj##*/}
        grep -q ^${subj^}\  $file || echo ${subj^} 0 >> $file
      done
  done

好,现在:

grep ' 0$' student/*
student/matthew:Geography 0

注意::由于我$RANDOM的使用,您的测试结果可能有所不同;-)

另一个方法:又走了两个步骤

第一步:建立学生名单,然后立即以0表示法创建学生文件:

cd /tmp/school
rm student/*
declare -A students
for file in subject/* ;do
    while read student mark ;do
        [ "$student" ] && students[$student]=
      done <$file
  done
for file in subject/*;do
    class=(${!students[@]})
    while read student mark ;do
        subj=${file##*/}
        echo >> student/${student,,} ${subj^} $mark
        class=(${class[@]/$student})
      done <$file
    for student in ${class[@]};do
        echo >>  student/${student,,} ${subj^} 0
      done
  done

统计工具

为了娱乐,有很多 bashisms 且没有创建文件,但有一个漂亮的转储工具:

#!/bin/bash

declare -A students
declare subjects=() sublen=0 stdlen=0
for file in subject/* ;do                               # read all subject files
    subj=${file##*/}
    subjects+=($subj)                                     # Add subject to array
    sublen=$(( ${#subj} > sublen ? ${#subj} : sublen )) # Max subject string len
    declare -A mark_$subj                   # Create subject's associative array
    while read student mark ;do
    stdlen=$(( ${#student} > $stdlen ? ${#student} : stdlen ))
        [ "$student" ] && {                                   # Skip empty lines
        ((students[$student]++))                     # Count student's marks
        printf -v mark_$subj[$student] "%d" $mark     # Store student's mark
    }
    done <$file
  done

printf -v formatstr %${#subjects[@]}s;  # prepare format string for all subjects
formatstr="%-${stdlen}s %2s ${formatstr// / %${sublen}s}"

printf -v headline "$formatstr" Student Qt "${subjects[@]}"
echo "$headline"                                               # print head line
echo "${headline//[^ ]/-}"                                # underscore head line

for student in ${!students[@]};do                   # Now one line by student...
    marks=()                                                       # Clear marks
    for subject in ${subjects[@]};do    
        eval "marks+=(\${mark_$subject[\$student]:-0})"  # Add subject mark or 0
    done
    printf "$formatstr\n" $student ${students[$student]} ${marks[@]}
done

这可能会打印出以下内容:

Student Qt    english geography      math
------- --    ------- ---------      ----
Phil     2         18        15         0
Matthew  3         17        15        10
Elena    2          0        14        19

Nota

此脚本是为 bem v4.4.12 构建的,并已在 bem v5.0 中进行了测试。

>

更多

您可以下载更大的演示脚本:scholl-averages-demo.sh(在浏览器as text .txt中查看)。

始终纯bash 不带叉子,但带

  • 学生平均水平,学科平均水平和总体平均水平,以假浮点数
  • 主题和学生按字母顺序排序
  • 在学生姓名中支持UTF-8

Student Qt        art   biology   english geography   history      math  Average
------- --        ---   -------   ------- ---------   -------      ----  -------
Elena    5         12         0        15        14        17        19    12.83
Iñacio   6         12        15        19        18        12        14    15.00
Matthew  5         19        18        17        15        17         0    14.33
Phil     5         15        19        18         0        13        17    13.67
Renée    6         14        19        18        17        18        15    16.83
Theresa  5         17        14         0        12        17        18    13.00
William  6         17        17        15        15        13        14    15.17
------- --        ---   -------   ------- ---------   -------      ----  -------
Avgs     7      15.14     14.57     14.57     13.00     15.28     13.86    14.40

答案 1 :(得分:1)

我会这样做。首先为每个学生制作空文件:

cat /home/subject/* | cut -d' ' -f1 | sort -u | while read student_name; do > /home/students/$student ; done

然后,我将逐一检查并添加标记:

for student in `ls /home/students` ; do
    for file in /home/subjects/* ; do
        subject="`basename $file`"
        mark="`egrep "^$student [0-9]+" $file | cut -d' ' -f2`"
        if [ -z "$mark" ]; then
            echo "$subject 0" >> /home/students/$student
        else
            echo "$subject $mark" >> /home/students/$student
        fi
    done
done

反正如此