如何在循环中使用 awk 命令生成多个细化数据文件
How to use the awk command in a loop to produce several thinned data files
我有几个包含 8 列和 120,000 行的大型数据文件。现在我想从第 100 行开始每 200 行保留 1 行。我的脚本文件 thin.sh 为:
awk '(NR%200==100)' original_file > thinned_file
但是,现在我有30个原始文件,这意味着我必须一点一点地修改命令30次,原始文件的名称相似:
data.0000.dat, data.0001.dat data.0002.dat, ..., data.0029.dat
我想一定有某种方法可以将 awk
命令嵌入到循环中以实现我的目标,可能是这样的:
for(i=0;i<30;i++);
do
awk '(NR%200==100)' data.$i.dat > data.$i_thinned.dat
done
但是我发现文件名中$i
前面有两位00
。我可以使用 sprintf("%s")
什么的吗?如果是这样,awk
和sprinf
的顺序怎么安排?
我使用 ubuntu 和 bash.
带序列:
for i in $(seq -f %04g 1 29); do
awk 'NR % 200 == 100' "data.${i}.dat" > "data.${i}_thinned.dat"
done
或者 bash:
for i in {0001..0029}; do
第一个片段中的引号并不是绝对必要的,因为我们知道 $i
不包含任何恶意内容,但最好对 shell 脚本中的扩展持偏执态度。 "data.${i}_thinned.dat"
中的大括号是必需的,因此 shell 不会寻找要使用的变量 $i_thinned
。它们在 "data.${i}.dat"
中不是绝对必要的,因为 shell 变量名称中不能包含 .
,但一致性很好。
成分(GAWK)
1 FNR
- 当前文件中的记录数
1 match
- 匹配正则表达式字符串并可以将组捕获到数组中。
1 print
- 打印以下数据(如果提供 none 则默认为当前记录)
1 *.dat
- 当前目录中所有以 .dat 结尾的文件。
说明
- 条件块检查当前文件中的当前记录数除以200余100
- 如果是,那么 运行 下一个区块
{..}
- 获取当前文件名并匹配到最后一个点,将在此之前的所有内容与
(.*)
捕获到数组 a
.
- 使用捕获的日期
a[1]
打印到文件中,扩展名为 _thinned.dat
- 最后在最后加上
*.dat
即可读取当前目录下的所有.dat文件
结果代码
gawk '(FNR%200==100){match(FILENAME,/(.*)\./,a);print >(a[1]"_thinned.dat")}' *.dat
您只需要:
awk 'FNR==1{close(out); out=FILENAME; sub(/\.dat/,"_thinned&",out)} (FNR%200==100){print > out}' data.[0-9][0-9][0-9][0-9].dat
我使用 data.[0-9][0-9][0-9][0-9].dat
作为文件名通配模式而不是 data.*.dat
,以防您在之前生成所有“_thinned”文件的同一目录中重新运行脚本。
我有几个包含 8 列和 120,000 行的大型数据文件。现在我想从第 100 行开始每 200 行保留 1 行。我的脚本文件 thin.sh 为:
awk '(NR%200==100)' original_file > thinned_file
但是,现在我有30个原始文件,这意味着我必须一点一点地修改命令30次,原始文件的名称相似:
data.0000.dat, data.0001.dat data.0002.dat, ..., data.0029.dat
我想一定有某种方法可以将 awk
命令嵌入到循环中以实现我的目标,可能是这样的:
for(i=0;i<30;i++);
do
awk '(NR%200==100)' data.$i.dat > data.$i_thinned.dat
done
但是我发现文件名中$i
前面有两位00
。我可以使用 sprintf("%s")
什么的吗?如果是这样,awk
和sprinf
的顺序怎么安排?
我使用 ubuntu 和 bash.
带序列:
for i in $(seq -f %04g 1 29); do
awk 'NR % 200 == 100' "data.${i}.dat" > "data.${i}_thinned.dat"
done
或者 bash:
for i in {0001..0029}; do
第一个片段中的引号并不是绝对必要的,因为我们知道 $i
不包含任何恶意内容,但最好对 shell 脚本中的扩展持偏执态度。 "data.${i}_thinned.dat"
中的大括号是必需的,因此 shell 不会寻找要使用的变量 $i_thinned
。它们在 "data.${i}.dat"
中不是绝对必要的,因为 shell 变量名称中不能包含 .
,但一致性很好。
成分(GAWK)
1 FNR
- 当前文件中的记录数
1 match
- 匹配正则表达式字符串并可以将组捕获到数组中。
1 print
- 打印以下数据(如果提供 none 则默认为当前记录)
1 *.dat
- 当前目录中所有以 .dat 结尾的文件。
说明
- 条件块检查当前文件中的当前记录数除以200余100
- 如果是,那么 运行 下一个区块
{..}
- 获取当前文件名并匹配到最后一个点,将在此之前的所有内容与
(.*)
捕获到数组a
. - 使用捕获的日期
a[1]
打印到文件中,扩展名为_thinned.dat
- 最后在最后加上
*.dat
即可读取当前目录下的所有.dat文件
结果代码
gawk '(FNR%200==100){match(FILENAME,/(.*)\./,a);print >(a[1]"_thinned.dat")}' *.dat
您只需要:
awk 'FNR==1{close(out); out=FILENAME; sub(/\.dat/,"_thinned&",out)} (FNR%200==100){print > out}' data.[0-9][0-9][0-9][0-9].dat
我使用 data.[0-9][0-9][0-9][0-9].dat
作为文件名通配模式而不是 data.*.dat
,以防您在之前生成所有“_thinned”文件的同一目录中重新运行脚本。