在固定宽度文件上使用 awk substr
Using awk substr on fixed width file
我有一个固定宽度的文件,我想按前四个字符定义的值将行拆分到名为 file_1985.dat
和 file_1986.dat
的文件中。拿这个最小的文件:
$ cat foo.dat
1985tiny dancer
1986largechicken
1985hey jude
我想这样结束:
$ cat file_1985.dat
1985tiny dancer
1985hey jude
还有这个:
$ cat file_1986.dat
1986largechicken
我很确定我需要做这样的事情:
awk -F, '{if(???)print > "file_1985.dat";else print > "file_1986.dat"}' foo.dat
其中 ???
涉及 substr
的一些使用。有人可以在这里建议吗?
使用 substr([=15=], 1, 4)
获取文件名中的 4 个字符(从字符 1
开始,长度为 4
的子字符串):
awk '{
out = "file_" substr([=10=], 1, 4) ".dat" # set filename
if (out != prev) close(prev) # close previous file
print >> out # write to file
prev = out # remember filename to check on next line
}' foo.dat
文件名 out
来自将字符串文字与 substr
的结果连接的结果。此变量用于确定 print
的输出最终所在的文件。
>>
在"append mode"中打开一个文件,这意味着如果您重新打开同一个文件,您不会丢失之前的内容。
正在测试:
$ awk '{ out = "file_" substr([=11=], 1, 4) ".dat"; if (out != prev) close(prev); print >> out; prev = out }' foo.dat
$ cat file_1985.dat
1985tiny dancer
1985hey jude
$ cat file_1986.dat
1986largechicken
close
的使用是防止打开太多文件的预防措施,但如果您的输入不是太大,那么您可以简化为:
awk '{ print > ("file_" substr([=12=], 1, 4) ".dat") }' foo.dat
关于性能,您可以尝试对输入进行排序,以避免重复打开和关闭相同的文件(尽管排序本身会花费时间):
sort -s -k1.1,1.4 foo.dat | awk '{ out = "file_" substr([=13=], 1, 4) ".dat"; if (out != prev) close(prev); print > out; prev = out }'
这里我也将 >>
更改为 >
因为 awk 只会打开每个文件一次。
您还可以通过缓存结果来避免每行重复一次相同的字符串连接:
{
ss = substr([=14=], 1, 4)
if (!(ss in outs)) {
outs[ss] = "file_" ss ".dat"
}
out = outs[ss]
if (out != prev) close(prev)
print >> out
prev = out
}
将它放在像 script.awk
和 运行 这样的脚本中,就像 awk -f script.awk foo.dat
。
gawk -v FIELDWIDTHS="4 200" '{ print > "file_" ".dat" }' foo.dat
来自手册页:
如果 FIELDWIDTHS 变量设置为 space 分隔的数字列表,则每个字段都应具有固定宽度,并且 gawk 使用指定的宽度拆分记录。每个字段宽度可以
可选地在前面加上一个冒号分隔的值,指定在字段开始之前要跳过的字符数。 FS 的值被忽略。为 FS 或 FPAT 分配新值会覆盖
使用 FIELDWIDTHS。
如果您使用的是 GNU awk,或者您的输出文件少于 12 个,那么:
awk '{print > ("file_"substr([=10=],1,4)".dat")}' foo.dat
否则要避免 "too many open files" 错误:
awk '{out="file_"substr([=11=],1,4)".dat"; print >> out; close(out)}' foo.dat
我有一个固定宽度的文件,我想按前四个字符定义的值将行拆分到名为 file_1985.dat
和 file_1986.dat
的文件中。拿这个最小的文件:
$ cat foo.dat
1985tiny dancer
1986largechicken
1985hey jude
我想这样结束:
$ cat file_1985.dat
1985tiny dancer
1985hey jude
还有这个:
$ cat file_1986.dat
1986largechicken
我很确定我需要做这样的事情:
awk -F, '{if(???)print > "file_1985.dat";else print > "file_1986.dat"}' foo.dat
其中 ???
涉及 substr
的一些使用。有人可以在这里建议吗?
使用 substr([=15=], 1, 4)
获取文件名中的 4 个字符(从字符 1
开始,长度为 4
的子字符串):
awk '{
out = "file_" substr([=10=], 1, 4) ".dat" # set filename
if (out != prev) close(prev) # close previous file
print >> out # write to file
prev = out # remember filename to check on next line
}' foo.dat
文件名 out
来自将字符串文字与 substr
的结果连接的结果。此变量用于确定 print
的输出最终所在的文件。
>>
在"append mode"中打开一个文件,这意味着如果您重新打开同一个文件,您不会丢失之前的内容。
正在测试:
$ awk '{ out = "file_" substr([=11=], 1, 4) ".dat"; if (out != prev) close(prev); print >> out; prev = out }' foo.dat
$ cat file_1985.dat
1985tiny dancer
1985hey jude
$ cat file_1986.dat
1986largechicken
close
的使用是防止打开太多文件的预防措施,但如果您的输入不是太大,那么您可以简化为:
awk '{ print > ("file_" substr([=12=], 1, 4) ".dat") }' foo.dat
关于性能,您可以尝试对输入进行排序,以避免重复打开和关闭相同的文件(尽管排序本身会花费时间):
sort -s -k1.1,1.4 foo.dat | awk '{ out = "file_" substr([=13=], 1, 4) ".dat"; if (out != prev) close(prev); print > out; prev = out }'
这里我也将 >>
更改为 >
因为 awk 只会打开每个文件一次。
您还可以通过缓存结果来避免每行重复一次相同的字符串连接:
{
ss = substr([=14=], 1, 4)
if (!(ss in outs)) {
outs[ss] = "file_" ss ".dat"
}
out = outs[ss]
if (out != prev) close(prev)
print >> out
prev = out
}
将它放在像 script.awk
和 运行 这样的脚本中,就像 awk -f script.awk foo.dat
。
gawk -v FIELDWIDTHS="4 200" '{ print > "file_" ".dat" }' foo.dat
来自手册页: 如果 FIELDWIDTHS 变量设置为 space 分隔的数字列表,则每个字段都应具有固定宽度,并且 gawk 使用指定的宽度拆分记录。每个字段宽度可以 可选地在前面加上一个冒号分隔的值,指定在字段开始之前要跳过的字符数。 FS 的值被忽略。为 FS 或 FPAT 分配新值会覆盖 使用 FIELDWIDTHS。
如果您使用的是 GNU awk,或者您的输出文件少于 12 个,那么:
awk '{print > ("file_"substr([=10=],1,4)".dat")}' foo.dat
否则要避免 "too many open files" 错误:
awk '{out="file_"substr([=11=],1,4)".dat"; print >> out; close(out)}' foo.dat