Fre*_*eel 6 command-line text-processing
我希望输出前一行指定的两个位置 A 和 B 之间的字符。每对,两条线的长度相等,但对之间的长度可以不同。有没有一种有效的方法(巨大的文件大小)可以使用grep
, sed
, 或awk
?
示例文件:
xxxxxxAxxxxxxBxxxxxx
1234567890MNOPQRSTUV
xxAxxxxxxxxxxxxxxBxxxxxx
1234567890MNOPQRSTUVWXYZ
Run Code Online (Sandbox Code Playgroud)
...
我想获得输出:
7890MNOP
34567890MNOPQRST
Run Code Online (Sandbox Code Playgroud)
...
使用awk
:
$ awk '!seen{match($0, /A.*B/);seen=1;next} {print substr($0,RSTART,RLENGTH);seen=0}' infile
7890MNOP
34567890MNOPQRST
Run Code Online (Sandbox Code Playgroud)
解释:读入manawk
:
RSTART
The index of the first character matched by match(); 0 if no
match. (This implies that character indices start at one.)
RLENGTH
The length of the string matched by match(); -1 if no match.
match(s, r [, a])
Return the position in s where the regular expression r occurs,
or 0 if r is not present, and set the values of RSTART and RLENGTH. (...)
substr(s, i [, n])
Return the at most n-character substring of s starting at I.
If n is omitted, use the rest of s.
Run Code Online (Sandbox Code Playgroud)
虽然你可以用 AWK 做到这一点,但我建议使用 Perl。这是一个脚本:
#!/usr/bin/env perl
use strict;
use warnings;
while (my $pattern = <>) {
my $text = <>;
my $start = index $pattern, 'A';
my $stop = index $pattern, 'B', $start;
print substr($text, $start, $stop - $start + 1), "\n";
}
Run Code Online (Sandbox Code Playgroud)
您可以随意命名该脚本文件。如果您要为其命名并将其interval
放入当前目录,则可以将其标记为可执行文件chmod +x interval
。然后你可以运行:
./interval paths...
Run Code Online (Sandbox Code Playgroud)
替换paths...
为要解析的文件的实际路径名或路径名。例如:
$ ./interval interval-example.txt
7890MNOP
34567890MNOPQRST
Run Code Online (Sandbox Code Playgroud)
脚本的工作方式是,直到到达输入结束(即没有更多行),它:
$pattern
,这是您的字符串,A
和B
,以及另一行,$text
,这是将被切片的字符串。A
in$pattern
和 first的索引,B
除了可能在 first 之前的任何索引A
,并将它们分别存储在$start
和$stop
变量中。$text
其索引范围从$start
到 的部分$stop
。Perl 的substr
函数采用 offset 和 length 参数,这就是减法的原因,并且您将紧接在 下的字母包括在内B
,这就是添加1
.如果出于某种原因,您更喜欢一个短的单行命令,它可以实现相同的功能但很容易粘贴进去——但也更难理解和维护——那么你可以使用这个:
./interval paths...
Run Code Online (Sandbox Code Playgroud)
(和以前一样,您必须paths...
用实际路径名替换。)
既然你提到了sed,你也可以用 sed 脚本来做到这一点:
/^x*Ax*Bx*$/{ # If an index line is matched, then
N # append the next (content) line into the pattern buffer
:a # label a
s/^x(.*\n).(.*)/\1\2/ # remove "x" from the index line start and a char from the content line start
ta # if a subtitution happened in the previous line then jump back to a
:b # label a
s/(.*)x(\n.*).$/\1\2/ # remove "x" from the index line end and a char from the content line end
tb # if a subtitution happened in the previous line then jump back to b
s/.*\n// # remove the index line
}
Run Code Online (Sandbox Code Playgroud)
如果你把这一切都放在一个命令行上,它看起来像这样:
$ sed -r '/^x*Ax*Bx*$/{N;:a;s/^x(.*\n).(.*)/\1\2/;ta;:b;s/(.*)x(\n.*).$/\1\2/;tb;s/.*\n//;}' example-file.txt
7890MNOP
34567890MNOPQRST
$
Run Code Online (Sandbox Code Playgroud)
-r
需要这样sed
才能理解正则表达式分组括号而无需额外转义。
FWIW,我认为这不能完全用 完成grep
,尽管我很乐意被证明是错误的。