awk自定义json_stringify函数输出异常问题排查求助
问题分析与解决方案
你的函数只输出第一个参数的结果,主要有两个核心问题:
1. 全局变量冲突导致循环提前终止
在awk中,变量默认是全局的。你在BEGIN块的循环中使用了变量i,同时在json_stringify函数内部的初始化循环也用了i。当第一次调用json_stringify处理第一个参数时,函数内的循环会把i的值递增到128,此时BEGIN块的循环条件i < ARGC不再成立(你的测试命令中ARGC为4),循环直接终止,后续参数根本没机会被处理。
2. awk会尝试将ARGV参数当作文件读取
即使解决了变量冲突,当BEGIN块执行完毕后,awk会默认把ARGV[1..ARGC-1]当作输入文件去读取。这些参数是字符串而非实际文件,awk会抛出"No such file or directory"的错误,甚至可能干扰正常输出。
修正后的函数代码
json_stringify() { LANG=C awk ' BEGIN { # 覆盖ARGC为1,阻止awk尝试读取参数作为文件 ARGC = 1 # 使用传递进来的ARGC_ORIG获取原始参数个数 for (i = 1; i < ARGC_ORIG; i++) print json_stringify(ARGV[i]) } # 用j作为局部循环变量,将_ESC_设为函数参数实现局部化 function json_stringify(str, _str, _out, _ESC_, j) { if (!("\\" in _ESC_)) { for (j = 1; j <= 127; j++) { _ESC_[sprintf("%c", j)] = sprintf("\\u%04x", j) } } _str = str _out = "\"" while (match(_str, /["\\[:cntrl:]]/)) { _out = _out substr(_str, 1, RSTART-1) _ESC_[substr(_str, RSTART, RLENGTH)] _str = substr(_str, RSTART + RLENGTH) } return _out _str "\"" } ' ARGC_ORIG=$# "$@" }
关键修改说明
- 解决变量冲突:将函数内部的循环变量从
i改为j,同时把_ESC_作为函数的参数(awk中未赋值的函数参数会被当作局部变量),彻底隔离全局变量和局部变量的影响。 - 阻止文件读取行为:在
BEGIN块开头将ARGC设为1,这样awk就不会再尝试处理ARGV中的参数作为输入文件。 - 传递原始参数个数:通过
ARGC_ORIG=$#将bash中的参数个数传递给awk,避免修改ARGC后无法获取原始参数数量。
现在执行你的测试命令:
json_stringify 'A"B' 'C\\D' $'\\b \\f \\t \\r \\n'
会得到符合预期的输出:
"A\u0022B" "C\u005cD" "\u0008 \u000c \u0009 \u000d \u000a"
(注:你预期输出中的双反斜杠\\u0022是bash的转义显示效果,实际输出的单个反斜杠才是符合JSON规范的正确格式)
内容的提问来源于stack exchange,提问作者Fravadona
相关产品推荐
相关产品推荐

