Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling

how to escape round parentheses in a system call

by ObiPanda (Acolyte)
on Jun 11, 2023 at 21:17 UTC ( [id://11152790] : perlquestion . print w/replies, xml ) Need Help??

ObiPanda has asked for the wisdom of the Perl Monks concerning the following question:

I am thankful to everyone who helped answer my last question.

I have a script with a system() call and I cannot seem to include (?i) in it.
I can print the command including (?i) but escaping it successfully, and, when attempting to use system, I have tried various permutations qq [] \( etc... but nothing helps.

Here's some pseudocode, which fails

system qq(command $_->{Sub_URL} \(?i\)Podcast ARGS);

But this is fine:

print qq(command $_->{Sub_URL} \(?i\)Podcast ARGS);

Replies are listed 'Best First'.
Re: how to escape round parentheses in a system call
by choroba (Cardinal) on Jun 11, 2023 at 21:26 UTC
    It's not clear how the command fails. I replaced "command" with "echo" and added a simple string to the hash referenced by $_. The qq behaves as double quotes, i.e. a single backslash is interpreted by it, so \( becomes (, but ( is special in the shell. You need to escape it, so use double backslash:
    $_->{Sub_URL} = 'suburl'; print qq{echo $_->{Sub_URL} \(?i\)Podcast ARGS\n}; system qq{echo $_->{Sub_URL} \\(?i\\)Podcast ARGS}; # ~~ ~~
    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]

      thanks. It works exactly as needed.

        It may work, but I disagree that it is a good solution: it will blow up when $_->{Sub_URL} contains shell metacharacters, and is a security hole if that variable contains any user input.

        See Calling External Commands More Safely. In this case I would recommend systemx from IPC::System::Simple, or at the very least the multi-argument system (as shown in other replies) with error checking (nobody showed this, but for an example see the first link).


Re: how to escape round parentheses in a system call
by ikegami (Patriarch) on Jun 11, 2023 at 22:28 UTC

    To convert a string to a shell literal, you can use String::ShellQuote's shell_quote. (If you're building a Windows command, see Win32::ShellQuote.)

    use String::ShellQuote qw( shell_quote ); my $cmd = shell_quote( "prog", $_->{Sub_URL}, "(?i)Podcast", @args ); system( $cmd );

    But why invoke a shell at all?

    my @cmd = ( "prog", $_->{Sub_URL}, "(?i)Podcast", @args ); system( { $cmd[0] } @cmd );

    (Ignore afoken's disparagement of shell_quote. He thinks the fact that unix and Windows are different is a defect of the module.)

      FYI - I liked your answer ikegami. Shell:Quote module looked to be very helpful, but it does not exist in CPAN. However, I did find the following modules:

      ShellQuote::Any - Escape strings for the shell on Linux, UNIX or MSWin32
      Win32::ShellQuote - Quote argument lists for Win32
      ShellQuote::Any::Tiny - Escape string for the Unix/Windows shell

      "It's not how hard you work, it's how much you get done."

Re: how to escape round parentheses in a system call
by afoken (Chancellor) on Jun 12, 2023 at 09:43 UTC


    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)