4

I have a shell script of the following type:

#!/bin/bash

ssh mylogin@myremotemachine.com
echo "Hi"
exit

I run it locally to do something on a remote server (represented by 'echo "Hi"'). However, when I run it, I see the prompt on the remote server -- so the 'exit' command is not executed. When I then manually type 'exit' on the remote prompt, I then see "Connection to myremotemachine.com" closed and then "Hi". How can I set up the shell script such that it exits correctly and shows me the (local) prompt from which I executed it?

https://unix.stackexchange.com/questions/89747/ssh-exits-after-quit-case-in-bash-script and ssh and shell through ssh : how to exit? seem somewhat related, but I couldn't adapt the ideas presented there./

UPDATE

The following, not so minimal version leads to Unmatched '..

#!/bin/bash

date=`date "+%Y-%m-%d"`
rsync -acxzP --delete --link-dest=/u3/mylogin/backup/old_backup /home/mylogin mylogin@myremotemachine.com:/u3/mylogin/backup/$date\_backup
ssh mylogin@myremotemachine.com bash -c "'
rm -f /u3/mylogin/backup/old_backup
ln -s $date\_backup /u3/mylogin/backup/old_backup
exit
'"

If I remove the double quotes in this snippet, I get: bash: -c: option requires an argument and date: Undefined variable.

Marius Hofert
  • 234
  • 2
  • 4
  • 14

4 Answers4

9

This should solve your problem.

ssh mylogin@myremotemachine.com << HERE
rm -f /u3/mylogin/backup/old_backup
ln -s $date\_backup /u3/mylogin/backup/old_backup
HERE

Or you can do the following. Put all the commands you want to run on the remote host in a separate script. Give it a name like remote.sh

Now run the following

ssh mylogin@myremotemachine.com 'bash -s' < /path/to/remote.sh

Where remote.sh contains.

rm -f /u3/mylogin/backup/old_backup
ln -s $date\_backup /u3/mylogin/backup/old_backup
R J
  • 620
  • 3
  • 6
  • 1
    Hi R J, thanks for helping. I prefer the first solution (I was aware of the second). However, I get `Pseudo-terminal will not be allocated because stdin is not a terminal. Warning: no access to tty (Bad file descriptor). Thus no job control in this shell.` But the commands are executed as expected. – Marius Hofert Sep 09 '14 at 01:52
  • 1
    Hi Marius. That is a friendly reminder from ssh that what is being executed is a script under a job that has no access to TTY, instead of the usual expected binary. Therefore you cannot interrupt it using Ctrl + c or suspend it using Ctrl + z or other interactive commands. It is harmless and can safely be ignored. – R J Sep 09 '14 at 07:43
1

You can do

$ssh user@comp echo abc<ENTER>

then it will run that command (outputting abc), and exit

barlop
  • 23,380
  • 43
  • 145
  • 225
  • Thanks! Is this equivalent to adding a newline character at the end of a script to simulate the carriage enter? Sometimes everything works even without this. When is this a must? I have a question regarding this: https://unix.stackexchange.com/questions/362203/when-do-i-need-a-carriage-return-at-the-end-of-my-job-script-submitted-by-ssh. Will be beautiful if you could explain this there. – Sibbs Gambling Apr 30 '17 at 02:44
  • @SibbsGambling i'm not sure if you misunderstood.. means push the enter key.. Re new lines at the end of a script, i'm not sure, I don't use *nix that much. – barlop Apr 30 '17 at 10:51
1

Although barlops answer is correct, I think we can expand on it, to make it more clear. Since you seem to be using a script, I would suggest something like this:

#!/bin/bash

ssh mylogin@myremotemachine.com "echo Hi\!"

Extra reading: I also suggest you also look into special characters and when you need to escape them, as bash will automatically parse exclamation marks, when in double quotes. You can solve this by either using single quotes, or the backslash character to 'escape' it.

Edit:

#!/bin/bash
date=`date "+%Y-%m-%d"`
rsync -acxzP --delete --link-dest=/u3/mylogin/backup/old_backup /home/mylogin mylogin@myremotemachine.com:/u3/mylogin/backup/$date\_backup
ssh mylogin@myremotemachine.com '
date=`date "+%Y-%m-%d"`
rm -f /u3/mylogin/backup/old_backup
ln -s $date\_backup /u3/mylogin/backup/old_backup
'

When I tried a simplified version, the date variable works without issue, maybe this will correct the bash -c issue you were having. Also the exit is unneeded at the end, when the last command is executed the ssh session is automatically closed.

Ctark
  • 46
  • 1
  • 6
  • Hi Ctark, thanks for helping. There are no special characters involved Obviously, the 'echo' here is just a minimal example; there are various lines of code to be executed remotely. I'm thus not sure how much this "writing everything in one line" should help... there are indeed several lines of code – Marius Hofert Sep 07 '14 at 01:20
  • ... but indeed you are right. If I put everything in one line, the 'exit' works. Hmmm... but the script is then not readable anymore :-( can one use curly braces or some kind of grouping? – Marius Hofert Sep 07 '14 at 01:25
  • 1
    In that case I would suggest this link: http://www.unixmantra.com/2014/03/a-simple-way-to-send-multiple-line-commands-over-ssh.html It seems to have basically what you are asking. (I could copy paste, but there is a lot of info, and it walks you through WHY it works, so you learn too!) – Ctark Sep 07 '14 at 01:30
  • It contains a lot information, thanks. But it does not suggest the 'general best' approach. The `EOF`-based approach did not work for me (same reasons as in the link you provided). I then tried the `"bash -c"` approach. But if I encapsulate the code in "'...'" as suggested, I obtain 2x `Unmatched '.`. If only use one pair of quotes (either single or double), I get `bash: -c: option requires an argument`. The code is executed, so we are close :-) – Marius Hofert Sep 07 '14 at 01:52
  • 1
    The easiest way would be to just use the ssh with single quotes, BUT if you have any other single quotes in the rest of the script you want to use, then it will mess up. If you can change all single quotes in the script you want to run to double quotes, then just a simple: ssh $host 'line 1 line2 line3 "some params" ' At the end of that article the author talks about trying to use single quotes, but it doesn't seem to like that very much, and he doesn't talk about a resolution. Basically unless you need variables or single quotes, you can just use the first example. – Ctark Sep 07 '14 at 02:03
  • The `...batch -c` approach is best (as it also solves another minor issue I had with the script). However, the observation remains: If I write the statements on different lines, I get the `Unmatched '.` errors/warnings. Only if I write them on the same line (`;`-separated), then it fully works. Strange (?) as it seemed to work on the website you point to. – Marius Hofert Sep 07 '14 at 02:27
  • 1
    Is it possible for you to post the different lines, it sounds like some of them use single quotes in them. If they do, that is where you are getting your unmatched ' errors. If you use semicolons, then you don't have the open/close single quote. I can't do anymore until I see the code you are using. – Ctark Sep 07 '14 at 03:10
  • Hi,I updated the original post with a not-so-minimal version. As you can see, it's essentially a script for doing a backup to a remote machine via `rsync`. The actual `rsync` command is a bit more tricky, but that shouldn't play a role. – Marius Hofert Sep 07 '14 at 03:23
  • Take out the double quotes from the start and end, making it: `ssh mylogin@myremotemachine.com bash -c ' rm -f /u3/mylogin/backup/old_backup ln -s $date\_backup /u3/mylogin/backup/old_backup exit '` Test with just something simple like that, if it starts working, then add things until it breaks, and go from there. – Ctark Sep 07 '14 at 04:08
  • If I do that (and have the linebreaks accordingly; see the update above), I get `bash: -c: option requires an argument` and `date: Undefined variable.`. – Marius Hofert Sep 07 '14 at 11:18
  • Assuming your updated script is all you are doing, can you move the date variable into the ssh, and remove the bash -c? See my updated answer for what I mean. – Ctark Sep 08 '14 at 20:38
  • When I move `date` "inside", I obtained `date: Undefined variable`. As this was a shell issue, I included the statement `bash` right before the `date` variable (in order to change to a bash so that the `date` is defined), but then I obtained `bash: -c: option requires an argument`. – Marius Hofert Sep 09 '14 at 01:55
  • 1
    Even though you found a different way, updated answer for anyone else that stumbles across this. the reason you were getting undefined variable is due to the rsync command using date, so you need it both inside and outside the ssh script (unless you use bash -c, and if you do you get other issues). Glad you finally found a solution that worked, sorry my solution kept having bugs. – Ctark Sep 09 '14 at 20:09
1

Maybe you have no newline at the end of script?

If there is no empty line (exactly LF - line feed character) after exit - your script will not "press enter" programatically.

Kamil
  • 2,656
  • 1
  • 19
  • 28
  • Hi, thanks for helping, I checked the script and I had two newlines there, so that wasn't the issue. – Marius Hofert Sep 07 '14 at 01:21
  • I have a question regarding this: https://unix.stackexchange.com/questions/362203/when-do-i-need-a-carriage-return-at-the-end-of-my-job-script-submitted-by-ssh. Will be beautiful if you could explain this there. – Sibbs Gambling Apr 30 '17 at 02:45