Awk脚本:如何利用输入文件名生成不同扩展名的输出文件
解决Awk中BEGIN块无法获取FILENAME及生成对应输出文件的问题
首先得搞清楚你遇到的核心问题:Awk的BEGIN块是在处理任何输入文件之前执行的,这时候FILENAME变量还没有被赋值,所以你在BEGIN里打印它会得到空字符串,这是Awk的正常执行流程导致的。
接下来针对你的需求——根据输入文件名生成对应扩展名的输出文件(比如test.txt→test.out),同时保留在内容开头加"start"、结尾加"end"的功能,给你两种可行的解决方案:
方案一:利用首行处理时机获取FILENAME
这是最简洁的方式,因为当Awk开始处理第一行输入时,FILENAME已经被正确设置为当前输入文件的名称。我们可以在第一次处理行的时候生成输出文件名,后续复用这个文件句柄:
#! /bin/awk -f # 初始化输出文件变量 BEGIN { # 这里不再尝试获取FILENAME,因为此时还未赋值 } # 处理第一行时,生成输出文件并写入开头的"start" NR == 1 { # 复制输入文件名,替换后缀为.out outfile = FILENAME sub(/\.txt$/, ".out", outfile) # 将"start"写入输出文件 print "start" > outfile } # 将每一行内容写入输出文件 { print $0 > outfile } # 处理完所有行后,写入"end"并关闭文件 END { print "end" >> outfile close(outfile) # 如果需要同时在终端输出start/end,可以保留原打印逻辑 # print "start" # print "end" }
调用方式还是你原来的:
./myscript.awk test.txt
关键点说明:
NR == 1:NR是当前处理的总行数,当它等于1时,就是第一次处理输入行,此时FILENAME已经有效。sub(/\.txt$/, ".out", outfile):用正则替换把文件名末尾的.txt换成.out,如果你的输入文件扩展名不是固定的,可以调整正则(比如用sub(/\.[^.]+$/, ".out", outfile)匹配任意后缀)。- 使用
close(outfile):避免Awk打开过多文件句柄,尤其是处理多个文件时更重要。
方案二:通过命令行参数传递文件名给BEGIN块
如果你一定要在BEGIN块里获取文件名,可以手动通过命令行参数把文件名传递给Awk,这样BEGIN块就能直接读取:
修改后的脚本:
#! /bin/awk -f BEGIN { # 遍历命令行参数,找到我们传递的文件名参数 for (i in ARGV) { if (ARGV[i] ~ /^input=/) { split(ARGV[i], param, "=") fname = param[2] break } } # 生成输出文件名 outfile = fname sub(/\.txt$/, ".out", outfile) # 现在BEGIN块里就能正常打印文件名了 print "fname: '" fname "'" print "start" > outfile } { print $0 > outfile } END { print "end" >> outfile close(outfile) }
调用时需要额外传递文件名参数:
./myscript.awk test.txt input=test.txt
这种方式虽然能让BEGIN块拿到文件名,但需要手动传参,不如方案一优雅,更适合特殊场景下使用。
内容的提问来源于stack exchange,提问作者code_fodder
相关产品推荐
相关产品推荐

