in reply to Refining my Program

I want to see some if there's neat some tricks I'm overlooking.

Oh, most definitely!

By making use of Perl's command-line/#!switches, you can turn your script into a one-liner...

perl -aF, -pli -e '$_ = "@F[1,0]"' test.txt

...although you may need to supply an argument to -i and change the quotes (ie, ' for ", and qq() for ') on OSes like Windows.

perl -aF, -pli.bak -e "$_ = qq(@F[1,0])" test.txt

    --k.


Update: Flipping " to ' won't work because of interpolation, so you really need something like qq() instead. Oops.

Update 2: Added explanation for the curious...

This isn't 100% accurate (for that, you should thumb through the docs or --the horror!-- Perl's source), purposely omitting things for brevity, but it should give a decent idea how the above one-liner works.

-e tells Perl should use the next argument as the code to execute rather than reading some in from a script.

$_ = "@F[1,0]";

... with "@F[1,0]" really just being a Perl idiom for ...

$_ = join( $", $F[1], $F[0] );

... where $" is, by default, set to a single space.

-p then wraps our code inside a while loop, assigning each line of files we specify after our code (ie, test.txt) to $_ and then printing $_ back out afterwards.

while (<>) {
    $_ = join( $", $F[1], $F[0] );
} continue {
    print $_;
}

And since we change the contents of $_, our replacement gets printed instead of the original line!

So that we don't have to worry about line endings, -l is used to autochomp each line, and suffix all prints with $\ ("\n" in this instance, as we're reading line by line).

while (<>) {
    chomp $_;
    $_ = join( $", $F[1], $F[0] );
} continue {
    print $_, $\;
}

-a then tells Perl to autosplits each line into the @F array.

while (<>) {
    chomp $_;
    @F = split( ' ', $_ );
    $_ = join( $", $F[1], $F[0] );
} continue {
    print $_, $\;
}

However, since we don't want -a to split on whitespace (the default), we use -F, to change our split pattern to commas instead.

while (<>) {
    chomp $_;
    @F = split( /,/, $_ );
    $_ = join( $", $F[1], $F[0] );
} continue {
    print $_, $\;
}

Finally, -i is used to do an "in-place edit" on all files parsed with the <>-operator. (See also $ARGV.)

$extension = $i_flag; # -i.bak
while (<>) {
    if ( $ARGV ne $oldargv ) {
        $backup = $ARGV . $extension;
        rename( $ARGV => $backup );
        open   ARGVOUT, ">$ARGV";
        select ARGVOUT;
        $oldargv = $ARGV;
    }
    chomp $_;
    @F = split( /,/ => $_ );
    $_ = join( $" => $F[1], $F[0] );
} continue {
    print $_, $\;
}
select STDOUT;

Replies are listed 'Best First'.
Re: Re: Refining my Program
by mephit (Scribe) on May 25, 2002 at 04:43 UTC
    OK, this definitely gets a ++ from me. I sort of understand how each switch operates by itself, but when I try to put them all together for this one-liner, my brain explodes. So, can anyone give a step-by-step explanation of this thing? Thanks.

    --

    There are 10 kinds of people -- those that understand binary, and those that don't.