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

So me and a co-worker are trying to do a very simple task. We want to do some file manipulation on a single file and for now we are testing some things from command line which is where we found this lil strangity (this a word?).

Given a known filename and due to the way we are going to run the finished product, we want to take that filename from stdin and work it a lil. So, we did the following:

For now, "saveme" is our test file (and its a blank touched file).

ls saveme | perl -n -e ' while ( <> ) { chomp; tr/\/*@//d; # remove shell aliased junk from ls open(F,$_); print eval{(lstat(F))[9]},"\n"; close(F); }'

Mind you that this snippet is only one thing we tried. Also note that we realize that there are a plethora of other ways to do this so that it works. However, it is this one phenomena that we are curious about.

Some of the other things we tried were:

$ls saveme | perl -n -e ' print "file is: ". <>,"\n"; ' file is: $ls saveme | perl -n -e ' my @files = <>;print "file: @files\n"; ' file:

What am I (are we) missing here? It has to be some fundamental rule I am forgetting/disregarding.

TIA

_ _ _ _ _ _ _ _ _ _
- Jim
Insert clever comment here...

Replies are listed 'Best First'.
Re: Oddity...losing filename from stdin - very wierd
by Dog and Pony (Priest) on Apr 09, 2002 at 16:51 UTC
    Try it on a directory with several files. You should see that you only get half the files in the directory.

    Why is that? A little deparse gives us the answer:

    perl -MO=Deparse -n -e 'print "file is: ".<>;'
    Should give us:
    LINE: while (defined($_ = <ARGV>)) { print 'file is: ' . <ARGV>; }
    So you see, every line of this loop, one filename is unshifted from ARGV going into $_, and one is unshifted and printed, making you miss the first, the third, etc.

    What you need to do is something like

    ls dir | perl -n -e 'print "File is $_"'


    You have moved into a dark place.
    It is pitch black. You are likely to be eaten by a grue.
      Fellow monk, if I could vote you up anymore I would. You are correct! It did not occur to me that perl is invoked for every instance of output from ls. Thus, it was not necessary to push the output of ls into a while loop (unles I wanted to do something more granular to the output of each instance from ls). Thanks a bunch! See? It was something I was doing wrong! :)

      Another lesson learned! I'll log that away! :) Thank you much!

      _ _ _ _ _ _ _ _ _ _
      - Jim
      Insert clever comment here...

        You missread what Dog & Pony is saying. Perl isn't "Invoked for every instance of output from ls" ... the problem you had was using the -n option of perl in addition to your own while loop. You need one, or the other, but not both.
Re: Oddity...losing filename from stdin - very wierd
by Rich36 (Chaplain) on Apr 09, 2002 at 16:48 UTC

    I think maybe the difference is using the diamond (<>) operator vs. globbing.

    If you want to print out the contents of a file use the diamond operator.

    % perl -e 'print while (<>);' yourfilenamehere

    If you want to print out a list of files, use the glob operator and specify which file names to print. For example, print the names of all the perl files in the dir

    % perl -e 'print while (<*.pl>);'

    Rich36
    There's more than one way to screw it up...

      Right. You are getting into the other ways to do the task and if you are saying that there is no other way to do what we want then I suppose I can go with that but reluctantly. I definitely see something wrong here. What I am trying to do should be possible to do and it probably is but I am doing something wrong.

      Your first example is not what I trying to do. I am not trying to get the contents of the file but am actually trying to pipe the filename itself to the perl script. Again, note, that the reason we are doing it this way is for a more grand scheme so this is only pseudocode (if you will) but it is a good mimic of what we want to do in the end.

      Your second example, while a good thought, is still steering away from how we want to work the idea. You are using Perl to glob the files. What we want to do is simply send a single filename to perl via ls. :)

      _ _ _ _ _ _ _ _ _ _
      - Jim
      Insert clever comment here...

Re: Oddity...losing filename from stdin - very wierd
by thelenm (Vicar) on Apr 09, 2002 at 16:45 UTC
    I notice that you're piping the output of ls... are you doing this in the directory where saveme is located? If not, ls will produce no output (but an error message on STDERR). Are you sure that ls is producing what you think it is? Maybe you could try using echo "saveme" instead?
      Good question. In fact, I am in the right directory. I've even checked to make sure that the file is there.

      $ ls -l saveme -rw-r--r-- 1 jconner jconner 0 04-09 12:07 saveme

      I also decided to check a few more ways and found that the first file is getting skipped! Very wierd. I've never seen this before.

      $ ls saveme .vimrc | perl -n -e ' print <>,"\n";' saveme $ ls saveme .vimrc | perl -n -e ' >while (<> ) { > print $_,"\n"; >} >' saveme

      Notice in these examples that I gave ls two files to query and this it should be that ls pipes out the two files to the perl one-liner. Btw, I double-checked that .vimrc exists too. :)

      $ ls -l .vimrc -rw-r--r-- 1 jconner jconner 831 01-18 17:55 .vimrc

      _ _ _ _ _ _ _ _ _ _
      - Jim
      Insert clever comment here...