【问题标题】:How to use the awk command in a loop to produce several thinned data files如何在循环中使用 awk 命令生成多个细化数据文件
【发布时间】:2015-01-13 22:13:58
【问题描述】:

我有几个包含 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") 什么的吗?如果是这样,如何安排awksprinf的顺序? 我使用 ubuntu 和 bash。

【问题讨论】:

  • 只需将所有文件名放在awk 之后,或者让您的shell 为您完成awk '{...}' *.dat 您可能需要将NR 更改为FNR

标签: bash loops awk


【解决方案1】:

带序列:

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

在第一个 sn-p 中,引号并不是绝对必要的,因为我们知道 $i 不包含任何恶意内容,但最好对 shell 脚本中的扩展保持偏执。 "data.${i}_thinned.dat" 中的大括号是必需的,因此 shell 不会查找要使用的变量 $i_thinned。它们在"data.${i}.dat" 中并不是绝对必要的,因为shell 变量名称中不能包含.,但一致性很好。

【讨论】:

  • 我试过你的代码,但它似乎不起作用。我最终的测试文件是data.0003.127.datdata.0006.127.datdata.0009.127.datdata.0012.127.dat,所以我把代码改成了:for i in {0003 0006 0009 0012}; do awk 'NR%200==100' data.$i.127.dat &gt; $i_thinned.dat done。但是当我在终端运行脚本时,它显示:awk: cannot open data.{.127.dat (No such file or directory) awk: cannot open data.0012.}.127.dat (No such file or directory) ,除了上述两个文件,00060009 也变薄了。
  • 方括号用于 0001 和 0029 之间的扩展。如果您只想选择几个选择标记,请使用 for i in 0003 0006 0009 0012。运行echo {0001..0029} 以查看{..} 的作用。如果您想要一个增量大于 1 的一般情况,seq 可能是要走的路,如for i in $(seq -f %04g 3 3 12)
  • 我已经更改了.sh 中的代码,因为我已经提到“我将代码更改为:for i in {0003 0006 0009 0012};”。所以你的意思是我需要取下牙套?啊,我试过了,但是脚本只产生了一个名为“127..dat”的文件,实际上我检查了里面的数据,它应该是文件127.12_thinned.dat然后我删除了127.$i_thinned.dat 中的127。并且这次没有生成细化的 dat 文件。
  • 哦,我知道了。在${i} 中的i 周围应该有大括号——它正在寻找一个名为i_thinned 的变量。这就是我不注意的结果:P 我会将其编辑到第一个循环中。
【解决方案2】:

你只需要:

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”文件的同一目录中重新运行脚本。

【讨论】:

    【解决方案3】:

    成分(GAWK)

    1 FNR - 当前文件中的记录号
    1 match - 匹配正则表达式字符串并可以将组捕获到数组中。
    1 print - 打印以下数据(如果没有提供则默认为当前记录)
    1 *.dat - 当前导向器中所有以 .dat 结尾的文件。


    说明

    1. 在条件块中,检查当前文件中的当前记录号除以 200 后的余数是否为 100。
    2. 如果是,则运行下一个块{..}
    3. 获取当前文件名并匹配到最后一个点,使用(.*) 将之前的所有内容捕获到数组a 中。
    4. 使用捕获的日期a[1] 和扩展名_thinned.dat 打印到文件中
    5. 最后在末尾加上*.dat,读取当前目录下的所有.dat文件

    结果代码

    gawk '(FNR%200==100){match(FILENAME,/(.*)\./,a);print >(a[1]"_thinned.dat")}' *.dat
    

    【讨论】:

    • @EdMorton 你不需要关闭它吗?
    • @EdMorton 啊,对,所有版本的 gawk 都是这样吗?
    • @EdMorton 比赛在其他 awk 上不起作用,所以我认为这不会是个问题。当然,它比不需要close 的可能性要小。无论如何我都会添加它以防万一:)还有可能将我引导到一些说明 awk 处理所有文件关闭的文档吗?我只能找到这个页面gnu.org/software/gawk/manual/html_node/…
    猜你喜欢
    • 2022-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-26
    • 1970-01-01
    • 2015-08-17
    • 1970-01-01
    相关资源
    最近更新 更多