I am trying to execute a system command. The problem is that 1) there is a space in the directory name for the directory path, and 2) there is a pipe and a redirection.
(2) means you are trying to execute a shell command, but you aren't running a shell. When using the single-argument form of system, Perl will invoke the command in a shell if it thinks necessary. But you aren't using the single-argument form of system.
system("mysqldump","--add-drop-table","-uroot","-ppassword", "mydataba +se","|","gzip","-9c",">","$backup_dir/mydatabase.sql.gz");
is the same as
mysqldump '-add-drop-table' '-uroot '-ppassword' 'mydatabase' '|' 'gzi +p' '-9c' '>' "$backup_dir/mydatabase.sql.gz"
at the prompt.
You have a couple of options.
Perl is the shell, so have Perl do the redirection.
use IPC::Open3 qw( open3 ); { local *FROM_MYSQLDUMP; open(local *INPUT, '<', '/dev/null') or die $!; open(local *OUTPUT, '>', "$backup_dir/mydatabase.sql.gz") or die $! +; my $mysqldump_pid = open3('<&INPUT', \*FROM_MYSQLDUMP, '>&STDERR', mysqldump => ( '--add-drop-table', '-u'.'root', '-p'.'password', 'mydatabase', ), ); my $gzip_pid = eval { open3('<&FROM_MYSQLDUMP', '>&OUTPUT', '>&STDERR', gzip => ( '-9c' ), ) }; if (!$gzip_pid) { my $e = $@; kill(KILL => $mysqldump_pid); waitpid($mysqldump_pid, 0); die($e); } waitpid($mysqldump_pid, 0); waitpid($gzip_pid, 0); }
You could craft a shell command and have the shell do the piping.
sub text_to_shell_lit(_) { return $_[0] if $_[0] =~ /^[a-zA-Z0-9_\-]+\z/; my $s = $_[0]; $s =~ s/'/'\\''/g; return "'$s'"; } my $mysqldump_cmd = join ' ', map text_to_shell_lit, mysqldump => ( '--add-drop-table', '-u'.'root', '-p'.'password', 'mydatabase', ); my $gzip_cmd = join ' ', map text_to_shell_lit, gzip => ( '-9c' ); my $output_file_lit = text_to_shell_lit("$backup_dir/mydatabase.sql.gz +"); system("$mysqldump_cmd | $gzip_cmd > $output_file_lit");
You could surely simplify at the cost of overhead.
IPC::Run and IPC::Run3 allows you to have a callback. You could use the callback as a pipe.
Again with IPC::Run and IPC::Run3, you could get the entire response from one process into memory and pass it to the next in the chain.
You could also replace gzip with a Perl module, leaving you with just external process. Then, all you'd need is backticks.
In reply to Re: System command using array and pipe
by ikegami
in thread System command using array and pipe
by civil777
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |