use a variable with whitespace Perl

928 Views Asked by At

I am currently working on a project but I have one big problem. I have some picture with a whitespace in the name and I want to do a montage. The problem is that I can't rename my picture and my code is like that :

$pic1 = qq(picture one.png);
$pic2 = qq(picture two.png);

my $cmd = "C:\...\montage.exe $pic1 $pic2 output.png";

system($cmd);

but because of the whitespace montage.exe doesn't work. How can I execute my code without renaming all my pictures?

Thanks a lot for your answer!

4

There are 4 best solutions below

1
On

You can properly quote the filenames within the string you pass to system, as @Borodin shows in his answer. Something like: system("montage.exe '$pic1' '$pic2'")

However, A more reliable and safer solution is to pass the arguments to montage.exe as extra parameters in the system call:

system('montage.exe', $pic2, $pic2, 'output.png')

Now you don't have to worry about nesting the correct quotes, or worry about files with unexpected characters. Not only is this simpler code, but it avoids malicious injection issues, should those file names ever come from a tainted source. Someone could enter | rm *, but your system call will not remove all your files for you.

Further, in real life, you probably are not going to have a separate scalar variable for each file name. You'll have them in an array. This makes your system call even easier:

system('montage.exe', @filenames, 'output.png')

Not only is that super easy, but it avoids the pitfall of having a command line too long. If your filenames have nice long paths (maybe 50-100 characters), a Windows command line will exceed the max command length after around 100 files. Passing the arguments through system() instead of in one big string avoids that limitation.

5
On

Alternatively, you can pass the arguments to montage.exe as a list (instead of concatenating them all into a string):

use strict;
use warnings;

my $pic1 = qq(picture one.png);
my $pic2 = qq(picture two.png);

my @cmd = ("C:\...\montage.exe", $pic1, $pic2, "output.png");

system(@cmd);
0
On

In unix systems, the best approach is the multi-argument form of system because 1) it avoids invoking a shell, and 2) that's the format accepted by the OS call. Neither of those are true in Windows. The OS call to spawn a program expects a command line, and system's attempt to form this command line is sometimes incorrect. The safest approach is to use Win32::ShellQuote.

use Win32::ShellQuote qw( quote_system );

system quote_system("C:\\...\\montage.exe", $pic1, $pic2, "output.png");
2
On

You need to put quotes around the file names that have spaces. You also need to escape the backslashes

my $cmd = qq{C:\\...\\montage.exe "$pic1" "$pic2" output.png};