Awk脚本在Ubuntu报非法变量引用错误但在MinGW-64正常运行
Awk脚本跨环境运行报错问题
错误现象
在MinGW-64(GNU Awk 5.0.0)中正常运行的Awk脚本,在Ubuntu 22.04(mawk 1.3.4)执行时出现如下错误:
awk: /home/username/chuleta/chuleta/glst.awk: line 22: illegal reference to variable a awk: /home/username/chuleta/chuleta/glst.awk: line 23: illegal reference to variable a
即使将shebang从#!/usr/bin/gawk -f改为#!/usr/bin/awk -f,问题依然存在。
脚本代码
#!/usr/bin/awk -f # generates list of terms related to a topic # this funcion substitutes a with b in $0 func change(a,b) { while (i=index($0,a)) $0 = substr($0,1,i-1) b substr($0,i+length(a)) } { # we delete the base folder (received in var RTO) from the input line # and clean it of other stuff change(RTO,"") change(".txt","") change("/"," ") change("_"," ") split($0,a," ") # using arr as associative array by using same string as index # this prevents duplicated strings and code is shorter # since we don't have to maintain a counter for index for (x in a) # this is line 22 arr[a[x]]=a[x] # this is line 23 } END{ n=asort(arr,sarr) for (x in sarr) printf("%s ",sarr[x]) }
补充信息
- 示例输入数据集:
/home/username/chuleta/chuleta-data/java/8/chuleta_foreach_loop.txt /home/username/chuleta/chuleta-data/java/8/chuleta_basic_functional_interfaces_in_function_package.txt /home/username/chuleta/chuleta-data/java/8/chuleta_advantages_new_date_time_api.txt /home/username/chuleta/chuleta-data/java/8/chuleta_new_date_time_api.txt /home/username/chuleta/chuleta-data/java/8/chuleta_solve_interface_default_methods_conflict.txt /home/username/chuleta/chuleta-data/java/8/chuleta_lambdas_with_parameters.txt
- 脚本逻辑:传入
RTO变量指定基础目录,移除路径、.txt后缀,将/和_替换为空格后分割为数组a,通过关联数组去重后排序输出。
问题原因
核心差异在于mawk和gawk对函数参数的作用域处理不同:
- GNU Awk(gawk)默认将函数参数视为局部变量,函数内部的
a和主程序中的数组a是两个独立的变量,互不干扰。 - mawk中函数参数是全局变量,
change函数的参数a和主程序里定义的数组a是同一个变量。当调用change函数时,参数a被赋值为字符串(比如RTO路径、.txt等),覆盖了后续split生成的数组a,导致遍历a时,它已经不是数组类型,触发“illegal reference to variable a”错误。
解决方法
修改change函数的参数名,避免和主程序中的数组a重名,比如将参数a改为old_str,b改为new_str:
修改后的脚本:
#!/usr/bin/awk -f # generates list of terms related to a topic # this funcion substitutes old_str with new_str in $0 func change(old_str, new_str) { while (i=index($0, old_str)) $0 = substr($0,1,i-1) new_str substr($0,i+length(old_str)) } { # we delete the base folder (received in var RTO) from the input line # and clean it of other stuff change(RTO,"") change(".txt","") change("/"," ") change("_"," ") split($0,a," ") # using arr as associative array by using same string as index # this prevents duplicated strings and code is shorter # since we don't have to maintain a counter for index for (x in a) arr[a[x]]=a[x] } END{ n=asort(arr,sarr) for (x in sarr) printf("%s ",sarr[x]) }
修改后,mawk和gawk环境下都能正常运行,因为函数参数和主程序数组不再重名,避免了全局变量覆盖的问题。
内容的提问来源于stack exchange,提问作者Tulains Córdova
相关产品推荐
相关产品推荐

