Shell脚本求助:2个文本之间搜索匹配列,并输出结果到第3个文件
-
- 帖子: 6
- 注册时间: 2014-11-18 4:38
- 系统: win7
Shell脚本求助:2个文本之间搜索匹配列,并输出结果到第3个文件
刚刚开始接触bash script和使用gnuplot作图,下面是我面临的任务,请教大家,如何写脚本,满足下面的任务要求:
一共有2个txt数据文件,暂且称文件1为:exp.txt(实验数据),文件2为sim.txt(模拟结果)。
文件1:exp.txt里的内容、及格式化大致如下:
x-axis species5_mole
1.000 0.3
2.000 0.4
3.000 0.5
4.000 0.6
......... .....
x-axis species8_mole
1.000 0.2
2.000 0.3
3.000 0.35
4.000 0.4
......... .....
即:每一个data block里的第一行是x、y轴的label,label之间是一个空格分隔;从每个data block的第2行起,就是x、y轴各自的value,value之间也是一个空格分隔;每个data block之间由一个空行分隔;data block的个数会变,比如有时是10个,有时是15个,但都是预先给定好的。
文件2:sim.txt里的内容、及格式化大致如下:
x-axis species1 species2 species3 ... species100
0.00000000 1.15174695E-014 5.28281175E-001 2.28199430E-004 ... 2.28199430E-004
1.60281966 1.14743622E-014 5.28276072E-001 2.28322770E-004 ... 2.28199430E-004
3.28277311 1.08184960E-014 5.28270725E-001 2.28452003E-004 ... 2.28199430E-004
4.00000000 6.84286765E-015 5.28232698E-001 2.29371009E-004 ... 2.28199430E-004
.................. ............................ ........................... ............................. ... ............................
即:第1列是x轴,之后的列都是各个species的value;第一行的文字、及从第2行起的数值,彼此间都是由一个空格分隔;但文件2里的列数(比如100列)远远超过文件1里的data block数目。
我需要得到文件3:sim_reduce.txt,该文件里的内容、及格式化应该如下:
x-axis species5 species8 species11 species13 species14 ...
value value value value value value …
value value value value value value …
value value value value value value …
value value value value value value …
即:该文件3里只有那些在文件1里出现的species的模拟数据,也就是说,文件1里有N个data block,文件3里就有(N+1)个列(因为第1列是x轴);而且顺序相对应,就是说,对应文件1里第X个data block的模拟数据,应该位于文件3里的第(X+1)列。
一下子写了这么多,不知我是否表达清楚了。非常感谢,如果能行的话,将大大简化我的重复行劳动。
一共有2个txt数据文件,暂且称文件1为:exp.txt(实验数据),文件2为sim.txt(模拟结果)。
文件1:exp.txt里的内容、及格式化大致如下:
x-axis species5_mole
1.000 0.3
2.000 0.4
3.000 0.5
4.000 0.6
......... .....
x-axis species8_mole
1.000 0.2
2.000 0.3
3.000 0.35
4.000 0.4
......... .....
即:每一个data block里的第一行是x、y轴的label,label之间是一个空格分隔;从每个data block的第2行起,就是x、y轴各自的value,value之间也是一个空格分隔;每个data block之间由一个空行分隔;data block的个数会变,比如有时是10个,有时是15个,但都是预先给定好的。
文件2:sim.txt里的内容、及格式化大致如下:
x-axis species1 species2 species3 ... species100
0.00000000 1.15174695E-014 5.28281175E-001 2.28199430E-004 ... 2.28199430E-004
1.60281966 1.14743622E-014 5.28276072E-001 2.28322770E-004 ... 2.28199430E-004
3.28277311 1.08184960E-014 5.28270725E-001 2.28452003E-004 ... 2.28199430E-004
4.00000000 6.84286765E-015 5.28232698E-001 2.29371009E-004 ... 2.28199430E-004
.................. ............................ ........................... ............................. ... ............................
即:第1列是x轴,之后的列都是各个species的value;第一行的文字、及从第2行起的数值,彼此间都是由一个空格分隔;但文件2里的列数(比如100列)远远超过文件1里的data block数目。
我需要得到文件3:sim_reduce.txt,该文件里的内容、及格式化应该如下:
x-axis species5 species8 species11 species13 species14 ...
value value value value value value …
value value value value value value …
value value value value value value …
value value value value value value …
即:该文件3里只有那些在文件1里出现的species的模拟数据,也就是说,文件1里有N个data block,文件3里就有(N+1)个列(因为第1列是x轴);而且顺序相对应,就是说,对应文件1里第X个data block的模拟数据,应该位于文件3里的第(X+1)列。
一下子写了这么多,不知我是否表达清楚了。非常感谢,如果能行的话,将大大简化我的重复行劳动。
- astolia
- 论坛版主
- 帖子: 6703
- 注册时间: 2008-09-18 13:11
Re: Shell脚本求助:2个文本之间搜索匹配列,并输出结果到第3个文件
文件2和生成的文件3有什么关系?似乎只需要文件1就行了
文件1中每个数据块的第一列是否都相同?
文件1中每个数据块的第一列是否都相同?
- eexpress
- 帖子: 58428
- 注册时间: 2005-08-14 21:55
- 来自: 长沙
-
- 帖子: 6
- 注册时间: 2014-11-18 4:38
- 系统: win7
Re: Shell脚本求助:2个文本之间搜索匹配列,并输出结果到第3个文件
非常谢谢快速的回复。astolia 写了:文件2和生成的文件3有什么关系?似乎只需要文件1就行了
文件1中每个数据块的第一列是否都相同?
文件2与生成的文件3是包含与被包含关系,文件2包含文件3,因为文件2里有很多列是我不需要的(文件1、2都是原始data,我不想改动它们),而在文件3里所有的列都是我需要的。
至于文件3里有哪些列出现,是由文件1中每个数据块的第一行的那个speciesN_mole决定(N比如等于3、5、7等)。
文件1中每个数据块的第一列都相同。
-
- 帖子: 6
- 注册时间: 2014-11-18 4:38
- 系统: win7
Re: Shell脚本求助:2个文本之间搜索匹配列,并输出结果到第3个文件
非常谢谢快速的回复。eexpress 写了:没看出相同的行。。。
抱歉,可能我没说清楚:文件3里的那个value,其实都是数值(就像文件2里一样),只不过我省事起见写成了文字“value”。
- astolia
- 论坛版主
- 帖子: 6703
- 注册时间: 2008-09-18 13:11
Re: Shell脚本求助:2个文本之间搜索匹配列,并输出结果到第3个文件
这样?
代码: 全选
$ cat sim.txt
x-axis species1 species5 species8 species100
0.00000000 1.15174695E-014 5.28281175E-001 2.28199430E-004 2.28199430E-004
1.60281966 1.14743622E-014 5.28276072E-001 2.28322770E-004 2.28199430E-004
3.28277311 1.08184960E-014 5.28270725E-001 2.28452003E-004 2.28199430E-004
4.00000000 6.84286765E-015 5.28232698E-001 2.29371009E-004 2.28199430E-004
$
$ cat exp.txt
x-axis species5_mole
1.000 0.3
2.000 0.4
3.000 0.5
4.000 0.6
x-axis species8_mole
1.000 0.2
2.000 0.3
3.000 0.35
4.000 0.4
$
$ COLS="$(head -1 sim.txt | COLS="$(grep '^x-axis' exp.txt | sed 's/^x-axis //;s/_mole$//')" awk 'BEGIN{split(ENVIRON["COLS"],arr,/\n/)}{for(i=1;i<=NF;i++){for(j in arr){if($i==arr[j]){print i}}}}')" awk 'BEGIN{ORS="";split(ENVIRON["COLS"],arr,/\n/)}{print $1;for(i in arr){print " " $arr[i]}print "\n"}' sim.txt
x-axis species5 species8
0.00000000 5.28281175E-001 2.28199430E-004
1.60281966 5.28276072E-001 2.28322770E-004
3.28277311 5.28270725E-001 2.28452003E-004
4.00000000 5.28232698E-001 2.29371009E-004
-
- 帖子: 6
- 注册时间: 2014-11-18 4:38
- 系统: win7
Re: Shell脚本求助:2个文本之间搜索匹配列,并输出结果到第3个文件
非常感谢,针对上面这个例子(sim.txt、exp.txt)确实能用!astolia 写了:这样?代码: 全选
$ cat sim.txt x-axis species1 species5 species8 species100 0.00000000 1.15174695E-014 5.28281175E-001 2.28199430E-004 2.28199430E-004 1.60281966 1.14743622E-014 5.28276072E-001 2.28322770E-004 2.28199430E-004 3.28277311 1.08184960E-014 5.28270725E-001 2.28452003E-004 2.28199430E-004 4.00000000 6.84286765E-015 5.28232698E-001 2.29371009E-004 2.28199430E-004 $ $ cat exp.txt x-axis species5_mole 1.000 0.3 2.000 0.4 3.000 0.5 4.000 0.6 x-axis species8_mole 1.000 0.2 2.000 0.3 3.000 0.35 4.000 0.4 $ $ COLS="$(head -1 sim.txt | COLS="$(grep '^x-axis' exp.txt | sed 's/^x-axis //;s/_mole$//')" awk 'BEGIN{split(ENVIRON["COLS"],arr,/\n/)}{for(i=1;i<=NF;i++){for(j in arr){if($i==arr[j]){print i}}}}')" awk 'BEGIN{ORS="";split(ENVIRON["COLS"],arr,/\n/)}{print $1;for(i in arr){print " " $arr[i]}print "\n"}' sim.txt x-axis species5 species8 0.00000000 5.28281175E-001 2.28199430E-004 1.60281966 5.28276072E-001 2.28322770E-004 3.28277311 5.28270725E-001 2.28452003E-004 4.00000000 5.28232698E-001 2.29371009E-004
请教astolia:
上面这个例子(sim.txt、exp.txt)里的数据\格式,都是我为了举例而给的假想出来的。为什么我使用同样的命令对我下面实际的例子,就不行了呢?
实际例子:
cat exp.txt
hab[mm] A1_molefraction[-]
0.42587 0.11844
3.12303 0.105674
4.40063 0.0801418
5.11041 0.058156
hab[mm] A1C2H_molefraction[-]
3.26519 4.94373e-05
4.94664 0.000304553
6.07465 0.000609801
7.07754 0.000347735
hab[mm] A2_molefraction[-]
3.26968 3.55234e-05
4.9572 0.000140069
5.80174 0.000262505
6.94614 0.000157304
cat sim.txt
x[mm] C AR A1 A1- A1C2H A1C2H-M
0.00000000E+000 4.03712310E-016 3.82186262E-001 9.16676140E-002 2.03271992E-006 1.83264579E-004 2.43353082E-008
1.06128907E-004 4.03727668E-016 3.82183696E-001 9.16648357E-002 2.03297647E-006 1.83291555E-004 2.43388851E-008
2.16313406E-004 4.03768634E-016 3.82181032E-001 9.16619510E-002 2.03324936E-006 1.83319566E-004 2.43426214E-008
3.33182039E-004 4.03839828E-016 3.82178206E-001 9.16588910E-002 2.03354608E-006 1.83349280E-004 2.43466096E-008
文件3里应该只有3列:
x[mm] A1 A1C2H
我使用的命令是:
COLS="$(head -1 sim.txt | COLS="$(grep '^hab' exp.txt | sed 's/^hab[mm] //;s/_molefraction[-]$//')" awk 'BEGIN{split(ENVIRON["COLS"],arr,/\n/)}{for(i=1;i<=NF;i++){for(j in arr){if($i==arr[j]){print i}}}}')" awk 'BEGIN{ORS="";split(ENVIRON["COLS"],arr,/\n/)}{print $1;for(i in arr){print " " $arr}print "\n"}' sim.txt
我目前唯一能想到的不成功的可能原因是:是不是因为sim.txt、exp.txt里每一行的数据之间有的是tab分隔,有的是空格分隔?
- astolia
- 论坛版主
- 帖子: 6703
- 注册时间: 2008-09-18 13:11
Re: Shell脚本求助:2个文本之间搜索匹配列,并输出结果到第3个文件
你把整个命令拆分出来看,除去变量赋值传递部分,有这么三个主要步骤
grep '^hab' exp.txt | sed 's/^hab[mm] //;s/_molefraction[-]$//'
head -1 sim.txt | awk 'BEGIN{split(ENVIRON["COLS"],arr,/\n/)}{for(i=1;i<=NF;i++){for(j in arr){if($i==arr[j]){print i}}}}'
awk 'BEGIN{ORS="";split(ENVIRON["COLS"],arr,/\n/)}{print $1;for(i in arr){print " " $arr}print "\n"}' sim.txt
第一步是从exp.txt中提取出列名
第二步是从sim.txt的第一行中,将第一步提取出列名转换成对应的序号
第三步是对sim.txt的每一行,只输出第二步中得到的列序号
你的问题出在两方面,一是第一步中对列名的提取,二是你所说的列的分隔
因为sed用的是正则表达式,[和]在正则表达式中有特殊的含义,你的情况下需要转义。也就是换成\[和\]
列分隔的话,需要给二三步中的awk加个参数。用awk -F '(\t| )+',表示列分隔符是至少一个tab或空格。如果确定没有连续的tab或空格作分隔的话,可以去掉+号。这也是个正则表达式,如果对正则表达式不熟悉,可以找找看那篇正则表达式30分钟入门教程
grep '^hab' exp.txt | sed 's/^hab[mm] //;s/_molefraction[-]$//'
head -1 sim.txt | awk 'BEGIN{split(ENVIRON["COLS"],arr,/\n/)}{for(i=1;i<=NF;i++){for(j in arr){if($i==arr[j]){print i}}}}'
awk 'BEGIN{ORS="";split(ENVIRON["COLS"],arr,/\n/)}{print $1;for(i in arr){print " " $arr}print "\n"}' sim.txt
第一步是从exp.txt中提取出列名
第二步是从sim.txt的第一行中,将第一步提取出列名转换成对应的序号
第三步是对sim.txt的每一行,只输出第二步中得到的列序号
你的问题出在两方面,一是第一步中对列名的提取,二是你所说的列的分隔
因为sed用的是正则表达式,[和]在正则表达式中有特殊的含义,你的情况下需要转义。也就是换成\[和\]
列分隔的话,需要给二三步中的awk加个参数。用awk -F '(\t| )+',表示列分隔符是至少一个tab或空格。如果确定没有连续的tab或空格作分隔的话,可以去掉+号。这也是个正则表达式,如果对正则表达式不熟悉,可以找找看那篇正则表达式30分钟入门教程
-
- 帖子: 6
- 注册时间: 2014-11-18 4:38
- 系统: win7
Re: Shell脚本求助:2个文本之间搜索匹配列,并输出结果到第3个文件
非常感谢astolia!学习了!试了试,确实可行!
我只还有一个小问题:
如何调整第二、三步(我估计应该是调整那个for循环吧),才能使文件3里的列的顺序和exp.txt里的数据块的顺序一致,即:文件3里第一列是x[mm],第二列是A1,第三列是A1C2H……?(因为exp.txt的实际情况是里面包含30多块数据块)
我只还有一个小问题:
如何调整第二、三步(我估计应该是调整那个for循环吧),才能使文件3里的列的顺序和exp.txt里的数据块的顺序一致,即:文件3里第一列是x[mm],第二列是A1,第三列是A1C2H……?(因为exp.txt的实际情况是里面包含30多块数据块)
- astolia
- 论坛版主
- 帖子: 6703
- 注册时间: 2008-09-18 13:11
Re: Shell脚本求助:2个文本之间搜索匹配列,并输出结果到第3个文件
把第二步两个for循环对调一下就行了
-
- 帖子: 6
- 注册时间: 2014-11-18 4:38
- 系统: win7
Re: Shell脚本求助:2个文本之间搜索匹配列,并输出结果到第3个文件
谢谢。如果是下面这样对调的话:
COLS="$(head -1 sim.txt | COLS="$(grep '^hab' exp.txt | sed 's/^hab\[mm\] //;s/_molefraction\[-\]$//')" awk -F '(\t| )+' 'BEGIN{split(ENVIRON["COLS"],arr,/\n/)}{for(j in arr){for(i=1;i<=NF;i++){if($i==arr[j]){print i}}}}')" awk -F '(\t| )+' 'BEGIN{ORS="";split(ENVIRON["COLS"],arr,/\n/)}{print $1;for(i in arr){print " " $arr}print "\n"}' sim.txt
我试了试,似乎还是不行呀。
COLS="$(head -1 sim.txt | COLS="$(grep '^hab' exp.txt | sed 's/^hab\[mm\] //;s/_molefraction\[-\]$//')" awk -F '(\t| )+' 'BEGIN{split(ENVIRON["COLS"],arr,/\n/)}{for(j in arr){for(i=1;i<=NF;i++){if($i==arr[j]){print i}}}}')" awk -F '(\t| )+' 'BEGIN{ORS="";split(ENVIRON["COLS"],arr,/\n/)}{print $1;for(i in arr){print " " $arr}print "\n"}' sim.txt
我试了试,似乎还是不行呀。
- astolia
- 论坛版主
- 帖子: 6703
- 注册时间: 2008-09-18 13:11
Re: Shell脚本求助:2个文本之间搜索匹配列,并输出结果到第3个文件
我这边是没问题的,你那边的输出是啥?你又想得到什么输出?