Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perl backticks using bash

In Perl, the default shell to execute backticks is sh. I'd like to switch to use bash for its richer syntax. So far I found that the suggested solution is

`bash -c \"echo a b\"`

The apparent drawback is that the escaped double quotes, which means I will have difficulty to use double quotes in my bash args. For example, if I wanted to run commands requiring double quotes in bash

echo "a'b"

The above method will be very awkward.

Perl's system() call has a solution for this problem: to use ARRAY args,

system("bash", "-c", qq(echo "a'b"));

This keeps my original bash command unmodified, and almost always.

I'd like to use ARRAY args in backticks too. Is it possible?

like image 480
oldpride Avatar asked Feb 01 '26 02:02

oldpride


1 Answers

For one, one can submit a list to qx; it gets interpolated into a string and then passed to either execvp or a shell (see qx, and the second part of this post and comments). And if you need a shell then presumably that string contains shell metacharacters so it goes via shell.

my @cmd = qw(ls -l "dir with spaces");
#my @cmd = qw(ls -l "dir with spaces" > outfile);
my @out = qx(@cmd);
print for @out;

I make a "dir with spaces" directory with a file in it to test. (For a command with quotes in it a shell does get used.)

Next, I would in principle recommend a module to compose those shell commands, instead of going through a nail-biter to correctly escape and pass it all, like String::ShellQuote

use String::ShellQuote qw(shell_quote); 

my @cmd = ('ls', '-l', q(dir with spaces)); 

my $quoted = shell_quote(@cmd);; 
my @out = qx($quoted); 
#my @out = qx($quoted > outfile); 
print for @out;

I use the q(...) operator form of single quotes to demonstrate another way (also useful for including single quotes); it is not necessary for this simple example. One still need be careful with details; that's in the nature of using complex external commands and cannot be fully avoided by any approach or tool.

As for running bash, note that normally sh delegates to a default-of-sorts shell on your system, and on many systems it is bash that is used. But if it isn't on yours, one way to use bash -c in the command would be to first prepare the command and then add that to the qx string

my @cmd = ('ls', '-l', q(dir with spaces)); 
my $quoted = shell_quote(@cmd); 
my @out = qx(bash -c "$quoted"); 
#my @out = qx(bash -c "$quoted" > outfile); 
print for @out;

A couple more notes I'd like to offer:

  • That qx is an ancient demon. How about using modern tools/modules for running external commands? There may be a little more to do in order to prepare your involved bash strings but then everything else will be better. Options abound. For example

    • IPC::System::Simple with its few utility functions

    • Use Capture::Tiny to wrap a system call with syntax you prefer

    • The IPC::Run can do any and all of this and then way way more

  • Why use external commands, with Perl's (far) superior richness? It's a whole, very complete, programming language, vs. the command-interpreter with some programming capabilities. If you need shell's capabilities why not run just those things via the shell and do all else in Perl?

like image 194
zdim Avatar answered Feb 02 '26 20:02

zdim



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!