How do you use sed from Perl?

前端 未结 10 516
渐次进展
渐次进展 2021-01-18 01:14

I know how to use sed with grep, but within Perl the below fails. How can one get sed to work within a Perl program?

c         


        
相关标签:
10条回答
  • 2021-01-18 01:37

    Use power Luke:

    $ echo -e "a\nb\na"|perl -lne'/a/&&print$.'
    1
    3
    

    Thus when you want same think as this slow and overcomplicated grep and sed combination you can do it far simpler and faster in perl itself:

    my @linenumbers;
    open my $fh, '<', $fileToProcess or die "Can't open $fileToProcess: $!";
    while (<$fh>)
    {
       /textToFind/ and push @lineNumbers, $.;
    }
    close $fh;
    

    Or with same memory culprits as the original solution

    my @linenumbers = do {
        open my $fh, '<', $fileToProcess or die "Can't open $fileToProcess: $!";
        my $i;
        map { ( ++$i ) x /textToFind/ } <$fh>
    };
    
    0 讨论(0)
  • 2021-01-18 01:39

    If you had a large sed expression, you could use s2p, to convert it into a perl program.

    If you run  <s2p 's/^\([0-9]*\)[:].*/\1/p'>, this is what you would get:

    #!/opt/perl/bin/perl -w
    eval 'exec /opt/perl/bin/perl -S $0 ${1+"$@"}'
      if 0;
    $0 =~ s/^.*?(\w+)[\.\w+]*$/$1/;
    
    use strict;
    use Symbol;
    use vars qw{ $isEOF $Hold %wFiles @Q $CondReg
             $doAutoPrint $doOpenWrite $doPrint };
    $doAutoPrint = 1;
    $doOpenWrite = 1;
    # prototypes
    sub openARGV();
    sub getsARGV(;\$);
    sub eofARGV();
    sub printQ();
    
    # Run: the sed loop reading input and applying the script
    #
    sub Run(){
        my( $h, $icnt, $s, $n );
        # hack (not unbreakable :-/) to avoid // matching an empty string
        my $z = "\000"; $z =~ /$z/;
        # Initialize.
        openARGV();
        $Hold    = '';
        $CondReg = 0;
        $doPrint = $doAutoPrint;
    CYCLE:
        while( getsARGV() ){
        chomp();
        $CondReg = 0;   # cleared on t
    BOS:;
    # s/^\([0-9]*\)[:].*/\1/p
    { $s = s /^(\d*)[:].*/${1}/s;
      $CondReg ||= $s;
      print $_, "\n" if $s;
    }
    EOS:    if( $doPrint ){
                print $_, "\n";
            } else {
            $doPrint = $doAutoPrint;
        }
            printQ() if @Q;
        }
    
        exit( 0 );
    }
    Run();
    
    # openARGV: open 1st input file
    #
    sub openARGV(){
        unshift( @ARGV, '-' ) unless @ARGV;
        my $file = shift( @ARGV );
        open( ARG, "<$file" )
        || die( "$0: can't open $file for reading ($!)\n" );
        $isEOF = 0;
    }
    
    # getsARGV: Read another input line into argument (default: $_).
    #           Move on to next input file, and reset EOF flag $isEOF.
    sub getsARGV(;\$){
        my $argref = @_ ? shift() : \$_; 
        while( $isEOF || ! defined( $$argref = <ARG> ) ){
        close( ARG );
        return 0 unless @ARGV;
        my $file = shift( @ARGV );
        open( ARG, "<$file" )
        || die( "$0: can't open $file for reading ($!)\n" );
        $isEOF = 0;
        }
        1;
    }
    
    # eofARGV: end-of-file test
    #
    sub eofARGV(){
        return @ARGV == 0 && ( $isEOF = eof( ARG ) );
    }
    
    # makeHandle: Generates another file handle for some file (given by its path)
    #             to be written due to a w command or an s command's w flag.
    sub makeHandle($){
        my( $path ) = @_;
        my $handle;
        if( ! exists( $wFiles{$path} ) || $wFiles{$path} eq '' ){
            $handle = $wFiles{$path} = gensym();
        if( $doOpenWrite ){
            if( ! open( $handle, ">$path" ) ){
            die( "$0: can't open $path for writing: ($!)\n" );
            }
        }
        } else {
            $handle = $wFiles{$path};
        }
        return $handle;
    }
    
    # printQ: Print queued output which is either a string or a reference
    #         to a pathname.
    sub printQ(){
        for my $q ( @Q ){
        if( ref( $q ) ){
                # flush open w files so that reading this file gets it all
            if( exists( $wFiles{$$q} ) && $wFiles{$$q} ne '' ){
            open( $wFiles{$$q}, ">>$$q" );
            }
                # copy file to stdout: slow, but safe
            if( open( RF, "<$$q" ) ){
            while( defined( my $line = <RF> ) ){
                print $line;
            }
            close( RF );
            }
        } else {
            print $q;
        }
        }
        undef( @Q );
    }
    

    Not exactly worth doing on small expressions.

    0 讨论(0)
  • 2021-01-18 01:42

    Suggestion: Use Perl regular expressions and replacements instead of grep or sed.

    It's approximentally the same syntax, but more powerful. Also in the end it will be more efficient than invoking the extra sed process.

    0 讨论(0)
  • 2021-01-18 01:50

    Here's how you can use Perl as a replacement for Sed:

    Instead of:

    sed "s/xxx/yyy/g" files_to_process
    

    Use:

    perl -i.bak -pe "s/xxx/yyy/g" files_to_process
    

    This will modify the files in-place and make a backup (.bak) of each modified file.

    0 讨论(0)
提交回复
热议问题