Should the args of subprocess.run() be expanded or not? - python-3.x

With python 3.7.1, both centos7 and chromeos, the following code errors out
from subprocess import run
run('git diff --quiet #{u} #{0}'.split(), shell=True)
but
run('git diff --quiet #{u} #{0}', shell=True)
works.
There are other occasions where split and not-split both works. When do they differ? Is one be more preferable than the other?

Related

Adapting a Complex System Command to subprocess.run()

I am writing a Python3 script, which must run this system command on my Ubuntu 20.04.5 LTS machine:
sudo su - otherUser -c "scp -P 1234 otherUser#10.10.10.10:/path/to/file/x.txt /tmp/x.txt"
When I manually paste this command into the server's command line, the command works just fine. Now I need my Python script to execute it. Thanks to posts like this, I believe that the subprocess.run() command should work here.
Here's my test code:
import subprocess
def main():
subprocess.run(["ls", "-l"]) # For testing purposes
print("===================================================================================")
cmd = ["sudo", "su - otherUser", "-c", "\"scp -P 1234 otherUser#10.10.10.10:/path/to/file/x.txt /tmp/x.txt\""]
print(cmd) # see the command first
subprocess.run(cmd)
if __name__ == "__main__":
main()
Output is:
me#ubuntu01$ python3 testSubprocess.py
total 4
-rw-r----- 1 demo demo 576 Jan 18 21:08 testSubprocess.py
===================================================================================
['sudo', 'su - otherUser', '-c', '"scp -P 1234 otherUser#10.10.10.10:/path/to/file/x.txt /tmp/x.txt"']
sudo: su - otherUser: command not found
me#ubuntu01$
As you can tell, I'm really confused about how to parse the command so that subprocess.run() can understand it. The documentation (here and here) isn't that helpful for a beginner like me. The format of subprocess.run() is:
subprocess.run(args, *, ...lots of other stuff...)
...where args is:
args is required for all calls and should be a string, or a sequence
of program arguments. Providing a sequence of arguments is generally
preferred, as it allows the module to take care of any required
escaping and quoting of arguments (e.g. to permit spaces in file
names). If passing a single string, either shell must be True (see
below) or else the string must simply name the program to be executed
without specifying any arguments.
I don't fully follow that, but I do understand that subprocess.run() will take a list of strings that should be the command-to-be-executed. Okay. Can someone explain how to slice up my original command?
Solution found by trial-and-error. The original code defined the command like this:
cmd = ["sudo", "su - otherUser", "-c", "\"scp -P 1234 otherUser#10.10.10.10:/path/to/file/x.txt /tmp/x.txt\""]
...and the solution that worked:
cmd = ["sudo", "su", "otherUser", "-c", "scp -P 1234 otherUser#10.10.10.10:/path/to/file/x.txt /tmp/x.txt"]
i.e.:
Broke up "su - otherUser" into "su", "otherUser"
Removed the double quotes around the SCP command

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)

Python: subprocess.call('nvm ls', shell=True) giving this error /bin/sh: nvm: command not found

def runLinter2( ):
subprocess.call('nvm ls', shell=True)
return
When i run this python script, it gives error "error /bin/sh: nvm: command not found"
but when i tun simply this nvm ls in the terminal, it works.
To run python script, i am using this command python3 test.py
Could i get help on it?
The solution is here Python subprocess.call a bash alias
You should be able to call
subprocess.call(['/bin/bash', '-i', '-c', command])
so that you can access the alias defined in ~/.bashrc

Execute shell script on cygwin from Python

I want to execute a shell script, on cygwin from Python. The shell script is creating a file as an output.
I tried
import os
import subprocess
os.chdir(r"C:\\cygwin64\\bin\\ ")
cmd = ["bash", "-c", 'cd /<path for the script>; ./test.sh']
subprocess.call(cmd)
This works:
import os, subprocess
os.chdir(r"C:\cygwin64\bin")
cmd = ["bash", "-c", "cd $HOME; pwd; exit"]
ret = subprocess.call(cmd)

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 :)

Resources