I'm using windows 10 and while working on a new project, I need to interact with WSL(Ubuntu on windows) bash from within python (windows python interpreter).
I tried using subprocess python library to execute commands.. what I did looks like this:
import subprocess
print(subprocess.check_call(['cmd','ubuntu1804', 'BashCmdHere(eg: ls)']))#not working
print(subprocess.check_output("ubuntu1804", shell=True).decode())#also not working
The expected behavior is to execute ubuntu1804 command which starts a wsl linux bash on which I want to execute my 'BashCmdHere' and retrieve its results to python but it just freezes. What am I doing wrong ? or how to do this ?
Thank you so much
Found 2 ways to achieve this:
A correct version of my code looks like this
#e.g: To execute "ls -l"
import subprocess
print(subprocess.check_call(['wsl', 'ls','-l','MaybeOtherParamHere']))
I should have used wsl to invoke linux shell from windows aka bash then my command and parameters in separated arguments for the subprocess command.
The other way which I think is cleaner but may be heavier is using PowerShell Scripts:
#script.ps1
param([String]$folderpath, [String]$otherparam)
Write-Output $folderpath
Write-Output $otherparam
wsl ls -l $folderpath $otherparam
Then to execute it in python and get the results:
import subprocess
def callps1():
powerShellPath = r'C:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe'
powerShellCmd = "./script.ps1"
#call script with argument '/mnt/c/Users/aaa/'
p = subprocess.Popen([powerShellPath, '-ExecutionPolicy', 'Unrestricted', powerShellCmd, '/mnt/c/Users/aaa/', 'SecondArgValue']
, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output, error = p.communicate()
rc = p.returncode
print("Return code given to Python script is: " + str(rc))
print("\n\nstdout:\n\n" + str(output))
print("\n\nstderr: " + str(error))
# Test
callps1()
Thank you for helping out
What about:
print(subprocess.check_call(['ubuntu1804', 'run', 'BashCmdHere(eg: ls)'])) #also try without "run" or change ubuntu1804 to wsl
Or
print(subprocess.check_call(['cmd', '/c', 'ubuntu1804', 'run', 'BashCmdHere(eg: ls)']))#also try without "run" or change "ubuntu1804" to "wsl"
# I think you need to play with quotes here to produce: cmd /c 'ubuntu1804 run BashCmdHere(eg: ls)'
First, try to call your command from cmd.exe to see the right format and then translate it to Python.
os.system('bash')
I figured this out by accident.
Related
I made a python code that must sequentially execute a series of perl commands on the PC shell, the problem is that I did not realize that to send these scripts I have to add parameters (i have n_params), advice?
example command to send
perl [file_name.pl] [params]
To run these commands on the windows CMD I am using os and subprocess
python code example
# command = perl [file_name.pl] [params]
# path = location/of/where/the/pl/file/is/saved
perl_script = subprocess.Popen(["C:\\Perl64\\bin\\perl.exe",path + command], stdout=sys.stdout)
perl_script.communicate()
But running the script like this, the code gets me wrong because it says it can't find the filename in the specific directory
This argument to Popen()
["C:\\Perl64\\bin\\perl.exe", path + command]
does not look correct since you wrote that command is perl [file_name.pl] [params]. Instead try:
p = subprocess.Popen(["C:\\Perl64\\bin\\perl.exe", path+"file_name.pl", "param1", "param2", ...])
In Python 3.7 running on Windows, what specific syntax is required to:
1. Navigate to a directory containing a terraform program
2. Execute "terraform apply -auto-approve" in that target directory
3. Extract the resulting output variables into a form usable in python
The output variables might take the form:
security_group_id_nodes = sg-xxxxxxxxxx
vpc_id_myvpc = vpc-xxxxxxxxxxxxx
Want to be using windows cmd style commands here, NOT powershell.
My first failed newbie attempt is:
import os
os.chdir('C:\\path\\to\\terraform\\code')
from subprocess import check_output
check_output("terraform apply -auto-approve", shell=True).decode()
Not sure about your output, but subprocess could definitely make the trick.
Try something like:
command = 'terraform apply -auto-approve'
TARGET_DIR = 'E:\Target\Directory'
subprocess_handle = subprocess.Popen(shlex.split(command), cwd=TARGET_DIR, shell=False, stdout=subprocess.PIPE)
subprocess_handle.wait()
result = subprocess_handle.communicate()[0]
print(result)
Worked for me once, just play around with params.
UPD: Here I assume that "terraform" is an executable.
I'm trying to write a script that creates multiple ogr2ogr calls to a WFS service (in a loop). For some reason i can't use the osgeo lib (it's a work computer, with limited access..), so i figured i would give the Subprocess lib a try.
My though process so far is:
open OSGeo4W shell
transfer string from script to shell command line
loop for multiple ogr2ogr calls
Code:
import subprocess
p = subprocess.Popen(r'C:\Program Files\QGIS 2.18\OSGeo4W.bat',
stdout=subprocess.PIPE, stdin=subprocess.PIPE)
call = 'ogr2ogr -f "CSV" "folder_on_pc" WFS:"dbname" -sql "SELECT * from
specific_layer where attribute>=20180311 ORDER BY attribute"'
subprocess.check_call(call, shell=True)
output = p.communicate(call)[0]
I know the ogr2ogr call works, but can't seem to make the command line 'type it'. If this is a completly wrong approach, please tell me. I appriciate all help.
I am using Python 2.7.5, since this version is installed on the machine which I want to run script.
I have created a simple GUI in Tkinter, with button and text input.
Now in one input I provide the ip, or hostname of server, in next step I read the value of input fields and send it to linux bash terminal, and here I have a problem.
Reading the value from input field(works good)
nazwa_ip = self.Input_IP_hostname.get("1.0", 'end-1c')
and next:
os.system('gnome-terminal --window-with-profile=MY_PROFILE -e "ssh -t user_name#nazwa_ip"')
and here is the problem, because it wont change "nazwa_ip" to the read value. That comand send to terminal:
ssh -t user_name#nazwa_ip
but i want to send:
ssh -t user_name#ip_adres_from_input_field
Can somebody help me to resolve the issue?
according to the Python docs, it is recommended that os.system be replaced with the subprocess module .
status = os.system("mycmd" + " myarg")
# becomes
status = subprocess.call("mycmd" + " myarg", shell=True)
String formatting will work here:
os.system('gnome-terminal --window-with-profile=MY_PROFILE -e "ssh -t user_name#%s"' % nazwa_ip)
Using the subprocess method might be better to do this.
import subprocess
nazwa_ip = self.Input_IP_hostname.get("1.0", 'end-1c')
ssh_param = "ssh -t user_name#{}".format(nazwa_ip)
subprocess.call(['gnome-terminal', '--window-with-profile=MY_PROFILE', '-e', ssh_param])
Whilst running a subprocess is easy, starting one in a graphical terminal that behaves exactly like one the user launched is a little tricker. You could use my program interminal (link), which basically does what Stephen Rauch's answer does with gnome-terminal, but via a shell so that user environment variables and aliases etc are all available, which could be useful on the offchance that they affect how ssh runs.
You would use it from Python like this:
import subprocess
subprocess.Popen(['interminal', 'ssh', '-t', 'username#{}'.format(ip_address)])
I am looking for a way to execute multiple commands in the same shell instance using a separate function for each, something that I can define when the shell process opens/closes and can pass commands to.
so far all the answers I have found have only been in a single function
ie:
#!/usr/bin/env python
from subprocess import check_call
check_call(r"""set -e
ls -l
<some command> # This will change the present working directory
launchMyApp""", shell=True)
I need the same effect but with each command in a different function like
shell.open()
shell.exec("dir")
shell.exec("cd C:/Users/" + User + "/Desktop)
shell.close()
if you are wondering whyyy it has to be separate the command to run is coming from user input. yes I realize that is a security risk, but security isn't a problem in this case, as its purely an educational venture and not going to be used for anything
you could use subprocess.check_call(cmds_str, shell=True) in conjunction with multiple commands in the same line: How to run two commands in one line in Windows CMD?
You could build each command individually and add them to a list, and then use ' & '.join(cmd_list) to get cmds_str.
I don't use Windows but it works on Linux.
You can try pexpect with cmd.exe
import pexpect
child = pexpect.spawn("cmd.exe")
child.expect_exact("> ")
#print(child.before.decode('utf-8'))
print(child.before)
child.sendline("dir")
child.expect_exact("> ")
print(child.before)
child.sendline("cd C:/Users/" + User + "/Desktop")
child.expect_exact("> ")
print(child.before)
It runs cmd.exe, sends command in child.sendline() and looks for prompt child.expect_exact("> ") to get all text generated by command child.before.