【发布时间】:2020-06-30 01:03:14
【问题描述】:
如果我有一个包含一些文本数据的文件,例如
PATTERN1
TEXT1
PATTERN1
TEXT2
PATTERN2
如何从我知道 PATTERN1 和 PATTERN2 的文件中选择 TEXT2 数据? 我曾尝试使用 here 中提到的 awk,但它会同时打印 TEXT1 和 TEXT2。
【问题讨论】:
如果我有一个包含一些文本数据的文件,例如
PATTERN1
TEXT1
PATTERN1
TEXT2
PATTERN2
如何从我知道 PATTERN1 和 PATTERN2 的文件中选择 TEXT2 数据? 我曾尝试使用 here 中提到的 awk,但它会同时打印 TEXT1 和 TEXT2。
【问题讨论】:
如果 TEXT2 总是被 PATTERN1 和 PATTERN2 包围,你可以使用 grep:
grep -B2 "PATTERN2" file | grep -A1 "PATTERN1" | grep -v "PATTERN1"
grep -B2 "PATTERN2" -> 抓取 PATTERN2 和前面两行grep -A1 "PATTERN1" -> 从这三行中,抓取 PATTERN1 和后面的行grep -v "PATTERN1" -> 去掉包含 PATTERN1 的行,剩下的是 TEXT2【讨论】:
$ awk '
inBlock {
if ( /PATTERN2/ ) {
printf "%s", block
inBlock = 0
} else {
block = block $0 ORS
}
}
/PATTERN1/ {
inBlock = 1
block = ""
}
' file
TEXT2
【讨论】:
如果PATTERN2 可以出现多次,则仅提取内部文本:
sed '/PATTERN1/h;//!H;/PATTERN2/!d;//{x;/PATTERN1/!d}'
如果PATTERN2只能出现一次,你可以使用这样的sed脚本:
sed -n '/PATTERN1/h;//!H;/PATTERN2/{x;p}' input_file.txt
或:
sed '/PATTERN1/h;//!H;/PATTERN2/!d;//x'
您可以反转行,然后使用 sed 和 2 个地址并再次反转行:
tac input_file.txt | sed -n '/PATTERN2/,/PATTERN1/p' | tac
使用sed -z,我们可以删除模式前后的所有内容,因为正则表达式是贪婪的:
sed -z 's/.*\(PATTERN1\n\)/\1/;s/\(PATTERN2\n\).*/\1/g'
【讨论】:
PATTERN1 和 PATTERN2,我的印象是 OP 希望删除这些。
这可能对你有用(GNU sed):
sed '/PATTERN1/{z;x;d};/PATTERN2/!{H;d};g;s/.//p;d' file
如果当前行包含PATTERN1,则清除该行并删除保留空间(HS)。
如果当前行不包含PATTERN2,则将其附加到HS并删除该行。
如果当前行包含PATTERN2,则将其替换为HS的内容,删除第一个字符(将是引入的换行符),打印结果并删除该行。
替代方案:
sed -En '/PATTERN1/{:a;/PATTERN1/z;N;/PATTERN2/!ba;s/.(.*)\n.*/\1/p}' file
第一个解决方案假定文件将包含PATTERN1 和PATTERN2,第二个不包含。
【讨论】:
Perl 来救援!
perl -ne 'print(@buffer), $inside = @buffer = () if /PATTERN2/;
push @buffer, $_ if $inside;
@buffer = (), $inside = 1 if /PATTERN1/;
' -- file.txt
我们在@buffer 中保留了一组要输出的行。如果我们遇到了 PATTERN1,但还没有遇到 PATTERN2,我们还会保留一个设置为 true 的标志 $inside。
【讨论】: