rduke15 has asked for the wisdom of the Perl Monks concerning the following question:

Hello,

Is the following somehow possible?

  echo stuff | perl -ne '$x=shift; print "x=$x\n"' myarg

All I get is "Can't open myarg: No such file or directory.". I understand why, but is there some elegant solution to the problem?

Thanks.

Replies are listed 'Best First'.
Re: Differentiating STDIN from arguments when using -n ?
by bart (Canon) on Sep 15, 2007 at 11:06 UTC
    You have to consume the argument in @ARGV before the implicit loop starts. What's more, you must make sure the argument is consumed only once. Hence, most elegant solution: do it in a BEGIN block.
    echo stuff | perl -ne 'BEGIN{ $x=shift @ARGV; } print "x=$x\n"' myarg
    (untested)

    Is this like what you had in mind?

      I tried this but somehow $x seems to become undef after the first time through the implicit loop.

      $ cat gibberish This is a couple of lines of crud $ cat gibberish | perl -Mstrict -Mwarnings -ne ' > my $x; > BEGIN {$x = shift @ARGV; print qq{BEGIN - $x\n}} > print qq{x = $x\n$_};' myarg BEGIN - myarg x = myarg This is a couple Use of uninitialized value in concatenation (.) or string at -e line 4 +, <> line 2. x = of lines of crud $

      I wonder what is causing this.

      Cheers,

      JohnGG

        Don't declare the $x — it's just a one-liner. Perl wraps a while(<>) { ... } loop around the code you put there (really!), so it's a new $x for every line in the file.

        See for yourself:

        perl -n -MO=Deparse -e 'my $x' foo
        produces:
        LINE: while (defined($_ = <ARGV>)) { my $x; } -e syntax OK

      Thanks a lot. Indeed, with the BEGIN block, it now works.

      In case someone is curious, I needed it in a shell script for a convoluted situation: to be able to un-mount a disk cleanly, I needed a smart sort on the mounted partitions of the disk.

      # $dest was set to "sdb" through a shell argument mounted_disks=$(mount | perl -nae 'BEGIN{$d=shift}; push @m, $F[2] if +m{/dev/$d}; END{print join(" ", sort {length($b)<=>length($a)} @m)}' +$dest) umount -l $mounted_disks

      Thanks to Perl and the Perl Monks, it works.

        You don't really need a loop for that, you could do it like this:

        mounted_disks=$(mount | perl -le'$d = shift; print join " ", sort { le +ngth( $b ) <=> length( $a ) } map m{/dev/$d} ? (split)[2] : (), <>' $ +dest)

        Or even move the mount command into the perl code:

        mounted_disks=$(perl -le'$d = shift; print join " ", sort { length( $b + ) <=> length( $a ) } map m{/dev/$d} ? (split)[2] : (), qx(mount)' $d +est)
Re: Differentiating STDIN from arguments when using -n ?
by almut (Canon) on Sep 15, 2007 at 11:40 UTC

    Maybe something like this?

    echo stuff | perl -ne '$x=shift; print "x=$x\n"' - myarg

    It's always a good idea to tell what the expected outcome is :)

    With one line of input on stdin (like your echo), this produces the same result as bart's suggestion. With more lines on stdin, however, you'd get different behaviour. Assuming that stuff is a file containing the two lines "foo" and "bar", then when doing

    cat stuff | perl -ne '$x=shift; print "x=$x\n"; print "<>=$_"' - myarg + myarg2 stuff

    you'd get

    x=myarg <>=foo x=myarg2 <>=bar x= <>=foo x= <>=bar

    i.e. you'd shift as many arguments from @ARGV as there are lines on stdin. For the remaining arguments, Perl would try to open the respective filename.

Re: Differentiating STDIN from arguments when using -n ? (-s)
by rhesa (Vicar) on Sep 15, 2007 at 12:14 UTC
    perl -nse 'print if /$myarg/' -- -myarg=^#