Python subprocess.run to execute bash commands via ssh - python-3.x

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)

Related

Bash on Windows: script only progresses in -v mode

I have a script which starts like this:
#!/bin/bash
echo "Running on OSTYPE: '$OSTYPE'"
DISTRO=""
CODENAME=""
SUDO=$(command -v sudo 2>/dev/null)
echo foo
When I run it as-is or with bash -x, it stops after the assignment to SUDO, I get as only output
+ DISTRO=
+ CODENAME=
++ command -v sudo
+ SUDO=
When I add -v to the bash invocation to get even more verbose output, the script runs normally and I see my "foo". I'm using bash 4.4.23 as shipped on https://git-scm.com/downloads
What is going wrong on my system and how can I debug this?
This happens because $(command ...) is a subshell.
Instead of set -x or bash -x create a file like follow inside your home folder:
.bash_env
set -x
So the set -x will be applied to any new bash instance and subinstance.

Get bash script to open terminal

In Windows when I double-click a Batch script, it will automatically open a terminal window and show me what's happening. If I were to double-click a bash script in Linux, a terminal window does not open to show me what is happening; it runs in the background. I have seen that one can use one script to launch another script in a new terminal window with x-terminal-emulator -e "./script.sh", but is there any bash command I can put into the same (one) script.sh so that it will open a terminal and show me what's happening (or if I need to answer y/n questions)?
You can do something similar to what Slax
developers do in their bootinst.sh:
#!/usr/bin/env sh
#
# If you see this file in a text editor instead of getting it executed,
# then it is missing executable permissions (chmod). You can try to set
# exec permissions for this file by using: chmod a+x bootinst.sh
#
# Scrolling down will reveal the actual code of this script.
#
# if we're running this from X, re-run the script in konsole or xterm
if [ "$DISPLAY" != "" ]; then
if [ "$1" != "--rex" -a "$2" != "--rex" ]; then
konsole --nofork -e /bin/sh $0 --rex 2>/dev/null || xterm -e /bin/sh $0 --rex 2>/dev/null || /bin/sh $0 --rex 2>/dev/null
exit
fi
fi
# put contents of your script here
echo hi
# do not close the terminal immediately, let user look at the results
echo "Press Enter..."
read junk
This script would run correctly both when started in graphical
environment and in tty. It tries to restart the script inside
konsole and xterm and but if it doesn't find neither of them it
will simply run in the background.

Passing parameter from one batch file to another not working [duplicate]

I need to execute a shell script remotely inside the Linux box from Windows
#!/bin/bash
if [ "$#" -ne 1 ]; then
echo "Illegal number of parameters"
exit
fi
echo "$1"
Here is the command I ran from Windows command prompt
cmd> plink.exe -ssh username#host -pw gbG32s4D/ -m C:\myscript.sh 5
I am getting output as
"Illegal number of parameters"
Is there any way I can pass command line parameter to shell script which will execute on remote server?
You misunderstand how the -m switch works.
It is just a way to make plink load the commands to send to the server from a local file.
The file is NOT uploaded and executed on the remote server (with arguments).
It's contents is read locally and sent to the server and executed there as if you typed it on a (remote) command line. You cannot give it arguments.
A workaround is to generate the file on the fly locally before running plink from a batch file (say run.bat):
echo echo %1 > script.tmp
plink.exe -ssh username#host -pw gbG32s4D/ -m script.tmp
Then run the batch file with the argument:
run.bat 5
The above will make the script execute echo 5 on the server.
If the script is complex, instead of assembling it locally, have it ready on the server (as #MarcelKuiper suggested) and execute just the script via Plink.
plink.exe -ssh username#host -pw gbG32s4D/ "./myscript.sh %1"
In this case, as we execute just one command, you can pass it on Plink command line, including the arguments. You do not have to use the -m switch with a (temporary) file.
I triggered the Shell script in "commands.txt" from Plink which worked for me like a charm with below method I tried:
You can define your script as an one liner using && in a file (I defined in one liner)
You need to run your command in <
Note: Use first EOF in quote like <<'EOF' but not the last one. Else you will see you code will behave weirdly.
Please see below.
Example:
sudo -i <<'EOF'
<your script here>
EOF
Then, finally run it using Plink:
plink -ssh username#hostname -pw password -m commands.txt
Have you tried putting the command and argument in quotes:
i.e. -m "C:\myscript.sh 5"

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

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.

Script command losing alias from shell

When I run the script command it loses all the aliases from the existing shell which is not desired for people using lots of aliases. So, I am trying to see if I can automatically source the .profile again to see if it works without the user have to do it.
Here below is the code:
#!/bin/bash -l
rm aliaspipe
mkfifo aliaspipe
bash -c "sleep 1;echo 'source ~/.bash_profile' > aliaspipe ;echo 'alias' > aliaspipe ;echo 'exec 0<&-' > aliaspipe"&
echo "starting script for recording"
script < aliaspipe
Basically I am creating a named pipe and the making the pipe as stdin to the script program, trying to run the source command and then close the stdin from pipe to the terminal stdin so that I can continue with the script.
But when I execute, the script is exiting after I execute "exec 0<&-",
bash-3.2$ exec 0<&-
bash-3.2$ exit
Script done, output file is typescript
Not sure why the exit is called and script is terminated. If I can make the script move the stdin from pipe to terminal then it should be fine.
You can get script to execute a bash login shell by telling it to do so explicitly.
# Gnu script (most Linux distros)
script -c "bash -l"
# BSD script (also Mac OS X)
script typescript bash -l
That will cause your .bash_profile to be sourced.
By the way, redirections are not stacks. When you write exec 0<&-, you're closing standard input, and when bash's standard input is closed, it exits.

Resources