Walt Mankowski on 12 Oct 2012 16:15:25 -0700


[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]

Re: [PLUG] perl -i question


On Fri, Oct 12, 2012 at 06:05:28PM -0400, JP Vossen wrote:
> See my previous "Perl one-liner to remove duplicates without
> changing file order" email for background.
> 
> I can understand why this might not work (note: -i'.bak'):
> 	$ perl -ni'.bak' -e '$line{$_} = $.; END { for
> (sort{$line{$a}<=>$line{$b}} keys %line) {print} }' /tmp/sample.hist
> 
> I'm *guessing* the END{} block executes *after* all the file handles
> are closed, so you end up writing nothing to your file.  (Hope you
> have a backup.)
> 
> But why doesn't this work:
> 	$ perl -i'.bak' -e 'while (<>) {$line{$_} = $.} for
> (sort{$line{$a}<=>$line{$b}} keys %line) {print}' /tmp/sample.hist
> 
> These *do* work:
> 	$ perl -ni'.bak' -e '$line{$_}++ or print' /tmp/sample.hist
> 	$ perl -i'.bak' -e 'while (<>) { $line{$_}++ or print }' /tmp/sample.hist
> 
> But these do not either:
> 	$ perl -ni'.bak' -e '$line{$_}++; END { for
> (sort{$line{$a}<=>$line{$b}} keys %line) {print} }' /tmp/sample.hist
> 	$ perl -i'.bak' -e 'while (<>) {$line{$_}++} for
> (sort{$line{$a}<=>$line{$b}} keys %line) {print}' /tmp/sample.hist
> 
> So WTH???  I've Googled the heck out and this and read
> http://perldoc.perl.org/perlrun.html#*-i*[_extension_] 10 times, but
> nothing I try works, print always goes to STDOUT and my file always
> ends up zero bytes.  I'm guessing the "select(STDOUT);" in line 21
> of the listing in the URL is what is getting me, but I can't figure
> out how to work around it in Perl.  (I can easily work around this
> outside of Perl, I just don't wanna.)  I've tried all kinds of crazy
> stuff like:
> 	$ perl -i'.bak' -e 'while (<>) {$line{$_} = $.;} select(ARGV); for
> (sort{$line{$a}<=>$line{$b}} keys %line) {print}' /tmp/sample.hist
> 	$ perl -i'.bak' -e 'while (<>) {$line{$_} = $.;} select(ARGVOUT);
> for (sort{$line{$a}<=>$line{$b}} keys %line) {print}'
> /tmp/sample.hist
> 	$ perl -i'.bak' -e 'while (<>) {$line{$_} = $.;} for
> (sort{$line{$a}<=>$line{$b}} keys %line) {print ARGV}'
> /tmp/sample.hist
> 	$ perl -i'.bak' -e 'while (<>) {$line{$_} = $.;} for
> (sort{$line{$a}<=>$line{$b}} keys %line) {print ARGVOUT}'
> /tmp/sample.hist
> 
> And anything else I can think of, but it all silently fails (and
> nukes my file) on both Debian Perl 5.10.1 and XP ActiveState (810)
> 5.8.4, so I'm pretty sure Perl is WaD and I'm just missing something
> obvious.
> 
> Anyone know what I am doing wrong?

Yes, the "select(STDOUT) is what's getting you.  Notice that it's
outside of the "while (<>)" loop.  Once you fall out of that loop,
print goes to STDOUT instead of the file.

At a higher level, what's really getting you is that the -i flag has
special logic to handle multiple files on the command line.  Whenever
if gets to EOF on one file, it closes that one and opens the next one.
(That's what's going on when it checks $ARGV.)  Because of that,
you've got to print the lines while you've still got the file open.
You're circumventing that by gathering them all up printing the lines
later.

Walt

Attachment: signature.asc
Description: Digital signature

___________________________________________________________________________
Philadelphia Linux Users Group         --        http://www.phillylinux.org
Announcements - http://lists.phillylinux.org/mailman/listinfo/plug-announce
General Discussion  --   http://lists.phillylinux.org/mailman/listinfo/plug