AWK,同一文件中使用不同分隔符打印 2 次
AWK, 2 prints with different separators from the same file
假设我有这条线
"58062","2022-03-23 10:07:21.718670","Standard query 0x04c0 AAAA contoso.local"
我只想打印“contoso.local”,这是双引号内最后一个块的第 5 列。
我这样做得到了我想要的:
cat file.log | awk -F "," '{print }' | awk '{print }'
有没有更优雅的方法来实现这个?我在第一个 awk 中尝试了一个 awk,但这不起作用,我相信我使用的是 Ubuntu 18.
中的 GNU Awk
编辑:
这确实是一个日志文件(很多过滤的 dns 查询),其中所有行都具有相同的结构,更具体地说:我并不严格需要该行的最后一个词,例如我可能需要提取域之前的字母数字代码,它始终是最后一个块的第 3 列。
"58062","2022-03-23 10:07:21","Standard query 0x04c0 A contoso.local"
"58063","2022-03-23 10:08:22","Standard query 0xcif0 A something.local"
"58064","2022-03-23 10:09:23","Standard query 0xEec0 AAAA domain.local"
以上文件有效:
cat file.log | awk -F "," '{print }' | awk '{print }'
另一种选择是简单地使用 sed
和通常的替换 ('s/find/replace/' file
) 捕获行中最后一个空格分隔的文本到第一个 '"'
并重新插入该文本使用第一个命名的反向引用。
sed -E 's/^.*[[:space:]]([^"]+)"$//'
上面的 -E
选项指定了 扩展正则表达式 语法。如果您的 sed
不支持 -E
(或 -r
),您只需用 *
(零次或多次出现)再次声明匹配并转义capture-group 中的括号。使用基本正则表达式将是:
sed -E 's/^.*[[:space:]]\([^"][^"]*\)"$//'
例子Use/Output
使用 file
中的示例行,您将得到:
$ sed -E 's/^.*[[:space:]]([^"]+)"$//' file
contoso.local
这取决于你的数据。如果问题是:'Print the last "word" without ending quote',那么可能是:
sed -E 's/.* (.*)"//'
awk -F'.* |"' '{[=10=]=}1'
# grep -oP '([^\s]+)(?="$)' file.log
contoso.local
something.local
domain.local
1.grep 支持 lookaround,你需要在你的 grep 中添加 -P 选项(如果你的 grep 支持的话)。因为 PCRE 支持它们。
2.\s匹配任意空格,^表示否定,+表示匹配一次或多次,"$表示以引号结尾
以上评论来自@JNevill的回答
awk -F"," '{split(,a,"[ \"]"); print a[5]}' test.txt
对我的评论进行一些澄清:
gawk -F"," '{ FS=" "; [=10=]=; print }' file.log
这在 file.log
只有一行时有效,而在包含多行时无效。这可以通过以下方式解决:
gawk -F"," '{ FS=" "; [=11=]=; print ; FS="," }' file.log
步骤:
-F","
字段分隔符设置为逗号
FS=" "
字段分隔符设置为 space。这是在阅读第一行后完成的。
[=16=]=
Re-assinging [=17=]
具有一个值(在本例中为 </code>)将使 gawk 再次拆分该值,由 <code>FS
.
print
打印第 5 个字段。
FS=","
将字段分隔符重新设置为“,”以处理下一行。
因为多次给 FS 赋值,所以最好使用 split()
这将导致:
gawk -F"," '{ split(,a," "); print a[5] }' file.log
(JNevil 在评论中也给出了)
如果您非常确定您需要的是 </code> 的最后一个 space/tab 之后,那么 </p>
<pre><code> # using FS to deal with trailing double-quote
mawk 'sub("^.+ ",_,$(($!_=$_=)<_))' FS=',|["]$'
or
# using gsub() to deal with trailing double-quote
mawk 'gsub("^.+ |["]$",_,$(NF=($_=)~_))' FS=','
or
#using RS to deal with trailing double-quote
mawk 'sub("^.+ ",_,$(NF=($_=)~_))' FS=',' RS='"?\n'
"58062","2022-03-23 10:07:21","Standard query 0x04c0 A contoso.local"
"58063","2022-03-23 10:08:22","Standard query 0xcif0 A something.local"
"58064","2022-03-23 10:09:23","Standard query 0xEec0 AAAA domain.local"
contoso.local
something.local
domain.local
或者也许
echo "${aaa}" \
\
| mawk 'BEGIN { FS=_=","
} $!+_=$+(FS=_)=substr("",$(($!+_=)<"")=$+(FS=" |[]$")) $--NF'
contoso.local
something.local
domain.local
假设我有这条线
"58062","2022-03-23 10:07:21.718670","Standard query 0x04c0 AAAA contoso.local"
我只想打印“contoso.local”,这是双引号内最后一个块的第 5 列。
我这样做得到了我想要的:
cat file.log | awk -F "," '{print }' | awk '{print }'
有没有更优雅的方法来实现这个?我在第一个 awk 中尝试了一个 awk,但这不起作用,我相信我使用的是 Ubuntu 18.
中的 GNU Awk编辑:
这确实是一个日志文件(很多过滤的 dns 查询),其中所有行都具有相同的结构,更具体地说:我并不严格需要该行的最后一个词,例如我可能需要提取域之前的字母数字代码,它始终是最后一个块的第 3 列。
"58062","2022-03-23 10:07:21","Standard query 0x04c0 A contoso.local"
"58063","2022-03-23 10:08:22","Standard query 0xcif0 A something.local"
"58064","2022-03-23 10:09:23","Standard query 0xEec0 AAAA domain.local"
以上文件有效:
cat file.log | awk -F "," '{print }' | awk '{print }'
另一种选择是简单地使用 sed
和通常的替换 ('s/find/replace/' file
) 捕获行中最后一个空格分隔的文本到第一个 '"'
并重新插入该文本使用第一个命名的反向引用。
sed -E 's/^.*[[:space:]]([^"]+)"$//'
上面的 -E
选项指定了 扩展正则表达式 语法。如果您的 sed
不支持 -E
(或 -r
),您只需用 *
(零次或多次出现)再次声明匹配并转义capture-group 中的括号。使用基本正则表达式将是:
sed -E 's/^.*[[:space:]]\([^"][^"]*\)"$//'
例子Use/Output
使用 file
中的示例行,您将得到:
$ sed -E 's/^.*[[:space:]]([^"]+)"$//' file
contoso.local
这取决于你的数据。如果问题是:'Print the last "word" without ending quote',那么可能是:
sed -E 's/.* (.*)"//'
awk -F'.* |"' '{[=10=]=}1'
# grep -oP '([^\s]+)(?="$)' file.log
contoso.local
something.local
domain.local
1.grep 支持 lookaround,你需要在你的 grep 中添加 -P 选项(如果你的 grep 支持的话)。因为 PCRE 支持它们。
2.\s匹配任意空格,^表示否定,+表示匹配一次或多次,"$表示以引号结尾
以上评论来自@JNevill的回答
awk -F"," '{split(,a,"[ \"]"); print a[5]}' test.txt
对我的评论进行一些澄清:
gawk -F"," '{ FS=" "; [=10=]=; print }' file.log
这在 file.log
只有一行时有效,而在包含多行时无效。这可以通过以下方式解决:
gawk -F"," '{ FS=" "; [=11=]=; print ; FS="," }' file.log
步骤:
-F","
字段分隔符设置为逗号FS=" "
字段分隔符设置为 space。这是在阅读第一行后完成的。[=16=]=
Re-assinging[=17=]
具有一个值(在本例中为</code>)将使 gawk 再次拆分该值,由 <code>FS
.print
打印第 5 个字段。FS=","
将字段分隔符重新设置为“,”以处理下一行。
因为多次给 FS 赋值,所以最好使用 split()
这将导致:
gawk -F"," '{ split(,a," "); print a[5] }' file.log
(JNevil 在评论中也给出了)
如果您非常确定您需要的是 </code> 的最后一个 space/tab 之后,那么 </p>
<pre><code> # using FS to deal with trailing double-quote
mawk 'sub("^.+ ",_,$(($!_=$_=)<_))' FS=',|["]$'
or
# using gsub() to deal with trailing double-quote
mawk 'gsub("^.+ |["]$",_,$(NF=($_=)~_))' FS=','
or
#using RS to deal with trailing double-quote
mawk 'sub("^.+ ",_,$(NF=($_=)~_))' FS=',' RS='"?\n'
"58062","2022-03-23 10:07:21","Standard query 0x04c0 A contoso.local"
"58063","2022-03-23 10:08:22","Standard query 0xcif0 A something.local"
"58064","2022-03-23 10:09:23","Standard query 0xEec0 AAAA domain.local"
contoso.local
something.local
domain.local
或者也许
echo "${aaa}" \
\
| mawk 'BEGIN { FS=_=","
} $!+_=$+(FS=_)=substr("",$(($!+_=)<"")=$+(FS=" |[]$")) $--NF'
contoso.local
something.local
domain.local