【问题标题】:sed newline and carriage return pattern capturesed 换行和回车模式捕获
【发布时间】:2013-08-04 16:41:36
【问题描述】:

我有以下文本块(带有 \r\n 或 \n),我想用 sed 查找并删除它。

<?php
/*
*/
?>

我已经尝试了许多令人尴尬的事情(基于许多 SE 答案)来删除这个已经惨遭失败的事情,而不是让水变得浑浊,什么是捕获和删除这种模式的正确方法?对 \n 或 \r\n 使用两个单独的 sed 命令也可以。

好的,我将分享两个糟糕的尝试:

sed 'N;s/<\?php\r\n\/\*\r\n\*\/\r\n\?>//g' file.txt

sed ':a;N;$!ba;s/<\?php\r\n\/\*\r\n\*\/\r\n\?>//g' file.txt

编辑:根据下面的答案,我尝试将其放入 PERL 递归例程中,以便搜索 .php 文件并修改它们。但是 $text 最终未定义。错误是“在 [line "print $text"] 的 print 中使用未初始化的值 $text”

抱歉,我之前没用过perl...

#!/usr/bin/perl

use strict;
use warnings;

my $parent_dir = ".";
my $dir="";
my $file="";
process_dir($parent_dir);

sub process_dir {
        my $dir = shift;
        print "Processing $dir\n";
        opendir(my $SCR , $dir) or die "Can't open $dir: $!";
        while( defined (my $file = readdir $SCR) )
        {
           next if ($file =~ /\.$/ );
           if ( $file =~ /\.php$/ ) {
             &process_file();
           } elsif ( -d "$dir/$file" ) {
             print "directory : $dir/$file\n";
             process_dir("$dir/$file/");
             #next;
           #} elsif ( $file
           } else {
                print "Else :$file\n" if ( -B "$dir/$file");
           }
           print "file -> $file\n";
        }
    closedir($SCR);
}

sub process_file{

    my $text="";
    open(my $fh, '<', "$dir/$file") or die "cannot open file $file";
    {
        local $/;
        $text = <$fh>;
    }
    close($fh); 

    print "Before:\n";

    print $text;

    $text =~ s{ <\?php \s* \r?\n \s* /\* \s* \r?\n \s* \*/ \s* \r?\n \?> \s* \r?\n }{}gmx;

    print "After:\n";
    print $text;
}

【问题讨论】:

  • 哎哟...一定是sed吗?我不认为这是我用于这项工作的工具。我可能会使用perl,但即使这样也不是特别漂亮。文件有多大?大概不是那么大(更可能是千字节而不是兆字节),所以 slurp 和处理可能是合适的。
  • 有些文件是 20-30Kb。但是有 100 个,所以你明白为什么我需要某种工具来递归它们。 Perl 会很好,但我不是很了解。
  • 如今,在决定将整个文件放入内存是一个坏主意之前,这些文件必须是数兆字节(甚至可能是千兆字节)。虽然它们仍然以千字节为单位,但它们很容易管理——没有机器会费力地处理它。

标签: sed


【解决方案1】:

这可能对你有用(GNU sed):

sed ':a;$!{N;ba};s/\n\?<?php\r\?\n\/\*\r\?\n\*\/\r\?\n?>//g' file

这会将整个文件放入模式空间,然后删除所需的字符串。

正则表达式使用\?,这意味着期望进行模式的1或0(在一般情况下\r或在第一种情况下\n

空白可能是一个看不见的问题,在这种情况下:

sed ':a;$!{N;ba};s/\n\?\s*<?php\s*\r\?\n\s*\/\*\s*\r\?\n\s*\*\/\s*\r\?\n\s*?>//g' file

【讨论】:

    【解决方案2】:

    基本 Perl 脚本

    我可能会使用 Perl 来完成这项工作。假设文件足够小,将整个文件放入内存是一种合理的策略,那么这段代码似乎可以完成这项工作:

    #!/usr/bin/env perl
    use strict;
    use warnings;
    
    my $text;
    {
    local $/;
    $text = <>;
    }
    
    print "Before:\n";
    print $text;
    
    $text =~ s{ <\?php \s* \r?\n \s* /\* \s* \r?\n \s* \*/ \s* \r?\n \?> \s* \r?\n }{}gmx;
    
    print "After:\n";
    print $text;
    

    前三行是标准启动代码。接下来的五个将整个文件读入变量$text。打印行是不言自明的。替换命令是所有乐趣所在。

    模式在第一个{} 对之间;替换文本在第二对 {} 之间。最后的限定符重复替换 (g),跨换行符 (m),使用扩展符号 (x),因此正则表达式中的空格不重要。

    匹配模式查找 &lt;?php 后跟零个或多个空格 (\s*)、可选的回车 (\r?) 和换行符 (\n)。空格、回车和换行符模式出现 4 次,每行以您要匹配的模式结尾一次。其他部分匹配/*之前的零个或多个空格,*/之前的零个或多个空格,?&gt;之前的零个或多个空格,记住*?是特殊字符,必须转义才能匹配从字面上看。

    样本输出

    Before:
    
    aasdasdsa
    sdasdsada
    <?php
    /*
    */
    ?>
    sdasdasda
    asdsdasas
    
    After:
    
    aasdasdsa
    sdasdsada
    sdasdasda
    asdsdasas
    

    递归代码

    #!/usr/bin/env perl
    use strict;
    use warnings;
    use File::Find;
    
    find({ wanted => \&process_file, no_chdir => 1 }, @ARGV);
    
    sub process_file
    {
        my $name = $_;
        return unless -f $name;
        print "$name\n";
        open my $fh, '+<', $name or die "Failed to open file $name for reading and writing";
        my $text;
        {
        local $/;
        $text = <$fh>;
        }
        $text =~ s{ <\?php \s* \r?\n \s* /\* \s* \r?\n \s* \*/ \s* \r?\n \?> \s* \r?\n }{}gmx;
        seek $fh, 0, 0;
        truncate $fh, 0;
        print $fh $text;
        close $fh;
    }
    

    错误处理还有很多不足之处; die 可能应该被 print 替换(到标准错误)并返回。

    【讨论】:

    • 谢谢!不太了解 perl,我将如何修改它以使用模式通过文件结构递归?我无法让这个stackoverflow.com/questions/5241692/… 工作
    • 我想我已经很接近了,如果你能看看我在我编辑的问题中的错误,它真的会帮助我。
    猜你喜欢
    • 2020-02-05
    • 2017-05-02
    • 2012-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多