Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"

Redirect output of the system() command

by Gangabass (Vicar)
on Jul 11, 2012 at 04:04 UTC ( #980995=perlquestion: print w/replies, xml ) Need Help??
Gangabass has asked for the wisdom of the Perl Monks concerning the following question:

Hi, Monks

I'm trying to redirect output (warnings) of some weird program to /dev/null (I don't want this info in web server's error log) but with no luck.

The program I'm talking about is wkhtmltopdf and the main problem with it that it's accept several files. So then I use ">/dev/null 2>&1" it think about /dev/null like a file to convert.

So this code gives me an error about wrong file name:

my @options = qw( --orientation Landscape --page-size A3 --title "Here is our Title" ); system( $config->{wkhtmltopdf_path}, @options, $source_file, $config-> +{result_filename}, ">/dev/null", "2>&1" );

I'm also tried to enclose whole command in () and next redirect it. But this approach is not working from system().

system("( /usr/bin/wkhtmltopdf Result.pdf )", ">/dev/nu +ll", "2>&1");

Please help me to redirect output in this situation.

Replies are listed 'Best First'.
Re: Redirect output of the system() command
by jwkrahn (Monsignor) on Jul 11, 2012 at 05:41 UTC
    system( $config->{wkhtmltopdf_path}, @options, $source_file, $config-> +{result_filename}, ">/dev/null", "2>&1" );

    Your problem is that you are passing a list to system and when system is passed a list it does not use the shell, but redirection (>/dev/null 2>&1) requires the shell so you have to put everything into a string:

    system "$config->{wkhtmltopdf_path} @options $source_file $config->{re +sult_filename} >/dev/null 2>&1";

      Bingo! That's the answer:

      Note that argument processing varies depending on the number of arguments. If there is more than one argument in LIST, or if LIST is an array with more than one value, starts the program given by the first element of the list with arguments given by the rest of the list. If there is only one scalar argument, the argument is checked for shell metacharacters, and if there are any, the entire argument is passed to the system's command shell for parsing (this is /bin/sh -c on Unix platforms, but varies on other platforms). If there are no shell metacharacters in the argument, it is split into words and passed directly to execvp , which is more efficient.

      (Thus saith system.)

      Once the OP fixes his system usage, it may be worthwhile to go investigate Capture::Tiny. Rather than worrying about the portability issues that arise when dealing with the shell, leverage the power of CPAN by using Capture::Tiny. It's such a handy module, I wish I had found it several years ago.


      Your code will not work because I can use folders with space in the name and also some of my options contain quotes.

      But the direction is right so thank you.

Re: Redirect output of the system() command
by monsoon (Pilgrim) on Jul 11, 2012 at 04:56 UTC
    You can invoke shell in the 'system' call. Working example from Windows
    system( "cmd /C \"h2p\\wkhtmltopdf.exe", " +d=980995", "out.pdf", "2>nul\"" );

    That would be 'bash -c' on Linux I think. This is non portable though, so backticks, which Athanasius already mentioned, are probably your best bet.

      Thank you for the hint with bash -c!

      I have fixed issues with this (really ugly) code:

      my @options = qw( --orientation Landscape --load-error-handling ignore --page-size A3 --quiet ); $config->{wkhtmltopdf_path} =~ s{ }{\\ }g; $config->{result_filename} =~ s{ }{\\ }g; my $command = "(" . join(" ", $config->{wkhtmltopdf_path}, @options, $ +source_file, $config->{result_filename}) . ")"; system( "/bin/bash -c \"$command\" >/dev/null 2>&1" );
        A bit modified version (as soon as I need to quote some options too):
        my @options = qw( --orientation Portrait --page-size A4 --title "Rechnung" --footer-right "created by Manager" ); $config->{wkhtmltopdf_path} =~ s{ }{\\ }g; $source_file =~ s{ }{\\ }g; $config->{result_filename} =~ s{ }{\\ }g; my $command = "(" . join(" ", $config->{wkhtmltopdf_path}, @options, $ +source_file, $config->{result_filename}) . ")"; $command =~ s/\"/\\\"/g; system( "/bin/bash -c \"$command\" >/dev/null 2>&1" );
Re: Redirect output of the system() command
by Athanasius (Chancellor) on Jul 11, 2012 at 04:32 UTC

    Just a thought:

    Have you tried using backticks (qx//) instead of system? The perldoc entry addresses the problem of redirecting STDOUT and/or STDERR.


    Athanasius <°(((><contra mundum

      It's not a system() problem so the qx// doesn't help too. The called program (wkhtmltopdf) just eat all arguments and don't rest anything to the shell.

        You never invoked a shell because you didn't pass a shell command to system

        You want

        system('sh' => ( '-c' => '"$@" >/dev/null 2>&1', '--', $config->{wkhtmltopdf_path}, @options, $source_file, $config->{result_filename}, ));

        This approach handles spaces and other special characters in file names and options.

Re: Redirect output of the system() command
by NetWallah (Abbot) on Jul 11, 2012 at 05:20 UTC
    Your "system" call may be getting confused because you have used "qw()", and your options contain quoted text that you expect to be retained as a single array element.

    When you feed "Here is our Title" to qw(), you would end up with 4 elements, not one. This would result in positional parameters being in the wrong place.

                 I hope life isn't a big joke, because I don't get it.

      'system' takes a list. @options gives it that list in exactly the order that was specified by 'qw'. Space separated items can be combined into a single string or can be standalone list items. Now how would in this case the positional parameters end up in the wrong place?
        See Your Mother's comments below.

        I wasn't clear in my previous node - what I meant by "wrong place" was that multiple spaces would be collapsed in a quoted string. (or maybe I'm making that up now - can't remember what I was thinking).

                     I hope life isn't a big joke, because I don't get it.

Re: Redirect output of the system() command
by andal (Hermit) on Jul 11, 2012 at 10:02 UTC

    The executed command inherits STDOUT, STDIN, STDERR from the process that executes it. So, you can simply reopen STDERR and STDOUT to /dev/null and then execute the command. See 'perldoc -f open' for details on how to restore your STDERR and STDOUT after the command finishes.

Re: Redirect output of the system() command
by Your Mother (Chancellor) on Jul 11, 2012 at 15:14 UTC

    NetWallah alluded to this: qw doesn't handle your args the way you expect, I'm guessing-

    print $_, $/ for @options; --orientation Portrait --page-size A4 --title "Rechnung" --footer-right "created by Manager"

      Nice catch but I have tried my code without such options with no luck (same error). So I'm absolutely sure this is not qw() issue.

      This is wkpdftohtml issue (see this)

        Sure, sure. I didn't think is was the ultimate problem, just that it might be truncating/mangling arguments unexpectedly.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://980995]
Front-paged by NetWallah
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others avoiding work at the Monastery: (6)
As of 2017-06-25 09:02 GMT
Find Nodes?
    Voting Booth?
    How many monitors do you use while coding?

    Results (565 votes). Check out past polls.