我的文件中有两个字段:学生和教师。它们由分号分隔,我想找到哪些单身学生有两个不同的老师。
jdoe;ateacher
jdoe;bteacher
jsmith;cteacher
bbrown;dteacher
dholden;eteacher
将传送至:
jdoe;ateacher
jdoe;bteacher
我怎样才能用外壳做到这一点?
笔记:这是家庭作业。我不是在寻找确切的答案,只是不确定从哪里开始。我已经解析并将其从文件中传输到我需要的字段中,现在我只需要找到重复的内容,但我不知道如何开始。
答案1
假设您显示的文件格式是严格的,如果学生有 2 个不同的老师,则该学生只会显示两次,并且给定学生的条目始终彼此相邻,您可以使用此命令来查找所有重复项。该文件中的重复项表示一个学生有多个老师,因此我们可以忽略这一事实。
例子
$ awk -F';' '{ print $1 }' file | uniq -d
jdoe
这将解析文件file
并使用awk
字段分隔符开关将其分割-F';'
。然后我们指示awk
仅打印第一个字段,即学生的姓名。然后,我们将该输出通过管道传输uniq
并告诉它仅打印重复的行。
然后,我们可以在 for 循环中使用此信息,并且仅打印上面命令返回的列表中包含学生的行。以下是循环的粗略结构:
$ for i in $(..cmd from above..); do
... print lines that contain "$i" ...
done
在这里,我们获取初始命令的输出awk
,并在 Bash shell 中使用 for 循环对其进行循环。这通常是大多数人刚开始时会采取的方法。
例子
$ for i in $(awk -F';' '{ print $1 }' file | uniq -d); do \
grep "^$i;" file; done
jdoe;ateacher
jdoe;bteacher
这种方法虽然有效,但也存在一些问题。如果文件名包含空格,此方法将失败。您可以使用 while 循环切换到更复杂的方法。
$ while read; do grep "^$i;" file; done \
< <(awk -F';' '{ print $1 }' file | uniq -d)
jdoe;ateacher
jdoe;bteacher
在这里,我们从命令中获取输出并将其传递到 while 循环中,如下所示:
$ while read; do .... ; done < <(...our command...)
这样做的好处是可以使用此表示法创建临时文件,并将所有结果作为行传递到 while 循环中。因此,该read
命令现在只需解析由换行符分割的结果,而不是 for 循环实现中的空格。
< <(...command...)
例子
以下是 for 循环和空格所发生的情况:
$ for i in jdoe john smith jjill;do echo "$i"; done
jdoe
john
smith
jjill