Hi, The below code works fine.

No, it does not. It actually is dangerously wrong.

chdir '/user/perl_monks' || die "cannot change dir: $!"; open(my $fh, "ls|") || die "cannot open the file handle:$!"; my @files = <$fh>; chomp @files; for ( @files) { system ( "scp $_ username\@host:/any/folder/" ); }

Here is what's wrong with this code:

  1. Newlines are legal in filenames. So, ls may return a single filename splitted over two or more lines, resulting in a filename splitted over two or more elements of @files.
  2. At least GNU ls behaves differently depending on environment variables. It may quote and/or escape special characters in filenames (see GNU ls documentation), but your code assumes sane defaults.
  3. Various characters that have a special meaning to the shell are legal in filenames. (In fact, all characters except ASCII NUL and / are legal in filenames.) So you may legally name a file $(rm -rf /) or $(rm -rf *). Because your code use the single-argument form of system, and it does not clean up $_ before interpolation, the shell will be invoked, and it will interpret those filenames according to shell rules. So, with these filenames, you will likely delete a lot of files.
  4. You blindly assume that system and scp succeed.
  5. Shells are different. Quoting rules change from shell to shell, so there is no safe way to handle the shell.

And here is how to fix it:

  1. Don't use the shells to read filenames from a directory. glob will do, as will opendir, readdir, closedir, and IO::Dir. For a simple "ls" with sane defaults, glob('*') should do the job.
  2. See above. Avoiding ls also avoids all quoting and escaping issues of ls.
  3. Use the multiple-argument form of system, i.e. system('/path/to/scp',$_,'username@host:/any/folder');.
  4. Check the return value of system to see if system or scp failed. Also look at $!.
  5. Avoid the shells. It just makes life harder. If you want a harder life, read http://www.in-ulm.de/~mascheck/various/.
I also found that special characters like @ inside the system qq needs to be escaped.

This has nothing to do with system, you always have to escape @ inside double quoted strings.

Also note that the qx// operator, also in the backticks form, can also be used in list context. There, it returns one list element per line of output. (This is documented in I/O Operators.) You don't have to use pipe-open and readline (<$handle>), chomp(my @files=`ls`) would be sufficient. But see above for why this is at least problematic, if not dangerous.

Alexander

--
Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)

In reply to Re^2: scp output without having to use "Net::SCP" in Perl by afoken
in thread scp output without having to use "Net::SCP" in Perl by pjzero@90

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.