如何判断GNU AWK脚本是否通过-i/@include引入?实现双模式运行
GNU AWK实现脚本/库双模式(类似Python name,支持嵌套引入)
要实现GNU AWK脚本同时作为独立工具和函数库使用(直接运行时执行BEGIN块,被@include/-i引入时跳过BEGIN块),可以利用FILENAME和ARGV数组判断当前脚本是否为主脚本,替代环境变量方案,完美支持嵌套引入。
核心思路
GNU AWK中,直接运行的主脚本文件名会出现在ARGV数组(命令行参数列表)中;而通过@include/-i引入的脚本,其文件名不会出现在ARGV里。我们可以通过对比当前脚本的FILENAME与ARGV中的元素,判断是否为主脚本,进而决定是否执行BEGIN块逻辑。
为了兼容相对路径、绝对路径的差异,使用GNU AWK 4.1+提供的realpath()函数统一路径格式;若版本较低,可改用basename对比(兼容性稍弱)。
实现示例
main.gawk
#!/bin/sh exec gawk -f "$0" -- "$@" @include "incl.gawk" BEGIN { is_main = 0 # 遍历命令行参数,检查当前脚本是否为主脚本 for (i = 1; i < ARGC; i++) { if (realpath(FILENAME) == realpath(ARGV[i])) { is_main = 1 break } } if (is_main) { do_included_stuff() exit do_main_stuff() } } function do_main_stuff() { print 1 }
incl.gawk
#!/bin/gawk -f BEGIN { is_main = 0 for (i = 1; i < ARGC; i++) { if (realpath(FILENAME) == realpath(ARGV[i])) { is_main = 1 break } } if (is_main) { do_included_stuff() } } function do_included_stuff() { print 2 }
低版本GNU AWK兼容方案(<4.1)
如果无法使用realpath(),可以通过提取文件名的basename来对比:
function get_basename(path) { return gensub(/.*\//, "", 1, path) } # 在BEGIN块中替换为: if (get_basename(FILENAME) == get_basename(ARGV[i])) { is_main = 1 break }
执行验证
$ ./main.gawk 2 1 $ ./incl.gawk 2
嵌套引入支持
如果incl.gawk再引入其他脚本(比如subincl.gawk),只需在subincl.gawk中复用相同的BEGIN判断逻辑即可,只有直接运行subincl.gawk时才会执行它的BEGIN块,完全支持多层嵌套。
内容的提问来源于stack exchange,提问作者taprs
相关产品推荐
相关产品推荐

