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

So I am writing a script that will backup the given file(s) to a Backups directory. I have the portion working for checking for the directory and creating a new one if it doesn't exist, as well as copying the original file to the directory with a new name.

What I want to be able to do now is do this for multiple files that are specified either with ARGV, or if the user forgets that, from either a comma or space separated list from STDIN. I'm not sure how to do this part however. Do I somehow do this with a foreach loop, or am I supposed to use a while? Do I need to push STDIN to an array using the comma or space as the delimiter?

Here's an example of my current code:

my $filename = shift @ARGV; unless ($filename) { print "Enter file name(s) to be backed up:\n"; $filename = <STDIN>; chomp $filename; } if ( -e $filename ) { if ( -d "Backups") { # copy file to directory } else { mkdir "Backups"; # copy file to directory } }

Thanks for any help you can provide.

Edit: I now have the script working to read multiple files from the command line, and I can take the space separated list from STDIN and input into an array. I still cannot figure out how to get it to step through each element of the STDIN array like I have it working for ARGV.

My if statements have been moved into a while loop: while ($filename). I added $filename = shift before I close out the while loop. The initial portion of my code has been updated to this (second try, this time trying an if/else):

if (!@ARGV) { print "Enter file name(s) to be backed up, separated by spaces:\n" +; $filename = <STDIN>; chomp $filename; my @filenames = split(/\ /, $filename); $filename = shift(@filenames); } else { $filename = shift(@ARGV); }

Replies are listed 'Best First'.
Re: Process multiple filenames from command line or STDIN
by graff (Chancellor) on Mar 18, 2016 at 23:39 UTC
    There's something I don't understand. You say:

    ...backup the given file(s)...

    implying that you would do more than one file in a given run, if that's what the user wants to do, and the user makes this clear EITHER by putting two or more file names as command line args (or a wildcard pattern that matches two or more files, which amounts to the exact same thing), OR, with no command-line args, typing two or more file names and hitting <enter> after the script has started.

    But then in either case, the code you posted ignores all but the first file name. That seems inconsistent with your stated purpose.

    Anyway, here's how I would approach things:

    my @files_to_do; if ( @ARGV and -f $ARGV[0] ) @files_to_do = @ARGV; } else { print "Enter file name(s), separated by space and/or newline:\n" i +f ( -t ); while (<STDIN>) { chomp; push @files_to_do, split //; } } die "Nothing to do\n" unless @files_to_do; # now do something that loops over @files_to_do...
    Note the "if (-t)" -- that causes the prompt message to be printed only if STDIN is coming from a terminal (rather than from some other command whose output is being piped to your script).

    Also note that if the user decided to type in file names after the script has started, the approach I'm suggesting here requires that he must also type an EOF control character (^D on linux/unix, ^Z (I think) on windows), so that perl knows to stop reading STDIN.

    Accepting input from a pipe is great stuff - e.g. using a *n*x shell environment, you could do stuff like:

    ls | my_backup.pl find some_path -name '*.foo' | my_backup.pl
    and countless other useful variants (including helper commands like grep, etc., as filters on the input to your script). These make it less likely that someone would need to type file names at all -- and that's good, because typing file names is error-prone, and it's a drag (especially if you don't have access to auto-completion or wildcard globs or decent line-editing keystrokes, which is what happens when you use the default method of typing when perl is reading from the terminal keyboard).

    (Update: I'll just mention that I never write a perl script such that it prompts the user to type something via STDIN after the script starts. If some input from the user is needed, and there are no command-line args, and nothing being piped to the script, my scripts will die with a "Usage: ..." synopsis, explaining what sort(s) of input are expected from the user at the point when the script is first launched.)

Re: Process multiple filenames from command line or STDIN
by Marshall (Canon) on Mar 18, 2016 at 22:16 UTC

      But I'm not trying to use a wildcard in the command line, so I'm not sure how this applies to my question.

      I am using Ubuntu.

        Ok. I was thinking in a more complex direction.

        If you have an enumerated list (no wildcards)on the command line, then you need to read multiple things from the command line.

        Assign an array, @names = @ARGV instead of scalar like $names. iterate over the @names.

        please when you update code, do not delete the original post. This just confuses folks.

        update: oh I see that I'm wrong here. I'm doing this on a very small screen and I didn't see it. Oops.