How to exit from shell script if any of the command in SSH returns non-zero value - linux

I have a shell script with below ssh command to perform few actions,
$SSH $user#$remoteIpAddress "sudo rm -rf $remoteLocation/xxx/*; cd $remoteLocation/yyy; .... ... "
Directory $remoteLocation/yyy is not available and it will display the error as,
./test.sh: line 6: cd: /opt/test/yyy: No such file or directory
and it is proceeding to the next line. My scenario is to exit from the shell script itself if any command in ssh returns non-zero value. I could add set -e to exit from shell but i am not sure how to handle it in ssh. Thanks in advance.
EDIT :
I have few lines of command below the SSH command. I need a solution to exit entirely from the script and not to execute any lines below the ssh command.

Keep in mind that your set -e idea applies just as well to the shell you open on the other end with ssh. So you can prepend your ssh commands with that to ensure an error terminates the ssh session:
$SSH $user#$remoteIpAddress "set -e; sudo rm -rf $remoteLocation/xxx/*; cd $remoteLocation/yyy; .... ... "
Then the ssh shell will exit with non-zero error code as soon as an error is encountered, and your script will exit as well if you have set -e earlier in your script.

Related

Python subprocess.run to execute bash commands via ssh

I am currently creating a function that will run at least 2 bash commands on a remote system via subprocess.run module because I need to capture the return code as well.
The example bash commands is ssh username#ipaddress 'ls && exit'
This will basically print out the contents of the remote home directory and exit the terminal created.
This works when using os.system("ssh username#ipaddress 'ls && exit'") but will not capture the return code.
In subprocess.run
### bashCommand is "ssh username#ipaddress 'ls && exit'"
bashCommand = ['ssh', f"username#ipaddress", "'ls && exit'"]
output = subprocess.run(bashCommand)
However when the subprocess.run command was run,
the terminal says that bash: ls && exit: command not found
the return code is 127 (from output.returncode)

How to get exit code of remote command through ssh

I am running a script from remote machine via ssh:
ssh 'some_cmd;my_script'
Now, I want to store exit status of shell script on my local machine.
How can I do it?
Assuming nothing goes wrong with ssh itself, its exit status is the exit status of the last command executed on the remote host. (If something does go wrong, its exit status is 255.)
$ ssh remotehost exit 13
$ echo $?
13
I had same problem. I don't think the previous answers will work (at least, they did not work for me).
This is what worked for me: I ran my command and displayed the exit code and captured it in a variable.
Ensure you protect the $? sign with the escape sequence, \:
# retcode=$(ssh test#1.2.3.4 "grep -q test /etc/passwd ; echo \$? " 2>/dev/null)
# echo $retcode
# 1

Execute remote bash with ssh together with a local script, that, when ends, will kill the remote execution

I logged with ssh on the server with public key (no password).
This are the command that I would like to automatize with a bash:
ssh user#ip
cd path
./bash0.sh parameter1 paramter2 & <-- this is a loop and is working on remote server in background
exit <-- exit form ssh
./bash1.sh <-- starting local bash
ssh user#ip pkill bash0.sh <-- kill the process at the end of the bash1.sh. From terminal is ok, but from bash?
The problem is to execute the cd path and immediately after the ./bash0.sh paramter1 parameter2 & and then exit from ssh without waiting the ./bash0.sh to finish.
I cannot do ssh user#ip ./path/bash0.sh paramter1 paramter2 because the bash file contains relative paths.
Simple approach:
./bash1.sh && ssh user#ip pkill bash0.sh
Found the solution:
ssh user#ip "cd path && ./bash0.sh parameter1 paramter2" &
/bash1.sh <-- starting local bash
ssh user#ip pkill bash0.sh
The "" are very important.
You can send mutliple commands over ssh by seperating them with a semicolon:
ssh user#ip "cd path;./bash0.sh parameter1 parameter2 & exit"
(the exit is not needed but only there to show how to append more commands after the &)
And ssh user#ip pkill bash0.sh should work from a bash script. Your terminal is probably also just bash.
EDIT: See http://www.skorks.com/2010/05/executing-multiple-commands-a-bash-productivity-tip/ for a detailed explanation of the ;, & and && operator.

Run a shell script in new terminal from current terminal

How do you run a shell script in a new terminal in Linux from a terminal like "start test.bat" in Windows, also it should be working in the console mode.
Here's a simple example to get you started:
To write a shell script, do this on your command prompt:
echo -e '#!/bin/sh\n echo "hello world"' > abc.sh
This writes:
#!/bin/sh
echo "hello world"
To a file called abc.sh
Next, you want to set it to executable by:
chmod +x abc.sh
Now, you can run it by:
./abc.sh
And you should see:
hello world
On your terminal.
To run it in a new terminal, you can do:
gnome-terminal -x ./abc.sh
or, if it's xterm:
xterm -e ./abc.sh
Here's a list of different terminal emulators.
Alternatively, you just run it in your current terminal, but background it instead by:
./abc.sh &
I came here wanting to figure out how to make a script spawn a terminal and run it self in it, so for those who want to do that I figured out this solution:
if [ ! -t 0 ]; then # script is executed outside the terminal?
# execute the script inside a terminal window with same arguments
x-terminal-emulator -e "$0" "$#"
# and abort running the rest of it
exit 0
fi
For gnome try this.
Replace ls with the command you want to run
gnome-terminal -x sh -c "ls|less"
I hope this is what you want
As of January 2020, the -e and -x option in gnome-terminal still run properly but throw out the following warnings:
For -e:
# Option “-e” is deprecated and might be removed in a later version
of gnome-terminal.
# Use “-- ” to terminate the options and put the command line to
execute after it.
For -x:
# Option “-x” is deprecated and might be removed in a later version
of gnome-terminal.
# Use “-- ” to terminate the options and put the command line to
execute after it.
Based on that information above, I confirmed that you can run the following two commands without receiving any warning messages:
gnome-terminal -- /bin/sh -c '<your command>'
gnome-terminal -- ./<your script>.sh
I hope this helps anyone else presently having this issue :)

how to write a bash shell script to ssh to remote machine and change user and export a env variable and do other commands

I have a webservice that runs on multiple different remote redhat machines. Whenever I want to update the service I will sync down the new webservice source code written in perl from a version control depot(I use perforce) and restart the service using that new synced down perl code. I think it is too boring to log to remote machines one by one and do that series of commands to restart the service one by one manully. So I wrote a bash script update.sh like below in order to "do it one time one place, update all machines". I will run this shell script in my local machine. But it seems that it won't work. It only execute the first command "sudo -u webservice_username -i" as I can tell from the command line in my local machine. (The code below only shows how it will update one of the remote webservice. The "export P4USER=myname" is for usage of perforce client)
#!/bin/sh
ssh myname#remotehost1 'sudo -u webservice_username -i ; export P4USER=myname; cd dir ; p4 sync ; cd bin ; ./prog --domain=config_file restart ; tail -f ../logs/service.log'
Why I know the only first command is executed? Well because after I input the password for the ssh on my local machine, it shows:
Your environment has been modified. Please check /tmp/webservice.env.
And it just gets stuck there. I mean no return.
As suggested by a commentor, I added "-t" for ssh
#!/bin/sh
ssh -t myname#remotehost1 'sudo -u webservice_username -i ; export P4USER=myname; cd dir ; p4 sync ; cd bin ; ./prog --domain=config_file restart ; tail -f ../logs/service.log'
This would let the local commandline return. But it seems weird, it cannot cd to that "dir", it says "cd:dir: No such file or directory" it also says "p4: command not found". So it looks like the sudo -u command executes with no effect and the export command has either not executed or excuted with no effect.
A detailed local log file is like below:
Your environment has been modified. Please check /tmp/dir/.env.
bash: line 0: cd: dir: No such file or directory
bash: p4: command not found
bash: line 0: cd: bin: No such file or directory
bash: ./prog: No such file or directory
tail: cannot open `../logs/service.log' for reading: No such file or directory
tail: no files remaining
Instead of connecting via ssh and then immediately changing users, can you not use something like ssh -t webservice_username#remotehost1 to connect with the desired username to begin with? That would avoid needing to sudo altogether.
If that isn't a possibility, try wrapping up all of the commands that you want to run in a shell script and store it on the remote machine. If you can get your task working from a script, then your ssh call becomes much simpler and should encounter fewer problems:
ssh myname#remotehost1 '/path/to/script'
For easily updating this script, you can write a short script for your local machine that uploads the most recent version via scp and then uses ssh to invoke it.
Note that when you run:
#!/bin/sh
ssh myname#remotehost1 'sudo -u webservice_username -i ; export P4USER=myname; cd dir ; p4 sync ; cd bin ; ./prog --domain=config_file restart ; tail -f ../logs/service.log'
Your ssh session runs sudo -u webservice_username -i waits for it to exit and then runs the rest of the commands; it does not execute sudo and then run the commands following. This has to do with the context in which you're running the series of commands. All the commands get executed in the shell of myname#remotehost1 and all sudo -u webservice_username - i is starts a shell for webservice_username and doesn't actually run any commands.
Really the best solution here is like bta said; write a script and then rsync/scp it to the destination and then run that using sudo.
export command simply not working with ssh like this, what you want to do is remote modify ~/.bashrc and it will source itself each time u do ssh login.

Resources