in reply to Re: remove files
in thread remove files

I tried the split function, but got an error

print "Please enter the files to be removed: \n"; my @removed_files = split, <STDIN>; foreach my $file (@removed_files) { print "FILE: $file \n"; unlink ($file); } ~

Here is the error thrown

Please enter the files to be removed: Use of uninitialized value $_ in split at ./Chapter13_Exer4a line 14.

TIA the Catfish

Replies are listed 'Best First'.
Re^3: remove files
by haukex (Archbishop) on Nov 25, 2019 at 21:42 UTC
    my @removed_files =  split, <STDIN>;

    You have a comma after the split, so Perl is reading that as split(), <STDIN>, which will try to operate on the special variable $_, which is why you're getting that warning. If you want to read all the lines from STDIN and have each element of the array be one line, it's enough to say:

    my @removed_files = <STDIN>; chomp(@removed_files);

    I added the chomp to remove the newline that each line will have at the end. Also, I might suggest a different variable name for clarity, such as @files_to_remove, and also you should check the return value of unlink to see if it actually removed a file. For example:

    my $removed = unlink($file); print "Removed $removed file(s).\n"; # - or - unlink($file) == 1 or die "Failed to unlink $file: $!";
Re^3: remove files
by Don Coyote (Hermit) on Nov 25, 2019 at 21:32 UTC

    You should validate the data to ensure you are getting only the number of files you expect.

    #!/Perl -T $what_i_am_about_to_type_at_prompt = 'file to remove.gah'; print "Please enter the file to be removed: \n"; my @file_I_intend_to_remove = <STDIN>; @file_I_intend_to_remove == 1 or die 'incorrect number of files sup +plied'; my $file_i_am_about_to_unlink = shift @file_I_intend_to_remove; unless( $file_i_am_about_to_unlink eq $what_i_am_about_to_type_at_p +rompt ){ printf "%s\n", $file_i_am_about_to_unlink; die 'for the love of ice-cream, don't do an unlink operation jus +t yet'; } # even if it matches you still need to untaint it. $file_i_am_about_to_unlink =~ m/\A(file\sto\sremove\.gah)\Z/ or die 'taint is a pain in the hyperbola, but I enjoy having a wor +king operating system'; $file_i_am_about_to_unlink = $1; # now i can unlink the file as it is the one i am expecting to unli +nk; printf "unlinking %s\n", $file_i_am_about_to_unlink; # unlink $file_i_am_about_to_unlink;

    The context you supply to the input operator, determines whether it returns the first field, or all fields. The input operator splits on IFS the Input Field Separator, $/. You do not need to call split on the input operator.

    You do need to check what your input is once it is in the array, and before you pass that input to a function. This is data-validation, more commonly known as untainting. For why we do this see perldoc perlsec. To scrub the data, you need to substitute a pattern match back into your scalar.

    perlsec is dense. keep it simple and only use straightforward file names while testing.

    my $filename = 'filename.fxt'; my $scrubbed = s/\A(filename\.fxt)\Z/$1/ or die 'need to read up on regex a bit more';

    Common error is to forget to chomp the string, or to try and use filenames with non-printable characters in them, such as spaces. Review chapter 8 to cover what you will need for this.

    edit removed split, re Re^4: remove files

      Your code still has the "split, <STDIN>", so it doesn't really address the problem the OP is having. Advice on playing it safe is certainly not bad, but this thread is in the context of a Learning Perl exercise, taint mode is probably a later chapter...

        Yes, I see your point. I have probably supplied more info than I needed to in my first response.

        removed split, from line