如何从文件中求和并在linux中的另一个文件中以特定方式移动?

时间:2011-11-16 23:25:03

标签: linux bash sed

Acttualy这是我的任务。我有三个四个文件,由学生记录相关。每个文件有两三个学生记录。像这样

Course Name:Opreating System
Credit: 4
123456 1 1 0 1 1 0 1 0 0 0 1 5 8 0 12 10 25
243567 0 1 1 0 1 1 0 1 0 0 0 7 9 12 15 17 15

每个文件都有不同的coursename。我做了每个coursename和studentid移动 在一个文件中,但现在我不知道如何添加所有标记并移动到同一个地方的另一个文件是id?你能告诉我怎么做吗?

看起来像这样:

Student# Operating Systems JAVA C++ Web Programming GPA
123456       76             63   50       82        67.75
243567       80             -    34       63          59

我确实喜欢这个:

#!/bin/sh

find ~/2011/Fall/StudentsRecord -name "*.rec" | xargs grep -l 'CREDITS' | xargs cat > rsh1

echo "STUDENT ID" > rsh2

sed -n /COURSE/p rsh1 | sed 's/COURSE NAME: //g' >> rsh2

echo "GPA" >> rsh2

sed -e :a -e '{N; s/\n/       /g; ta}' rsh2 > rshf

sed '/COURSE/d;/CREDIT/d' rsh1 | sort -uk 1,1 | cut -d' ' -f1 | paste -d' ' >> rshf

1 个答案:

答案 0 :(得分:2)

一些评论和一些指示:

为每行不明显的代码添加“注释”会有所帮助;即像mv f f.bak这样的代码不需要评论,但我不确定你的许多代码行的意图是什么。

您使用'#'字符插入注释,例如

#  concatenate all files that contain the word CREDITS into a file called rsh1
find ~/2011/Fall/StudentsRecord -name "*.rec" | xargs grep -l 'CREDITS' | xargs cat > rsh1

另请注意,当示例文件显示混合大小写时,您始终对搜索目标(即CREDITS)使用全部大写。为搜索目标使用正确的大小写,即

`grep -l 'Credits'` 

或告诉grep -i(gnore case),即

`grep -il 'Credits'

你的行

sed -n /COURSE/p rsh1 | sed 's/COURSE NAME: //g' >> rsh2

可以减少到1次调用sed(并且你有同样的案例混淆事情),试试

sed -n '/COURSE/i{;s/COURSE NAME: //gip;}' rsh1 >> rsh2

这意味着(-n默认不打印每一行),

`gip` = global substitute, 
      = ignore case in matching
        print only lines where substituion was made

所以你正在为任何包含COURSE的行编辑字符串COURSE NAME,并且只打印那些行'(你可能不需要'g'(全局)说明符,因为你只需要1个实例每行)

你的行

 sed -e :a -e '{N; s/\n/       /g; ta}' rsh2 > rshf

实际看起来相当不错,非常先进,你试图将每两条线“折叠”成一条线,对吗?

但是,

sed '/COURSE/d;/CREDIT/d' rsh1 | sort -uk 1,1 | cut -d' ' -f1 | paste -d' ' >> rshf

我真的对此感到困惑,这是你试图让学生得分的地方吗? (我猜不会嵌入排序)。为什么你认为你需要一种排序,

虽然可以在sed中执行算术,但它非常难以实现,因此您可以使用bash变量来计算值,也可以使用unix工具来处理文本并执行逻辑和数学运算。数据显示,awk或perl在这里浮现在脑海中

无论如何,每个得分总计的一个解决方案是使用awk

 echo "123456 1 1 0 1 1 0 1 0 0 0 1 5 8 0 12 10 25" |\
 awk '{for (i=2;i<=NF;i++) { tot+=$i }; print $1 "\t" tot }'  

将为您提供如何进行此操作的线索。

Awk有为每个文件填充的预定义变量,以及它读取的每行文本,即

$0 = complete line of text (as defined by the internal variables RS (RecordSeparator)
                             which defaults to '\n' new-line char, the unix end-of-line char

$1 = first field in text (as defined by the internal variables FS (FieldSeparator)
                           which defaults to (possibly multiple) space chars OR tab char
                          a line with 2 connected spaces chars and 1 tab char has 3 fields)

NF = Number(of)Fields in current line of data (again fields defined by value of FS as 
                                                described above)

(there are many others, besides, $0, $n, $NF, $FS, $RS).

你可以通过在示例代码中使用变量来编程增加$ 1,$ 2,$ 3等值,例如$ i(i是一个介于2和NF之间的数字的变量。前导'$' 说给我字段i的价值(即2美元,3美元,4美元......)

顺便提一下,使用单个awk脚本可以轻松解决您的问题,但显然,您应该了解cat, cut, grep等,这是一个非常有价值的目标。

我希望这会有所帮助。