Expanding Perl array into shell command arguments - perl

I want to invoke a shell command from a Perl script. The arguments to the command are present in a Perl array.
What's the simplest way to do this?
Thanks for replies

You probably need to call system, and it is most efficient to pass the parameters as a list, which avoids using the shell to parse the command line. A call like
my $status = system 'command', #arguments;
should do what you need.

There are usually two forms accepted by most functions to launch programs:
Accepts a path and a list of arguments
Accepts a shell command.
The first is safer, and require fewer resources.
system($prog, #args); # #args > 0
system({ $prog } $prog, #args); # #args >= 0
But if you must use the shell or if you must provide a shell command, there are String::ShellQuote (if you're on a unix system) or Win32::ShellQuote (if on a Win32 system) to help you.
use String::ShellQuote qw( shell_quote );
my $shell_cmd = shell_quote($prog, #args);
system($shell_cmd);

Related

Invoke perl script from another perl script [duplicate]

What would be an example of how I can call a shell command, say 'ls -a' in a Perl script and the way to retrieve the output of the command as well?
How to run a shell script from a Perl program
1. Using system system($command, #arguments);
For example:
system("sh", "script.sh", "--help" );
system("sh script.sh --help");
System will execute the $command with
#arguments and return to your script when finished. You may check $!
for certain errors passed to the OS by the external application. Read
the documentation for system for the nuances of how various
invocations are slightly different.
2. Using exec
This is very similar to the use of system, but it will
terminate your script upon execution. Again, read the documentation
for exec for more.
3. Using backticks or qx//
my $output = `script.sh --option`;
my $output = qx/script.sh --option/;
The backtick operator and it's equivalent qx//, excute the command and options inside the operator and return that commands output to STDOUT when it finishes.
There are also ways to run external applications through creative use of open, but this is advanced use; read the documentation for more.
From Perl HowTo, the most common ways to execute external commands from Perl are:
my $files = `ls -la` — captures the output of the command in $files
system "touch ~/foo" — if you don't want to capture the command's output
exec "vim ~/foo" — if you don't want to return to the script after executing the command
open(my $file, '|-', "grep foo"); print $file "foo\nbar" — if you want to pipe input into the command
Examples
`ls -l`;
system("ls -l");
exec("ls -l");
Look at the open function in Perl - especially the variants using a '|' (pipe) in the arguments. Done correctly, you'll get a file handle that you can use to read the output of the command. The back tick operators also do this.
You might also want to review whether Perl has access to the C functions that the command itself uses. For example, for ls -a, you could use the opendir function, and then read the file names with the readdir function, and finally close the directory with (surprise) the closedir function. This has a number of benefits - precision probably being more important than speed. Using these functions, you can get the correct data even if the file names contain odd characters like newline.
As you become more experienced with using Perl, you'll find that there are fewer and fewer occasions when you need to run shell commands. For example, one way to get a list of files is to use Perl's built-in glob function. If you want the list in sorted order you could combine it with the built-in sort function. If you want details about each file, you can use the stat function. Here's an example:
#!/usr/bin/perl
use strict;
use warnings;
foreach my $file ( sort glob('/home/grant/*') ) {
my($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks)
= stat($file);
printf("%-40s %8u bytes\n", $file, $size);
}
There are a lot of ways you can call a shell command from a Perl script, such as:
back tick
ls which captures the output and gives back to you.
system
system('ls');
open
Refer #17 here: Perl programming tips
You might want to look into open2 and open3 in case you need bidirectional communication.
I have been using system and qq to run linux programs inside perl. And it has worked well.
#!/usr/bin/perl # A hashbang line in perl
use strict; # It can save you a lot of time and headache
use warnings; # It helps you find typing mistakes
# my keyword in Perl declares the listed variable
my $adduser = '/usr/sbin/adduser';
my $edquota = '/usr/sbin/edquota';
my $chage = '/usr/bin/chage';
my $quota = '/usr/bin/quota';
my $nomeinteiro;
my $username;
my $home;
# system() function executes a system shell command
# qq() can be used in place of double quotes
system qq($adduser --home $home --gecos "$fullname" $username);
system qq($edquota -p john $username);
system qq($chage -E \$(date -d +180days +%Y-%m-%d) $username);
system qq($chage -l $username);
system qq($quota -s $username);

Running a system command in a perl script that has "#" character

I have a system command like this :
unix_command "#output_file path_to_file"
Now when I try exec or system commands in a perl script I get this error :
Getting a string when expecting an operator.
Can you please help me how to do it in Perl.
Appreciate your help.
Thanks a ton!
Rakesh
system is really two different functions.
You can use it to launch a program.
The following syntax are used to launch a program:
system($prog, #one_or_more_args)
system({ $prog }, $arg0, #args)
Using one of these syntax, all strings passed as arguments are passed untouched to the child program.
Example usage:
system('perl', '-e', 'my #a = "foo"; print "#a\n";');
You can use it to execute a shell command.
The following syntax are used to execute a shell command:
system($shell_cmd)
The above is short for
system('/bin/sh', '-c', $shell_cmd)
You must provide a valid shell command. It you are building the command, you will need to take care to properly escape anything that needs escaping.
Example usage:
use String::ShellQuote qw( shell_quote );
my $cmd = shell_quote('perl', '-e', 'my #a = "foo"; print "#a\n";');
system($cmd);
A bit more specifically to your case, the shell command
program #file1 file2
can be executed as follows:
system('program', '#'.$file1, $file2);
If you actually need to construct a shell command (e.g. because you want to redirect output), you can use the following:
use String::ShellQuote qw( shell_quote );
my $cmd = shell_quote('program', '#'.$file1, $file2) . ' >output.txt 2>&1';
system($cmd);
If you don't need interpolation, use single quotes.
system 'echo #a';
If you do, use backslash.
system "echo \#a";

command line arguments in perl with keywords

I am new to Perl and currently I am passing the command line arguments to a perl script and retrieving it via ARGS[0].
perl <perlscript.pl> windows IE.
I would like to give keywords to the values mentioned above.
perl <perlscript.pl> -os windows -browser IE -instance 2.
There might be times where instance might or might not be present. How do I go about handling this in my perl script.
Use Getopt::Long and store your options in a hash:
use warnings;
use strict;
use Getopt::Long qw(GetOptions);
my %opt;
GetOptions(\%opt, qw(
os=s
browser=s
instance=i
)) or die;
There are several modules for handling command line arguments: Getopt::Declare and Getopt::Long are probably the most popular. At my work we mainly use Getopt::Declare so Ill show and example of that since #toolic covered Getopt::Long.
my $ARGS = Getopt::Declare->new(
join("\n",
"[strict]",
"-os <string> The operating system [required]",
"-browser <string> The web browser [required]",
"-instance <int> The instance"
)
) or die;
Now you can access any of the parmeters via the $ARGS hash. i.e. $ARGS->{-os}
[strict] parses the command line strictly and reports any errors.
[required] after an option declaration means that field must be there, note I left it off of instance.

How can I call a shell command in my Perl script?

What would be an example of how I can call a shell command, say 'ls -a' in a Perl script and the way to retrieve the output of the command as well?
How to run a shell script from a Perl program
1. Using system system($command, #arguments);
For example:
system("sh", "script.sh", "--help" );
system("sh script.sh --help");
System will execute the $command with
#arguments and return to your script when finished. You may check $!
for certain errors passed to the OS by the external application. Read
the documentation for system for the nuances of how various
invocations are slightly different.
2. Using exec
This is very similar to the use of system, but it will
terminate your script upon execution. Again, read the documentation
for exec for more.
3. Using backticks or qx//
my $output = `script.sh --option`;
my $output = qx/script.sh --option/;
The backtick operator and it's equivalent qx//, excute the command and options inside the operator and return that commands output to STDOUT when it finishes.
There are also ways to run external applications through creative use of open, but this is advanced use; read the documentation for more.
From Perl HowTo, the most common ways to execute external commands from Perl are:
my $files = `ls -la` — captures the output of the command in $files
system "touch ~/foo" — if you don't want to capture the command's output
exec "vim ~/foo" — if you don't want to return to the script after executing the command
open(my $file, '|-', "grep foo"); print $file "foo\nbar" — if you want to pipe input into the command
Examples
`ls -l`;
system("ls -l");
exec("ls -l");
Look at the open function in Perl - especially the variants using a '|' (pipe) in the arguments. Done correctly, you'll get a file handle that you can use to read the output of the command. The back tick operators also do this.
You might also want to review whether Perl has access to the C functions that the command itself uses. For example, for ls -a, you could use the opendir function, and then read the file names with the readdir function, and finally close the directory with (surprise) the closedir function. This has a number of benefits - precision probably being more important than speed. Using these functions, you can get the correct data even if the file names contain odd characters like newline.
As you become more experienced with using Perl, you'll find that there are fewer and fewer occasions when you need to run shell commands. For example, one way to get a list of files is to use Perl's built-in glob function. If you want the list in sorted order you could combine it with the built-in sort function. If you want details about each file, you can use the stat function. Here's an example:
#!/usr/bin/perl
use strict;
use warnings;
foreach my $file ( sort glob('/home/grant/*') ) {
my($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks)
= stat($file);
printf("%-40s %8u bytes\n", $file, $size);
}
There are a lot of ways you can call a shell command from a Perl script, such as:
back tick
ls which captures the output and gives back to you.
system
system('ls');
open
Refer #17 here: Perl programming tips
You might want to look into open2 and open3 in case you need bidirectional communication.
I have been using system and qq to run linux programs inside perl. And it has worked well.
#!/usr/bin/perl # A hashbang line in perl
use strict; # It can save you a lot of time and headache
use warnings; # It helps you find typing mistakes
# my keyword in Perl declares the listed variable
my $adduser = '/usr/sbin/adduser';
my $edquota = '/usr/sbin/edquota';
my $chage = '/usr/bin/chage';
my $quota = '/usr/bin/quota';
my $nomeinteiro;
my $username;
my $home;
# system() function executes a system shell command
# qq() can be used in place of double quotes
system qq($adduser --home $home --gecos "$fullname" $username);
system qq($edquota -p john $username);
system qq($chage -E \$(date -d +180days +%Y-%m-%d) $username);
system qq($chage -l $username);
system qq($quota -s $username);

How do you capture stderr, stdout, and the exit code all at once, in Perl?

Is it possible to run an external process from Perl, capture its stderr, stdout AND the process exit code?
I seem to be able to do combinations of these, e.g. use backticks to get stdout, IPC::Open3 to capture outputs, and system() to get exit codes.
How do you capture stderr, stdout, and the exit code all at once?
(Update: I updated the API for IO::CaptureOutput to make this even easier.)
There are several ways to do this. Here's one option, using the IO::CaptureOutput module:
use IO::CaptureOutput qw/capture_exec/;
my ($stdout, $stderr, $success, $exit_code) = capture_exec( #cmd );
This is the capture_exec() function, but IO::CaptureOutput also has a more general capture() function that can be used to capture either Perl output or output from external programs. So if some Perl module happens to use some external program, you still get the output.
It also means you only need to remember one single approach to capturing STDOUT and STDERR (or merging them) instead of using IPC::Open3 for external programs and other modules for capturing Perl output.
If you reread the documentation for IPC::Open3, you'll see a note that you should call waitpid to reap the child process. Once you do this, the status should be available in $?. The exit value is $? >> 8. See
$? in perldoc perlvar.
If you don't want the contents of STDERR, then the capture() command from IPC::System::Simple module is almost exactly what you're after:
use IPC::System::Simple qw(capture system $EXITVAL);
my $output = capture($cmd, #args);
my $exit_value = $EXITVAL;
You can use capture() with a single argument to invoke the shell, or multiple arguments to reliably avoid the shell. There's also capturex() which never calls the shell, even with a single argument.
Unlike Perl's built-in system and backticks commands, IPC::System::Simple returns the full 32-bit exit value under Windows. It also throws a detailed exception if the command can't be started, dies to a signal, or returns an unexpected exit value. This means for many programs, rather than checking the exit values yourself, you can rely upon
IPC::System::Simple to do the hard work for you:
use IPC::System::Simple qw(system capture $EXIT_ANY);
system( [0,1], "frobincate", #files); # Must return exitval 0 or 1
my #lines = capture($EXIT_ANY, "baznicate", #files); # Any exitval is OK.
foreach my $record (#lines) {
system( [0, 32], "barnicate", $record); # Must return exitval 0 or 32
}
IPC::System::Simple is pure Perl, has no dependencies, and works on both Unix and Windows systems. Unfortunately, it doesn't provide a way of capturing STDERR, so it may not be suitable for all your needs.
IPC::Run3 provides a clean and easy interface into re-plumbing all three common filehandles, but unfortunately it doesn't check to see if the command was successful, so you'll need to inspect $? manually, which is not at all fun. Providing a public interface for inspecting $? is something which is on my to-do list for IPC::System::Simple, since inspecting $? in a cross-platform fashion is not a task I'd wish on anyone.
There are other modules in the IPC:: namespace that may also provide you with assistance. YMMV.
All the best,
Paul
There are three basic ways of running external commands:
system $cmd; # using system()
$output = `$cmd`; # using backticks (``)
open (PIPE, "cmd |"); # using open()
With system(), both STDOUT and STDERR will go the same place as the script's STDOUT and STDERR, unless the system() command redirects them. Backticks and open() read only the STDOUT of your command.
You could also call something like the following with open to redirect both STDOUT and STDERR.
open(PIPE, "cmd 2>&1 |");
The return code is always stored in $? as noted by #Michael Carman.
If you're getting really complicated, you might want to try Expect.pm. But that's probably overkill if you don't need to also manage sending input to the process as well.
I found IPC:run3 to be very helpful. You can forward all child pipes to a glob or a variable; very easily! And exit code will be stored in $?.
Below is how i grabbed stderr which i knew would be a number. The cmd output informatic transformations to stdout (which i piped to a file in the args using >) and reported how many transformations to STDERR.
use IPC::Run3
my $number;
my $run = run3("cmd arg1 arg2 >output_file",\undef, \undef, \$number);
die "Command failed: $!" unless ($run && $? == 0);