2

I am trying to pass an array of arguments to the qx operator. Consider

my @files=qw(A.txt B.txt);
print qx/ls "@files"/;

This gives error:

ls: cannot access A.txt B.txt: No such file or directory

whereas substituting the array arguments explicitly:

print qx/ls A.txt B.txt/;

works fine. How can I pass a perl array to the qx operator such that each array element becomes a separate argument to the shell command?

2
  • Do you have file named A.txt and B.txt in current dir. If not this is expected error message of ls Commented May 10, 2014 at 11:12
  • 1
    @Tejas: that's the error message for a file called "A.txt B.txt", not for two files. Commented May 10, 2014 at 11:13

2 Answers 2

3

Drop the quotes, what you have is as if you typed ls "A.txt B.txt" in your shell.

print qx/ls @files/;

Warning: this doesn't work if you have files with spaces in their name in your array. You could single-quote those individually, but that doesn't sound like a good idea and handling all special chars is bound to break at some point. At which point I'd suggest not using an external program at all, use Perl features instead.

Sign up to request clarification or add additional context in comments.

Comments

3

In your case, using

qx/ls @files/;

is enough.

@files will be interpolated in the argument (which is a string) of qx//, there is no need to put it in a string.

If any element of your @files has space, then qx/ls @files/ would not work. For example, the following code

my @files=('A.txt', 'B.txt', 'C .txt');
print qx/ls @files/;

will give these errors:

ls: .txt: No such file or directory
ls: A.txt: No such file or directory
ls: B.txt: No such file or directory
ls: C: No such file or directory

This could be fixed by quoting each element of @files, one way to achieve that is

my @files=('A.txt', 'B.txt', 'C .txt');

my $files;
$files .= " \Q$_" for @files;

print qx/ls $files/;

Another way is using map:

my @files=('A.txt', 'B.txt', 'C .txt');
@files = map { "\Q$_" } @files;
print qx/ls @files/;

The above code will give the following errors (as expected)

ls: A.txt: No such file or directory
ls: B.txt: No such file or directory
ls: C .txt: No such file or directory

Update:

\Q cannot handle embedded newline in file name, as pointed out by @choroba. Possible fix of this problem, \'$_\', cannot handle embedded single quote. It looks like we need to combine them together:

my @files=('A.txt', 'B.txt', 'C .txt', "D\t.txt", "E\n.txt", "F'.txt", 'G".txt');

my $files;
$files .= m/\n/ ? " \'$_\'" : " \Q$_" for @files;

print qx/ls $files/;

This will give the following expected errors

ls: A.txt: No such file or directory
ls: B.txt: No such file or directory
ls: C .txt: No such file or directory
ls: D\t.txt: No such file or directory
ls: E\n.txt: No such file or directory
ls: F'.txt: No such file or directory
ls: G".txt: No such file or directory

1 Comment

Just a nitpick: It doesn't work for filenames with a newline.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.