如何使用Perl单行命令(-pe选项)从序列超集中筛选目标序列组并在代码块处理后得到指定输出
解决Perl单行命令的序列合并问题
首先直接给你能得到预期输出的可用命令:
for i in {1..9}; do echo $i; done | perl -ne ' chomp; if (/3/) { $collecting = 1; $buffer = $_; } elsif ($collecting) { $buffer .= $_; if (/7/) { print "$buffer "; $collecting = 0; $buffer = ""; } } else { print "$_ "; } END { print "\n" } '
如果需要更紧凑的单行版本:
for i in {1..9}; do echo $i; done | perl -ne 'chomp; if(/3/){$c=1;$b=$_}elsif($c){$b.=$_;if(/7/){print"$b ";$c=0}}else{print"$_ "}END{print"\n"}'
执行后会输出:1 2 34567 8 9(末尾的空格如果介意,可以用数组存储所有元素最后用空格拼接,不过这个结果已经基本符合你的预期)
为什么你的原命令无法工作?
你的原命令有两个核心问题:
-pe选项的自动行为冲突:-pe等价于Perl代码外层自动包裹了while (<>) { ...; print },也就是说每行输入都会被自动打印一次。当处理到3这行时,你的代码进入了无限循环:while(1)里的$_始终是当前的3行,不会自动读取后续的4、5等行,而且因为/7/永远匹配不上,循环会一直运行,既不会处理后续行,也不会停止。没有主动读取后续行:
你的代码里没有主动调用<>来读取下一行输入,所以在while(1)循环里,你一直在重复处理3这一行,永远到不了触发/7/的条件。
正确代码的逻辑说明
- 用
-n代替-pe:-n会包裹while (<>) { ... }但不会自动打印每行,让我们完全控制输出时机。 - 状态管理:用
$collecting变量标记是否处于「合并序列」的状态:- 当遇到
3时,开启收集状态,把3存入缓冲区$buffer。 - 处于收集状态时,把每行内容追加到缓冲区,直到遇到
7,此时打印缓冲区内容,关闭收集状态。 - 非收集状态时,直接打印当前行(带空格分隔)。
- 当遇到
chomp去掉每行末尾的换行符,避免合并时出现多余换行。
如果你的预期输出是1 2 3 4567 8 9(即3单独输出,4-7合并),只需要调整逻辑:遇到3时先打印3 ,再开启收集状态,缓冲区从空开始,后续追加4-7,遇到7时打印4567 即可。对应的修改代码如下:
for i in {1..9}; do echo $i; done | perl -ne ' chomp; if (/3/) { print "$_ "; $collecting = 1; $buffer = ""; } elsif ($collecting) { $buffer .= $_; if (/7/) { print "$buffer "; $collecting = 0; $buffer = ""; } } else { print "$_ "; } END { print "\n" } '
内容的提问来源于stack exchange,提问作者user17227456
相关产品推荐
相关产品推荐

