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