Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change

comment on

( #3333=superdoc: print w/replies, xml ) Need Help??
sub ops_do_ssh_qx { my ($cmd) = @_; $cmd->{ssh_cmd_qx} = 'ssh ' . $cmd->{user} . '\@' . $cmd->{host} . + ' \'' . $cmd->{command} . '\'' . ' 2>/dev/null'; $cmd->{output} = qx($cmd->{ssh_cmd_qx}); if ( defined $cmd->{output} ) { $cmd->{cmd_ret_code} = $?; chomp $cmd->{output}; if ( $cmd->{cmd_ret_code} ) { $cmd->{success} = FAILURE; } } else { ($cmd->{ssh_ret_code}, $cmd->{ssh_ret_msg}) = (0 + $!, '' . $!); $cmd->{success} = FAILURE; } return $cmd; }

Well, I can't imagine an OS that has ssh, but no fork and exec (except for Windows). And if you have fork and exec, you can do better than using qx, see "Safe pipe opens" in perlipc.

Why no qx?

qx (and the equivalent ``) uses some heuristics to find out if the default shell needs to be invoked. For simple cases, like qx(foo bar baz), the shell is not needed. But when non-alphanumeric characters come into play, the entire string is passed to the default shell. And at that point, you can not win the game. The default shell is /bin/sh, and that's all you know. It may be a symlink to /bin/bash, which currently has four major versions with different behavior. It may be ash or debian's fork, dash. It may be some csh, or something completely different. And of course, all of those possible shells have different parsing and quoting rules. Start at if you want to get an impression of what traps you may find. And don't make me start complaining about and cmd.exe.

So, you definitively want to avoid the shell. "Safe pipe opens" avoids the shell by avoiding the biggest problem - parsing a string into a program and number of arguments. The "safe pipe opens" receipe uses the list form of exec, completely bypassing all parsing. Of course, that requires that you pass a list to the function, not a string.

Another problem is the exit status guessing. For openssh, the exit status is defined in one simple sentence:

ssh exits with the exit status of the remote command or with 255 if an error occurred.

(Source:, linked from

So, if you see an exit code of less than 255, ssh has returned the exit code of the remote program, any number between 0 and 254. If you see an exit code of 255, ssh may have run into trouble. Or it simply has returned the exit code of the remote command, which may also have been 255. That's not what your code does. Your code expects the remote program to exit with code 0. Several programs don't, like cmp, diff, and grep, to name just three.

Also, there is more than that. The exit status ($?) is more than the exit code. It also has a flag that indicates a core dump, and it returns the number of the signal - if any - that killed the process.

$! is something completely different, it is errno from the C library. It does not contain any information about ssh problems, but just tells you what went wrong if something went wrong when attempting to start ssh. So the names ssh_ret_code and ssh_ret_message are at best misleading. Note that $!, like errno, is NOT reset when a libc function was successful. Quite the opposite is true: errno and thus also $! contains garbage (old errors) if a function was successful.

Last, using qx in scalar context forces the user of your function to split the returned text into lines, wasting memory. qx supports list context, but your function doesn't.

So, some final words?

Why would you actually want to do such a thing to begin with? You wouldn't. Don't do it. Stop! For the love of ...

If, however, you have a machine who's operating system hasn't had a vendor supported upgrade any time this century, you may not have a choice.


If anybody finds this useful, you have my condolences.

Why did you post that? "Safe pipe opens" works better, and it did so even in the previous century. Don't post bad code!


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

In reply to Re: Ssh and qx by afoken
in thread Ssh and qx by cbeckley

Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":

  • Are you posting in the right place? Check out Where do I post X? to know for sure.
  • Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
    <code> <a> <b> <big> <blockquote> <br /> <dd> <dl> <dt> <em> <font> <h1> <h2> <h3> <h4> <h5> <h6> <hr /> <i> <li> <nbsp> <ol> <p> <small> <strike> <strong> <sub> <sup> <table> <td> <th> <tr> <tt> <u> <ul>
  • Snippets of code should be wrapped in <code> tags not <pre> tags. In fact, <pre> tags should generally be avoided. If they must be used, extreme care should be taken to ensure that their contents do not have long lines (<70 chars), in order to prevent horizontal scrolling (and possible janitor intervention).
  • Want more info? How to link or or How to display code and escape characters are good places to start.
Log In?

What's my password?
Create A New User
Domain Nodelet?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others wandering the Monastery: (2)
As of 2022-06-26 18:23 GMT
Find Nodes?
    Voting Booth?
    My most frequent journeys are powered by:

    Results (86 votes). Check out past polls.