Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer

Save all but line 32!

by bronto (Priest)
on Sep 18, 2002 at 16:05 UTC ( #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)?


# Another Perl edition of a song:
# The End, by The Beatles
  $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

    "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 ...


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
        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.


        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 $_; }


      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

      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) ; }

    There's more than one way to do it, but only some of them actually work.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlmeditation [id://198884]
Approved by valdez
[Corion]: Meh - anybody signed into Github? A wild spammer has appeared.
[Corion]: Otherwise, I'll open a ticket to get them killed in the evening

How do I use this? | Other CB clients
Other Users?
Others examining the Monastery: (8)
As of 2017-08-24 07:39 GMT
Find Nodes?
    Voting Booth?
    Who is your favorite scientist and why?

    Results (365 votes). Check out past polls.