我经常需要 grep 一行及其缩进部分。例如,如果缩进的行号已知,我们将通过以下方式实现此目标:
$ lspci -vq | grep -i wireless -B 1 -A 5
02:00.0 Network controller: Intel Corporation Wireless 7260 (rev 73)
Subsystem: Intel Corporation Wireless-N 7260
Flags: bus master, fast devsel, latency 0, IRQ 64
Memory at c0600000 (64-bit, non-prefetchable) [size=8K]
Capabilities: <access denied>
例如,以下命令的输出可能只包含一个无线局域网信息,也可能不包含所有信息:
$ sudo iwlist wlan0 scan | grep -i "cell 13" -A 34
Cell 13 - Address: 00:1A:2B:93:A7:9C
Channel:6
Frequency:2.437 GHz (Channel 6)
Quality=20/70 Signal level=-90 dBm
Encryption key:on
ESSID:"NetMASTER Uydunet-E445"
Bit Rates:1 Mb/s; 2 Mb/s; 5.5 Mb/s; 11 Mb/s; 18 Mb/s
24 Mb/s; 36 Mb/s; 54 Mb/s
Bit Rates:6 Mb/s; 9 Mb/s; 12 Mb/s; 48 Mb/s
Mode:Master
Extra:tsf=0000005b923c8227
Extra: Last beacon: 4648ms ago
IE: Unknown: 00164E65744D415354455220557964756E65742D45343435
IE: Unknown: 010882848B962430486C
IE: Unknown: 030106
IE: Unknown: 050400010000
IE: Unknown: 2A0100
IE: Unknown: 2F0100
IE: Unknown: 32040C121860
IE: Unknown: 2D1A2C181BFF00000000000000000000000000000000000000000000
IE: Unknown: 3D1606080400000000000000000000000000000000000000
IE: Unknown: DD090010180201F00C0000
IE: WPA Version 1
Group Cipher : CCMP
Pairwise Ciphers (1) : CCMP
Authentication Suites (1) : PSK
IE: Unknown: DD180050F2020101800003A4000027A4000042435E0062322F00
Cell 14 - Address: 90:F6:52:90:C2:2F
Channel:6
Frequency:2.437 GHz (Channel 6)
Quality=21/70 Signal level=-89 dBm
Encryption key:on
ESSID:"selma"
Bit Rates:1 Mb/s; 2 Mb/s; 5.5 Mb/s; 11 Mb/s; 6 Mb/s
9 Mb/s; 12 Mb/s; 18 Mb/s
如何将此输出裁剪为仅包含一个Cell
信息?
编辑
答案1
基于匹配章节标题的解决方案
Cell 13
要打印以 开头但之前停止的文本Cell 14
,请使用:
sudo iwlist wlan0 scan | awk '/Cell 13/{f=1} /^ *Cell 14/{f=0} f'
基于监控缩进级别的解决方案
这将打印从包含以下内容的行开始的所有行Cell 13
,并继续打印所有后续包含更大缩进级别:
sudo iwlist wlan0 scan | awk '/Cell 13/ && !f{f=1;x=$0;sub(/[^ ].*/,"",x);x=x" ";print;next} f {if (substr($0,1,length(x))==x)print; else f=0}'
怎么运行的:
该代码使用两个变量。 f
是一个标志,如果我们位于要打印的部分,则为 1,否则为 0。该字符串x
设置为比我们要打印的部分开头的缩进大一个空格。
/Cell 13/ && !f{f=1;x=$0;sub(/[^ ].*/,"",x);x=x" ";print;next}
这会查找包含
Cell 13
(或任何表示该部分开始的内容的行。如果一行与该行匹配并且我们尚未在该部分中,则:f
设置为 1。该字符串
x
设置为行开头的缩进。该行被打印出来。
其余命令将被跳过,我们跳到该
next
行。
f {if (substr($0,1,length(x))==x)print; else f=0}
如果我们位于要打印的部分内(
f
非零),则检查缩进级别。如果缩进至少为x
,则打印此行。否则,通过设置表示我们已到达该部分的末尾f=0
。
答案2
如果要输出 REGEXP 匹配项以及匹配项之后的所有缩进行:
command | perl -ne '/^( *)/; $i = length $1; $j && $i >= $j and print, next; $j = 0; /REGEXP/ and $j = $i + 1, print'
替换REGEXP
为您的正则表达式。
例如,
$ perl -ne '/^( *)/; $i = length $1; $j && $i >= $j and print, next; $j = 0; /a/ and $j = $i + 1, print' <<EOF
a
b
c
a
b
a
c
b
d
e
b
a
c
e
EOF
输出:
a
a
b
a
c
b
d
a
c
答案3
一般的解决方案是sed
使用范围地址。你们所有人都需要以某种方式指示从哪里开始和停止的线路。有可能关键字,缩进级别,空行或者是其他东西:
关键词
iwlist wlan0 scan | sed -n '/Cell 04/{:1;p;n;/Cell/!b1}'
缩进级别
iwlist wlan0 scan | sed -n '/Cell 04/{:1;p;n;/^\s\{1,18}\S/!b1}'
空行
lspci -vq | sed -n '/[Ww]ireless/{:1;p;n;/^$/!b1}'
答案4
概要
blockgrep [OPTIONS] PATTERN [FILE...]
PATTERN
在每个中搜索FILE
(STDIN
如果未提供文件名,则搜索 )。
与其他grep
s 不同,blockgrep
输出包含匹配项的块(通常是代码)。