Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?
 
PerlMonks  

Save all but line 32!

by bronto (Priest)
on Sep 18, 2002 at 16:05 UTC ( [id://198884]=perlmeditation: print w/replies, xml ) Need Help??

Hello *

A few minutes ago a colleague of mine asked me if *NIX had a command that could be easily used to delete the 32nd line from a bunch of file. awk, sed and cat (and some combinations of them) came to mind, but I preferred a full Perl approach:

perl -i.bak -ne 'print unless ++$i == 32' filename

But since TIMTOWTDI, how would you do the same with a one liner (and, if you want to use modules, using only modules in bundle with perl)?

Ciao!
--bronto

# Another Perl edition of a song:
# The End, by The Beatles
END {
  $you->take($love) eq $you->made($love) ;
}

Replies are listed 'Best First'.
Re: Save all but line 32!
by davorg (Chancellor) on Sep 18, 2002 at 16:11 UTC

    Why introduce your own variable?

    perl -i.bak -ne 'print unless $. == 32' filename
    --
    <http://www.dave.org.uk>

    "The first rule of Perl club is you do not talk about Perl club."
    -- Chip Salzenberg

Re: Save all but line 32!
by jmcnamara (Monsignor) on Sep 18, 2002 at 17:00 UTC

    Here is another way:     perl -i -pe '$_=$}if$.==32' file

    Update: To handle multiple files it needs to be a little longer:     perl -i -pe '$_=$}if$.==32;$.=$[if+eof' file1 file2 ...

    But this is probably the cleanest way:     awk 'FNR != 32' file1 file2 ...

    --
    John.

Re: Save all but line 32!
by perrin (Chancellor) on Sep 18, 2002 at 16:30 UTC
    Not as fast and doesn't handle a list of files, but for entertainment value:
    perl -MTie::File -e 'tie @file, 'Tie::File', $ARGV[0]; splice @file, 3 +1, 1;' filename
    (Tie::File is in the standard lib now.)
      Some None of the other solutions will not correctly handle a list of files either (only the ones using $. will). And this one is easily extended to do so: perl -MTie::File -e 'tie(@file, 'Tie::File', $_) and splice @file, 31, 1 for @ARGV' file1 file2 file3 Update: zigdon is right. I should have tested.

      Makeshifts last the longest.

        I thought $. only resets on a close call? meaning the <> operator doesn't reset it, since it never closes the filehandles. So the following code will omit the 35th line only for the first file, but not for any other file:
        perl -ne 'print unless $. == 35' file1 file2
        Is that correct?

        -- Dan

Re: Save all but line 32!
by zigdon (Deacon) on Sep 18, 2002 at 16:14 UTC
    not very different, but should be slightly faster:
    perl -i.bak -ne 'if ($. < 32) { print } elsif ($. > 32) { print <>}' f +ilename
    I think it'll be faster since once you pass the 32nd line, you don't need to check anymore, you can just dump out the rest of the file. Note that $. might not do what you expect, depending on the value of $/. See perlvar.

    -- Dan

      Penny wise but pound foolish.

      Your program will read in all lines after line 32 before printing them. Usually that will be a lot slower than the comparison you save.

      I do not understand your remark about $/. You aren't setting it, nor does any of the switches influence it. How could $/ be any different from the default?

      My suggestion for the program:

      perl -i -nwe 'print unless 32 .. 32' filename
      Abigail
        This confuses me. I don't see how this would work. It looks like it will print no lines since 32 .. 32 should return either 1 (the number of elements in the list) or 32 (the last element in the list) both of which are "true". I am betting the later, but I am not sure. Would you kindly point out where I am wrong?
        perl -- executes perl
        -i   -- in-place editing
        -n   -- implict loop
        -w   -- turn on warnings (why?)
        -e   -- execute the following string as the program
        
        print    -- print what is in $_ (only executed if the unless is  false)
        unless   -- execute the previous command if the result of the following
                    expression is 0, undef, or '' (or the equivalent)
        32 .. 32 -- construct a list containing the numbers 32 through 32
        filename -- the file to edit
        
Re: Save all but line 32!
by cephas (Pilgrim) on Sep 18, 2002 at 17:18 UTC

      Very nice. ++

      I like the twisted logic but the best part is the bare $ at the end. I had to run it through B::Deparse to see what was happening:

      $ perl -MO=Deparse -pe '$_=$' LINE: while (defined($_ = <ARGV>)) { $_ = $; } continue { die "-p destination: $!\n" unless print $_; }

      It shows that in this case $ gets interpreted as $; the subscript separator. However, this means that your code inserts an extra character in the file as shown by this:     perl -pe '$.-32or$_=$' file | cat -A

      But I'm still not sure why perl inserts that semicolon. It doesn't in other cases:

      $ perl -MO=Deparse -pe '$_=$.' LINE: while (defined($_ = <ARGV>)) { $_ = $. } continue { die "-p destination: $!\n" unless print $_; }

      Anyone have an explanation for this last point?

      Update: blakem's answer below is right. This last case is a perl 5.005 issue with B::Deparse.

      --
      John.

        I seem to get the semicolon with your second case:
        % perl5.6.1 -MO=Deparse -pe '$_=$.' LINE: while (defined($_ = <ARGV>)) { $_ = $.; } continue { die "-p destination: $!\n" unless print $_; } % perl5.8.0 -MO=Deparse -pe '$_=$.' LINE: while (defined($_ = <ARGV>)) { $_ = $.; } continue { die "-p destination: $!\n" unless print $_; }
        Update: Response to above update: with 5.00503 I get:
        % perl5.00503 -MO=Deparse -pe '$_=$.' LINE: while (defined($_ = <ARGV>)) { $_ = $. } continue { die "-p destination: $!\n" unless print $_; }

        -Blake

      won't "32or" get interpreted as a single token?
        won't "32or" get interpreted as a single token?

        No it won't.

        or32 would be seen as an identifier, though.

(OT) Re: Save all but line 32!
by JayBonci (Curate) on Sep 19, 2002 at 07:59 UTC
    Offtopic for the site, but sed's a much better tool for that job. It's very easy to do with sed addressing:
    sed -n 32\!p filename
    Sadly, I don't have a clever or shorter way to do it in perl. The number 32 can be anything, of course

        --jb
      Golf time! :^) sed -e 32d filename

      Makeshifts last the longest.

        8 instead of 11 chars (excluding the filename) :^)

        t filename^G32^M^D^S

        T is my editor

        ^G32 := goto line 32

        ^M := return to terminate/execute the goto

        ^D := delete the line

        ^S := Save and exit!


        Cor! Like yer ring! ... HALO dammit! ... 'Ave it yer way! Hal-lo, Mister la-de-da. ... Like yer ring!
Way OT....
by ellem (Hermit) on Sep 19, 2002 at 02:35 UTC
    You wote:
    # Another Perl edition of a song: # The End, by The Beatles END { $you->take($love) eq $you->made($love) ; }
    John and Paul wrote:
    # Another Perl edition of a song: # The End, by The Beatles END { $you->take($love) eq $you->make($love) ; }

    --
    ellem@optonline.net
    There's more than one way to do it, but only some of them actually work.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://198884]
Approved by valdez
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (4)
As of 2024-04-19 17:27 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found