我想打印“tmp 和之前的行,直到换行符”,我是 Unix 的新手。
例如:输入
AAA
CBH
VFh
GFD
DFC
VGF
HGD
TMP
JHG
TFD
PI1
98A
TMP
TMP
765
UBS
我想要的输出应该是这样的
GFD
DFC
VGF
HGD
TMP
TFD
PI1
98A
TMP
TMP
答案1
使用awk
:
$ awk -v RS='' -v ORS='\n\n' 'match($0,".*TMP") { print substr($0,1,RLENGTH) }' file
GFD
DFC
VGF
HGD
TMP
TFD
PI1
98A
TMP
TMP
这将由至少一个空行分隔的一组行视为一条记录。如果记录与正则表达式匹配.*TMP
,则删除匹配后面的位并打印记录的其余部分。
TMP
通过将正则表达式.*TMP
与当前记录进行匹配,然后使用substr()
仅打印与该表达式匹配的位,可以删除最后一次出现 后的位。正则表达式将从记录的开头到最后一个记录进行匹配TMP
,并且该match()
函数将变量设置RLENGTH
为该匹配的长度。
由于我们使用双换行符作为输出记录分隔符,因此您将在输出末尾得到一个额外的空行。
如果你的文件看起来像
AAA
CBH
VFh
GFD
DFC
VGF
HGD
tmp/some/path/here
JHG
TFD
PI1
98A
tmp/some/path/here
tmp/some/path/here
765
UBS
...并且您希望基于以 开头的行进行相同类型的转换tmp
,然后修改命令中使用的正则表达式,以便它一直匹配到“ -match()
末尾的换行符”tmp
线”:
$ awk -v RS='' -v ORS='\n\n' 'match($0,".*tmp[^\n]*") { print substr($0,1,RLENGTH) }' file
GFD
DFC
VGF
HGD
tmp/some/path/here
TFD
PI1
98A
tmp/some/path/here
tmp/some/path/here
请注意,我不能 100% 确定情况awk
如何应该\n
在括号表达式内进行解释,但awk
我有权访问的所有实现(OpenBSD awk
、mawk
和 GNE awk
)似乎都将其视为换行符和不是作为两个单独的字符\
和n
。
答案2
只需反转文本并从正则表达式到正则表达式进行正常打印,然后再次重新反转以获得原始顺序
tac < file.txt | sed -n '/TMP/,/^$/p' | tac
答案3
如果您可以匹配到第一个TMP
。空RS
将导致段落模式,其中两个或多个连续\n
字符将用作记录分隔符
$ # sub is used to remove everything after first occurrence of TMP
$ # return value of sub (0 if no match, 1 if match is found) determines
$ # if record should be printed or not
$ # use \nTMP\n to match only whole line
$ awk -v RS= 'sub(/TMP\n.*/, "TMP\n")' ip.txt
GFD
DFC
VGF
HGD
TMP
TFD
PI1
98A
TMP
如果您需要直到最后TMP
,您可以使用GNU awk
(because of gensub
) 或perl
$ # use \nTMP\n to match only whole line
$ # same as: perl -00 -ne 'print if s/.*TMP\n\K.*/\n/s' ip.txt
$ awk -v RS= '/TMP/{print gensub(/(.*TMP\n).*/, "\\1", 1)}' ip.txt
GFD
DFC
VGF
HGD
TMP
TFD
PI1
98A
TMP
TMP
答案4
您已使用 sed 进行标记,因此我们可以按照所示方式进行操作。请注意,我们使用的是 GNU sed。根据我的理解,您希望删除文本文件每个段落中以 tmp (小写)开头的最后一行之后的所有内容。段落是由非空行组成的孤岛,与下一个实例之间至少有一个空行分隔开。
sed -e '
/./{H;$!d;}
x;/\ntmp/!d
:chop
/\ntmp[^\n]*$/!s/\n[^\n]*$//
t chop
' file
积累一个段落。当我们到达边界(空行或 eof)时,我们开始检查段落。如果在换行符开头没有看到 tmp,我们会立即删除这一段。否则,我们开始从 para 末尾开始砍掉这些行,直到看到 tmp 行停止处理该 para 并打印它。
使用 GNU awk,我们在 tge 段落模式下操作并将输入字段分隔符设置为换行符。从末尾开始检查字段。当我们看到以 tmp 开头的字段时,我们将 para 缩小到该字段并打印并完成此段落。
awk -F '\n' -v RS= -v OFS='\n' '
/(^|\n)tmp/ {
for(i=NF; i; i--) {
if ($i ~ /^tmp/) {
NF=i; NF++; print; break
}
}
}
' file
rindex 将告诉子字符串在字符串中从末尾开始的位置。因此,通过 rindex abd 获取最后一个 tmp 的位置,使用该位置来获取下一个最接近的换行符的位置。
perl -p00e '
s/.*//s,next unless /^tmp/m;
s/\z/\n/;
my $p = 1+rindex($_, "\ntmp");
my $q = 1+index($_, "\n", $p);
substr($_, $q) = "\n";
' file