字符串的长度不是我想象的那样

字符串的长度不是我想象的那样

我在“test.txt”文件中有一个字符串:

207.46.13.136 - - [22/Jan/2019:03:56:21 +0330] "GET /product/30649?model=60398 HTTP/1.1" 200 41198 "-" "Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)" "-"

我执行了:

grep 'GET /product/*' test.txt | awk -F "/" '{ if ( "${#5}" -lt 6 ) {print $5} } '

所以它应该输出$5长度小于 6 的所有字符串。

我预计不会有输出,因为 my 的长度$5是 22 ( 30649?model=60398 HTTP) 但它还是输出了该字符串。

编辑:我发现 的长度"30649?model=60398 HTTP"是 0!我更困惑了。

发生了什么?

答案1

awk在这里混淆了 shell 和语法。

sh(或bash) 和awk是两种不同语言的两个解释器,彼此无关。

的语法awk非常类似于 C。

在 中awk,变量是用 引用的var$var与 shell 中不同,$inawk是一个一元运算符,用于检索输入字段的值(如果应用于 0,则检索完整记录)。$ (3 + 3)例如检索第 6 个字段的值。 in 中的字符串常量内部没有变量插值awk,更不用说运算符的解释,无论它是一元-还是。+$

所以 in 中awk"${#5}"只是具有文字值 的字符串常量${#5}

"${#5}" -lt,与应用于该字符串和变量的"string" - lt二元运算符相同。因为它是算术运算符,所以两个操作数都转换为数字。由于两者都以看起来像产生 的数字开头,所以都是 0。-lt0 - 0

然后使用(不可见的)串联运算符。在x yx和中,y它们被转换为字符串并连接起来产生一个新字符串。这"${#5}" -lt 6就是字符串("${#5}" - lt) 6的结果"06"

$ gawk 'BEGIN{result = "${#5}" -lt 6; print typeof(result) ": " result}'
string: 06

这用作iftrue 是非 0 数字或非空字符串的条件,所以这里我们总是得到真的因为"06"是一个非空字符串。

这里正确的awk语法是:

awk -F "/" '{ if (length($5) < 6) print $5 }'

或者使用更规范的<condition> {<action>}图案:

awk -F/ 'length($5) < 6 {print $5}'

另请注意,grep 'GET /product/*'查找GET /product后跟任意数量(包括 0)的/字符,因此它在功能上等同于grep 'GET /product'.awk作为 的超集grep,您通常也不需要将它们通过管道连接在一起。所以在这里:

awk -F/ 'index($0, "GET /product/") && length($5) < 6 {print $5}'

index($0, "string")string完整记录中定位 ( )$0相当于grep -F 'GET /product/'.另请参见/regexp/( 的缩写$0 ~ /regexp/) 的等效项grep -E regexp

相关内容