使用sed生成多个文件,这些文件的名称取决于搜索的正则表达式模式
基本上,我有一个顺序错误的文件,我想重建。常见的是一个节模式P,在正则表达式中是使用sed生成多个文件,这些文件的名称取决于搜索的正则表达式模式,sed,Sed,基本上,我有一个顺序错误的文件,我想重建。常见的是一个节模式P,在正则表达式中是^\d\{1,2}\\.\d\{1,2}\.\d\{1,2}\.,即:1.2.3.,下面是一些文本 我想要的是将这些截面块输出到单独的文件中,以便按顺序重建它们 到目前为止,我的策略(因为我还不能处理多行正则表达式)是 将这些模式P替换为前面有6个字符的相同模式(作为标记) 然后用其他的标记模式替换所有的换行符,比如说### 然后(这就是我遇到问题的地方),使用sed,搜索任何形式的&&&P[任何字符]&&&&&&,
^\d\{1,2}\\.\d\{1,2}\.\d\{1,2}\.
,即:1.2.3.
,下面是一些文本
我想要的是将这些截面块输出到单独的文件中,以便按顺序重建它们
到目前为止,我的策略(因为我还不能处理多行正则表达式)是
###
sed
,搜索任何形式的&&&P[任何字符]&&&&&&
,并将其输出到一个附加了值为P的数字的文件(即文件1.2.3
)&
标记,并用新行替换###
sed s/\\(\&\&\&\&\)\(^\d\{1,2}\.\d\{1,2}\.\\\.\\\\)\(.\&&&&&/\\)/\1\2\3/file\2
我试图使用regex模式\2
作为我的新文件的扩展名;而且,好吧,它根本不起作用
注意:我使用6&
,因此我不会选择&
形式的模式
任何帮助都将不胜感激 我想你可能对sed要求太多了。您的方法可能有效,但perl为这项工作提供了一些工具:
while ( $line = <> ) {
if( $line =~ /\d{1,2}.\d{1,2}.\d{1,2}/ ) {
$section = $1;
open( $SECTION, ">>", "out.$section.txt");
print $SECTION $line;
close $SECTION;
}
}
while($line=){
如果($line=~/\d{1,2}.\d{1,2}.\d{1,2}/){
$section=$1;
打开($SECTION,“>>”,“out.$SECTION.txt”);
打印$SECTION$行;
关闭$SECTION;
}
}
这是蛮力法。。。我在while循环中打开和关闭文件句柄,这是非常低效的。对于要在少于10000行的文件上运行几次的内容,这就足够了。请注意,此解决方案会将数据附加到每个文件中,因此如果要再次运行它,则必须清除所有文件
最好创建所有可能输出文件名的哈希,然后为每个文件名创建一个行数组。这些文件可以一个文件一个文件地整理和写出来 我认为可以公平地说,
sed
不是这项任务的正确工具。只要付出足够的努力,或许可以让它这样做,但让它这样做确实不公平
Perl(或Python)是一个合理的替代方案。我在Perl方面比Python更流利,所以我会使用它
此外,使用Perl,您甚至可能不需要将输出发送到多个文件,除非文档大小为数百兆字节
我读了一些字里行间的内容,但我认为您的文档输入格式如下:
2.1.9
...multiple lines of material for section 2.1.9...
1.3.6
...multiple lines of material for section 1.3.6...
9.1.3
...multiple lines of material for section 9.1.3...
各节未按顺序呈现的情况。对于我的建议来说,分区标记单独在一行上并不重要;如果在同一行上有文本,它会略微改变内容
在大纲中,代码应该如下所示:
my $current_section = "0.0.0";
my %section_list = ();
my $section_material = "";
while (<>)
{
if (m/^(\d+\.\d+\.\d+)/)
{
# Found a new section...stash the old one...
if ($section_material ne "")
{
# If the same section number appears twice, simply concatenate
# the new material over the old. Or you can get more complex,
# using an array of refs to section material...
$section_list{$current_section} = ""
if !defined $section_list{$current_section};
$section_list{$current_section} .= $section_material;
$current_section = $1;
$section_material = "";
}
}
$section_material .= $_;
}
if ($section_material ne "")
{
$section_list{$current_section} = ""
if !defined $section_list{$current_section};
$section_list{$current_section} .= $section_material;
}
# Now the hash %section_list contains all the material.
# You need a section number comparison function that can be used with sort
sub section_cmp
{
...if $a comes before $b...return -1
...if $b comes before $a...return +1
...otherwise...............return 0
}
foreach my $section (sort section_cmp keys %section_list)
{
print "[$section]\n";
print "$section_list{$section}\n";
}
您可以查找v-numbers,或者找到一个“版本比较”模块,它可以更快地完成这项工作。
awk
可以非常优雅地完成这项工作:
#!/usr/bin/awk
# Put anything before the first section somewhere so we don't lose it.
BEGIN { section = "pre" }
# When we hit a new section, change to that section. Print the section to a file, for sorting later.
/^([0-9]{1,2}\.){3}/ { print (section=$0) >> "sections" }
# Print the line into the current working file
{ print >> section }
现在,在运行此命令之后,每个节都位于其自己的文件中,以该节命名。让我们把它们结合起来
# print the preamble if there was any
[ -f pre ] && cat pre > full
# sort has a -V option to sort version numbers, which is what you want.
sort -V sections | while read file; do cat "$file" >> full; done
就这样。您已经有了完整的文件,按节排序,所有前言仍在顶部。非常感谢您的回复Barton,我还没有完全理解您代码的更详细的内容(因为我对perl真的是新手(目前是)),但我明天会尝试一下(为了测试目的,我会简化文件)让你知道我是怎么做的。关于你提到的效率低下,我说这个算法是n^2阶(对于n行数)对吗?你的另一个解决方案看起来不错,但再一次,在我可以实现它之前,我似乎还有一些需要学习的地方。不,应该是O(N)。。。只是打开和关闭文件句柄可能会很慢,因为每次打开和关闭文件句柄时,您(可能)都会碰到磁盘。我编辑了这个问题以添加代码标记。我建议你们提供一些输入样本和预期的输出,因为我很难猜测你们想要实现什么。
# print the preamble if there was any
[ -f pre ] && cat pre > full
# sort has a -V option to sort version numbers, which is what you want.
sort -V sections | while read file; do cat "$file" >> full; done