nested escape chars in a shell command

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Eli Criffield

    #1

    nested escape chars in a shell command

    I'm try run an ssh command in pexpect and I'm having trouble getting
    everything escaped to do what i want.

    Here's a striped down script showing what i want to do.

    --
    #!/usr/bin/env python
    import pexpect
    import sys
    if len(sys.argv) < 3:
    print "ssh.py host command"
    sys.exit(1)

    host = sys.argv[1]
    command = sys.argv[2]

    child = pexpect.spawn(' ''sh -x -c "stty -echo ; ssh -t -o
    'StrictHostKeyC hecking no' %s '%s' |awk '{print \"%s:\"$0}' "
    '''%(host,comma nd,host), timeout=30)

    child.setlog(sy s.stdout)
    child.expect(pe xpect.EOF)
    --

    The problem in the pexpect.spawn line, It doesn't like the \"%s:\" part
    of the awk command. This is necessary so i can see what server the
    command is running on, In the full script the command will be running
    on about 100 servers at a time.
    It parses out into:
    + stty -echo
    + ssh -t -o 'StrictHostKeyC hecking no' testserver date
    + awk '{print testserver:$0}'
    It totally strips out the "

    The stty -echo is required because part of what the program does is it
    tries to remember any passwords that are asked for, So you can run a
    command like "su -c id" and it will remember roots password for the
    next
    server and try that. -echo keeps the root password from being echoed to
    the screen.

    The second problem with the command is while "su -c id" works (taking
    out the awk part) running any command with more then one word after the
    -c in su fails, It strips out the '
    like so:
    ../sshexpect testserver "su -c 'ls -l /root'"
    + stty -echo
    + ssh -t -o 'StrictHostKeyC hecking no' testserver 'su -c ls' -l /root
    su: user /root does not exist

    I have tried every combination of escaping i can think of can i can't
    get either problem solved.

    Any ideas?

    Eli

  • Juho Schultz

    #2
    Re: nested escape chars in a shell command

    Eli Criffield wrote:[color=blue]
    > I'm try run an ssh command in pexpect and I'm having trouble getting
    > everything escaped to do what i want.
    >
    > Here's a striped down script showing what i want to do.
    >
    > --
    > #!/usr/bin/env python
    > import pexpect
    > import sys
    > if len(sys.argv) < 3:
    > print "ssh.py host command"
    > sys.exit(1)
    >
    > host = sys.argv[1]
    > command = sys.argv[2]
    >
    > child = pexpect.spawn(' ''sh -x -c "stty -echo ; ssh -t -o
    > 'StrictHostKeyC hecking no' %s '%s' |awk '{print \"%s:\"$0}' "
    > '''%(host,comma nd,host), timeout=30)
    >
    > child.setlog(sy s.stdout)
    > child.expect(pe xpect.EOF)
    > --
    >
    > The problem in the pexpect.spawn line, It doesn't like the \"%s:\" part
    > of the awk command. This is necessary so i can see what server the
    > command is running on, In the full script the command will be running
    > on about 100 servers at a time.
    > It parses out into:
    > + stty -echo
    > + ssh -t -o 'StrictHostKeyC hecking no' testserver date
    > + awk '{print testserver:$0}'
    > It totally strips out the "
    >
    > The stty -echo is required because part of what the program does is it
    > tries to remember any passwords that are asked for, So you can run a
    > command like "su -c id" and it will remember roots password for the
    > next
    > server and try that. -echo keeps the root password from being echoed to
    > the screen.
    >
    > The second problem with the command is while "su -c id" works (taking
    > out the awk part) running any command with more then one word after the
    > -c in su fails, It strips out the '
    > like so:
    > ./sshexpect testserver "su -c 'ls -l /root'"
    > + stty -echo
    > + ssh -t -o 'StrictHostKeyC hecking no' testserver 'su -c ls' -l /root
    > su: user /root does not exist
    >
    > I have tried every combination of escaping i can think of can i can't
    > get either problem solved.
    >
    > Any ideas?
    >
    > Eli
    >[/color]

    You can pass the argument list of your command to
    pexpect.spawn(c omm, args=['arg1','arg2'])
    If the argument list is empty, pexpect tries to get the arguments
    from the comm you passed to it. I guess this gives you problems.

    Try using the args parameter.
    Simplest would be args=[' '] just to avoid the processing.

    Comment

    • Eli Criffield

      #3
      Re: nested escape chars in a shell command

      I can't seem to get that to work either.

      child =
      pexpect.spawn('/bin/sh',args=['-c','/usr/bin/ssh','-t','-o','StrictHostK eyChecking
      no',host,comman d,'|','awk','{p rint %s:$0}'%host], timeout=30)

      Complains its getting the wrong arguments to ssh.

      Eli

      Comment

      • jepler@unpythonic.net

        #4
        Re: nested escape chars in a shell command

        I think you're mistaken about how 'sh -c' works. The next argument after "-c" is
        the script, and following arguments are the positional arguments. (what, you've
        never used -c in conjunction with positional arguments? me either!)

        Example:
        ------------------------------------------------------------------------
        $ /bin/sh -c 'echo $#' a b c

        # i.e., a blank line
        $ /bin/sh -c 'echo $# 0=$0 1=$1 2=$2' a b c
        2 0=a 1=b 2=c
        # i.e., a, b, c went to positional arguments
        ------------------------------------------------------------------------

        Additionally, unless pexpect.spawn behaves differently than os.spawnv,
        "-c" is actually going to /bin/sh's argv[0], and you end up trying to execute
        /usr/bin/ssh as a shell script, which is probably not what you want!

        ------------------------------------------------------------------------
        def shellquote(arg) :
        # shell quoting technique I first read about on the 'git' development list
        # Everything is safely quoted inside a ''-quoted string, except a ' itself,
        # which can be written as '\'' (a backslash-escaped ' outside of the ''-quoted
        # string)
        return "'" + arg.replace("'" , "'\\''") + "'"

        def shellquotelist( args):
        return " ".join([shellquote(arg) for arg in args])

        # XXX: you may wish to assemle 'command' using shellquotelist too
        command1 = shellquotelist(['/bin/sh', '-c','/usr/bin/ssh','-t','-o',
        'StrictHostKeyC hecking no',host,comman d])
        command2 = shellquotelist(['awk','{print %s:$0}'%host])

        child = \
        pexpect.spawn('/bin/sh',
        args=['/bin/sh', '-c', command1 + "|" + command2],
        timeout=30)
        ------------------------------------------------------------------------

        Finally, in your case the use of awk would seem to be gratuitous. Instead,
        prepend the hostname to each line when you read the lines in. (this could easy
        or hard depending on the structure of the code where you read the output
        generated by child---if you do it with readline() or by iterating over the file,
        it is probably easy)

        Jeff

        -----BEGIN PGP SIGNATURE-----
        Version: GnuPG v1.4.1 (GNU/Linux)

        iD8DBQFDWDd6Jd0 1MZaTXX0RAhb9AK CkRn/iBtG2KM2D7OCpIZ QE8A7YPACgpOCA
        swOL+oDJBOd4NjI 5cC5Pk+o=
        =VkjM
        -----END PGP SIGNATURE-----

        Comment

        Working...