行の長さが思ったより長くありません。

行の長さが思ったより長くありません。

"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ここではシェルと構文を混同しています。

sh(またはbash)は、awk互いに関連のない2つの異なる言語の2人の通訳者です。

構文はawkCに非常に似ています。

では、シェルとは異なり、awk変数が参照されますvar。ここで、inは入力フィールドの値を取得する単項演算子です(0に適用すると、レコード全体が検索されます)。たとえば、6番目のフィールドの値を取得します。単項かどうかにかかわらず、演算子の解釈はもちろん、inの文字列定数の内部には変数補間はありません。$var$awk$ (3 + 3)awk-+$

したがって、inはawkリテラル"${#5}"値を持つ文字列定数です${#5}

"${#5}" -lt、文字列と変数に"string" - lt同じバイナリ演算子が適用されます。算術演算子なので、両方のオペランドが数値に変換されます。両方とも結果の数字のように見えることから始まるので、どちらもゼロです。-lt0 - 0

次に、(見えない)接続演算子を使用します。x yxおよび ではy文字列に変換され、連結されて新しい文字列を生成します。これは文字列の結果"${#5}" -lt 6です。("${#5}" - lt) 6"06"

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

ifこれはtrueがゼロ以外の数字または空でない文字列になる条件として使用されるため、ここでは常に次のような結果が得られます。本物"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'。また、一般的awkgrep一緒にパイプする必要はありません。だからここにあります:

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

関連情報