Pass the background flag (&) through expect and ssh

7,165

Solution 1

Geekosaur is right in pointing out that you can pass the ampersand by quoting it, (you could also escape it with like script eclipse \& ) but there is something else we could maybe suggest a better way of doing here. It seems you have written an expect script to ssh into another machine with your password and execute a command.

You should know that from both a practical standpoint and a security standpoint this is not a very good solution. Practically, the whole situation is brittle and several potential situations could cause it to break, and debugging is confusing down the road. From a security standpoint it's crazy because your system password on another machine is saved in a text file somewhere!

There is a better way! Key based authentication was built to solve this issue. You create key pairs --one part goes on the server on one on the client-- that are allowed to authenticate without a password. This allows you to run ssh from scripts without using expect AND without saving your password anywhere. As an extra step you could even encrypt the local key with a pass-phrase and use an agent or keyring manager to load the key into a shell before you run any scripts that will need to use it.

Edit: I missed that you said you can't use public key authentication. That's crazy talk. I'm leaving my answer up for the benefit of any readers who might have also missed the requirement and don't realize that your script is a hack :)

Solution 2

If you didn't have to type the password, you could do

ssh -t 'eclipse & exec bash'

The -t flag tells ssh to allocate a terminal even though you're giving it a command name. The remote shell has to be non-interactive because it's executing a command, but the last thing it does is exec bash, i.e. replace itself by a new shell instance, which is interactive. (Replace bash by zsh or whatever your favorite shell is.)

If you need to type a password, you do need to type it in a terminal of some kind (which is why you need expect if you're going to automate that part). ssh deliberately refuses to read passwords from a command line argument or file.

One thing that may be useful is to create a master SSH connection once and for all, the piggyback onto it. As long as the master is running, you can establish slave connections that don't require any authentication. Put the following lines in your ~/.ssh/config:

Host nickname
HostName 10.101.0.133
ControlPath=~/.ssh-control:%l:%p:%r

Create the master connection with ssh -MX nickname eclipse (inside expect, if you still want to pass the password automatically). Then, as long as Eclipse is running, you can do ssh nickname without re-authenticating.

Solution 3

Use quoting: script 'eclipse &'. (Note that you do not quote $argv in the expect script; Tcl follows different rules from sh.)

Share:
7,165

Related videos on Youtube

Doug Stephen
Author by

Doug Stephen

Updated on September 18, 2022

Comments

  • Doug Stephen
    Doug Stephen over 1 year

    My command line/bash fu is extremely weak, but I'm trying to hone my abilities. Hopefully someone can help.

    I wrote a super simple expect script so that I can SSH in to a headless box we're using at work, while also sending in the password (for reasons that I am unable to expand upon, we can't use public keys to automate logging in). The script:

    #!/usr/bin/expect -f
    set timeout 30
    spawn ssh -X ***@10.101.0.133 $argv
    match_max 100000
    expect "*?assword:*"
    send -- "***\r"
    interact
    

    The box has a developer environment and Eclipse installed; most of the time that I'm connecting to it, I will end up tunneling straight in to Eclipse to work on some code that we keep on this box, so I usually end up using script eclipse.

    How can I pass the & flag in to expect so that it sees the ampersand as an argument for the ssh session I'm spawning ? When I use script eclipse & it just backgrounds script on my machine instead of doing something on the remote machine, but I'd like to be able to send the & in to script so that when Eclipse launches on the remote box I can still use the box's shell.

    This is probably an incredibly silly question, but any help would be greatly appreciated.

    Update: I figured out escaping the ampersand (which was definitely a "no duh" moment for me... meh). But this leads to a new problem. It seems that when I pass any arguments to my script, the expect command never allows me to interact; once the passed command executes the SSH session terminates. I'm guessing that this isn't a limitation of expect but a part of the behavior of ssh. Thanks for your answers though.

    Update 2: Just for the sake of posterity, I got the behavior I wanted by modifying the script to look like this:

    #!/usr/bin/expect -f
    set timeout 30
    spawn ssh -X ***@10.101.0.133
    match_max 100000
    expect "*?assword:*"
    send -- "***\r"
    send $argv
    send -- "\r"
    interact
    
    • tcoolspy
      tcoolspy almost 13 years
      The equivalent of regular, repeated open-heart surgery is modus-operendi for your team having installed eclipse in your robot's brain and regularly running it remotely using a scripted password -- yet you can't add ssh keys? Just when I thought I'd seen everything.
    • Admin
      Admin almost 13 years
      OR you could just use the ssh -f flag to fork it into a background process. :)
    • Doug Stephen
      Doug Stephen almost 13 years
      @Caleb it looks like it's okay for me to say it now; it's because the machine will eventually belong to NASA but I work from my own personal laptop. @simplicityFirst I wanted to background Eclipse, not the ssh connection.
    • tcoolspy
      tcoolspy almost 13 years
      @Doug: Oh that makes me feel much better :-P Next you're going to tell me that the robot is actually the rover Opportunity and the reason you can't add your public key is that there isn't enough space left on it's internal memory!
    • Doug Stephen
      Doug Stephen almost 13 years
      @Caleb ba-dum-psh. It's actually Robonaut 2.
  • Doug Stephen
    Doug Stephen almost 13 years
    This causes the bash shell to spit out a syntax error on the remote end because expect seems to turn the single quotes in to curly braces. I know that I could isolate each element in the argument vector but I'd prefer passing the entire vector in order to make the script generic. It appears to work if I escape the ampersand. But the new problem now seems to be that if I pass arguments, the script never makes it to interact; as soon as passed commands execute the SSH session ends. Updating my question to reflect this.
  • Doug Stephen
    Doug Stephen almost 13 years
    I know about key based authentication, but you'll notice in my question I said that there are reasons that I'm not at liberty to discuss that prevents me from using keys. I'm pretty familiar with setting up keys for SSH logins and I wish I could just use that.
  • tcoolspy
    tcoolspy almost 13 years
    @Doug: Did you try the escape method in my answer instead of quoting? If that doesn't work I'd suggest a wrapper script on the remote side to do the backgrounding or change your arguments to ssh so you don't have to background at all.
  • geekosaur
    geekosaur almost 13 years
    Mmm, yes, Tcl might well do that. Now I have to try to remember how to make it behave itself; only thing occurring to me off the top of my head is [puts $argv] in place of $argv, but boy is that ugly. (Hm, actually "$argv" might work there come to think of it. Don't remember Tcl quoting rules and the book is long lost in a move.)
  • Doug Stephen
    Doug Stephen almost 13 years
    @Caleb yeah, I did... It actually dawned on me before you popped up and said it. So it works as expected now, except for the caveat I put in my edit.
  • geekosaur
    geekosaur almost 13 years
    @Caleb: Tclsh is expanding the variable fully quoted, Tcl style, because of the space; changing how you escape it going in won't help because Tcl never sees the difference between the two forms. (The shell strips both of them before passing it in.)
  • tcoolspy
    tcoolspy almost 13 years
    @geekosaur: Good point. So why did it work for the OP? @Doug: Did you end up just escaping the ampersand or the space too like in my answer? If you did just the ampersand I guess I can see how it worked and geekosaur is right that I'm wrong.
  • Doug Stephen
    Doug Stephen almost 13 years
    @Caleb I only had to escape the ampersand; in other words script eclipse \& works just fine.
  • Doug Stephen
    Doug Stephen almost 13 years
    Didn't notice you were escaping the space as well. While I don't think this would make the command not work, it's not necessary. Reflected this in a reply to your comment below too.
  • tcoolspy
    tcoolspy almost 13 years
    @Doug: Figures. In that case what is happening is it is getting sent as two arguments instead of one and apparently tcsh doesn't feel the need to interfere and quote it again.
  • tcoolspy
    tcoolspy almost 13 years
    @Doug: It would break in the same way that geekosaur's solution broke. It's not that one or the other format isn't working inside expect, it's that not quoting/escaping the space meant the data got sent as two separate arguments instead of one and expect had different data to work with. I only escaped the space to have the same affect as geekosaur's answer which I assumed would work. It's only when you said it failed that I thought of mentioning the alternative.
  • Doug Stephen
    Doug Stephen almost 13 years
    gotcha. I understand what you're saying now.
  • geekosaur
    geekosaur almost 13 years
    @Doug, @Caleb: Yeh, I can see how that's working. All this does is remind me why I don't use Tcl....
  • tcoolspy
    tcoolspy almost 13 years
    +1 for suggesting ControlMaster as a way to get around not having key based authentication as an option for scripting. Client side fix for unfixable server-side problem.
  • Doug Stephen
    Doug Stephen almost 13 years
    Neat approach, I may end up using both; only because after I launch Eclipse and do some work, I tend to close it but remain connected to the box. The headless box is actually a robot brain that we develop directly on instead of cross compiling so it's a pony that does far too many tricks for a narrow scope solution; that's why I tried to make such a generic script. But it's a good solution for long periods of time in the dev phase. Also, thanks for adding the expect tag.
  • Gilles 'SO- stop being evil'
    Gilles 'SO- stop being evil' almost 13 years
    @Doug You can replace eclipse by sleep 999999999 to have an effectively infinitely long master connection.