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

Should be pretty simple, if there's a solution.

I need to get the exact string entered when calling a perl script.

join(" ", @ARGV);
is not good enough, because this doesn't tell me if a parameter was quoted when it was passed. For example, if my script was to be run like this...
./my_ssh.pl -l user machine "the remote command"
... I'd have four elements in @ARGV, but can't reproduce the original string, because I don't know what was quoted.

Is this even possible? I'm on solaris BTW.

Thanks, Rob

---
my name's not Keith, and I'm not reasonable.

Replies are listed 'Best First'.
Re: getting the exact string used to call a perl script
by revdiablo (Prior) on Oct 12, 2005 at 15:56 UTC

    I'm going to go out on a limb here, and guess that you want to call ssh with the options passed to your script, but avoid problems with the shell misinterpreting the arguments. The solution is not to use the shell at all, but instead use the list form of system, exec, or open (whichever you're using). It can be as simple as:

    use strict; use warnings; do_something_first(); system ssh => @ARGV;
      That's exactly what I'm trying to do! ++ ( if this works :) )
      ---
      my name's not Keith, and I'm not reasonable.
Re: getting the exact string used to call a perl script
by ikegami (Patriarch) on Oct 12, 2005 at 15:51 UTC
    The quotes are shell-specific. As I understand things, they are not passed to the application. The shell parses and interprets the command line and passes the resulting list of paramters to the exec system call as a list or as an array (depending on which version of exec is used).
Re: getting the exact string used to call a perl script
by blue_cowdawg (Monsignor) on Oct 12, 2005 at 15:55 UTC
        Is this even possible? I'm on solaris BTW.

    What I think you are being confused by here is the difference between what Perl is dealing with and what your shell is dealing with. That is, if I understand what you are after correctly.

    When you do an SSH to a remote box the shell is invoked first and any quotes that you have passed have already been digested in making up the ARGV to your script on the remote side. The relationship sorta loooks like this as a tree:

    ssh -l user machine "the remote command" | | (assuming bash on the other side) | +--- bash | | +--- the | +--- ARGV[0] = remote [1] = command
    or some such like that.

    Peter L. Berghold -- Unix Professional
    Peter -at- Berghold -dot- Net; AOL IM redcowdawg Yahoo IM: blue_cowdawg
Re: getting the exact string used to call a perl script
by Skeeve (Parson) on Oct 12, 2005 at 15:46 UTC
    I don't think it's possible. But tell us why do you think you need that information. Maybe we can find another solution!?

    s$$([},&%#}/&/]+}%&{})*;#$&&s&&$^X.($'^"%]=\&(|?*{%.+=%;.#_}\&"^"-+%*) +.}%:##%}={~=~:.")&e&&s""`$''`"e
      It's in the example, in my script my_ssh.pl, I need to run execute ssh, passing the same parameters that were passed to my script in the first place (which is pretending to be ssh).

      As to why I'm doing that. Well, we have a system that executes ssh commands according to a workflow. There is a daemon that runs these ssh commands as child processes. However, they always fail with the following error

      ssh: FATAL: ssh_io_register_fd: fd 0 already registered!
      The ssh commands are fine elsewhere, so I'm writing a script that will pass the commands to another process, which will then execute them. Hoping that they will be okay, as they won't be invoked by the deamon directly.

      (This is a stop gap until we can fix ssh properly.)

      ---
      my name's not Keith, and I'm not reasonable.
        I need to run execute ssh, passing the same parameters that were passed to my script in the first place
        So, what's wrong with:
        exec 'ssh', @ARGV; # Or system
        Perl --((8:>*

        Be sure to just include the program name (optionally including the full path) as the first argument of exec/system, no redirection or anything else. Then you'll be doing the exact same as the shell. For example,

        exec('ssh', @ARGV); #or exec('/usr/bin/ssh', @ARGV);
Re: getting the exact string used to call a perl script
by Perl Mouse (Chaplain) on Oct 12, 2005 at 15:51 UTC
    It's possible, but that would require writing (or modifying) a shell.

    It's the shell that's dealing with the quotes, perl is not passed the quotes. perl will be called by execve, with a 6 string array as second argument, the 6 strings being './my_ssh.pl', '-l', 'user', 'machine', 'the remote command' and the NULL pointer. (Sans quotes of course). perl will put the first element in $0, discard the NULL pointer, and pass the rest in @ARGV.

    Why do you need to know how the string was quoted?

    Perl --((8:>*
Re: getting the exact string used to call a perl script
by sgifford (Prior) on Oct 12, 2005 at 15:54 UTC
    This isn't possible under Unix; the shell processes quotes, wildcards, and other metacharacters before starting up your program. By the time you're running, the original string passed to the shell is long gone.
Re: getting the exact string used to call a perl script
by samizdat (Vicar) on Oct 12, 2005 at 15:55 UTC
    I would look at the docs of the shell you're running under for the special variables associated with a PID. Rather than looking at Perl, see what your environment stores about the program. I'm betting there is an association somewhere between PID and command line, much as ps gives.
Re: getting the exact string used to call a perl script
by tirwhan (Abbot) on Oct 12, 2005 at 15:55 UTC

    You should be able to read the full command line from /proc/$PID/cmdline (this may depend on which version of Solaris you're using)

      You should be able to read the full command line from /proc/$PID/cmdline
      But only after the shell processing the quotes. What you'll see in /proc/$PID/cmdline are the things passed in execve, separated by NUL characters.
      Perl --((8:>*
Re: getting the exact string used to call a perl script
by Anonymous Monk on Aug 01, 2010 at 15:42 UTC
    use Proc::ProcessTable; sub GetCommandLineForCurrentProcess { my (%args) = @_; my $t = new Proc::ProcessTable( 'cache_ttys' => 1 ); foreach $p (@{$t->table}) { if ($p->{pid} == $$) { return $p->{cmndline}; } } }