os.system(<command>) execution through Python :: Limitations? - python

I'm writing a python (ver 2.7) script to automate the set of commands in this Getting Started example for INOTOOL.
Problem: When I run this entire script, I repeatedly encounter these errors:
Current Directory is not empty
No project is found in this directory
No project is found in this directory
But, when I run a first script only up till the code line marked, and manually type in the next three lines, or when I run these last three lines (starting from the "ino init -t blink" line) after manually accessing the beep folder, then I am able to successfully execute the same code.
Is there a limitation with os.system() that I'm encountering?
My code:
import os,sys
def upload()
os.system("cd /home/pi/Downloads")
os.system("mkdir beep")
os.system("cd beep") #will refer to this code junction in question description
os.system("ino init -t blink")
os.system("ino build")
os.system("ino upload")
sys.exit(0)

Yes, when os.system() commands are run for cd , it does not actually change the current directory for the python process' context. From documentation -
os.system(command)
Execute the command (a string) in a subshell. This is implemented by calling the Standard C function system(), and has the same limitations. Changes to sys.stdin, etc. are not reflected in the environment of the executed command.
So even though you are changing directory in os.system() call, the next os.system call still occurs in same directory. Which could be causing your issue.
You shoud try using os.chdir() to change the directory instead of os.system() calls.
The Best would be to use subprocess module as #PadraicCunningham explains in his answer.

You can use the subprocess module and os.mkdir to make the directory, you can pass the current working directory cwd to check_callso you actually execute the command in the directory:
from subprocess import check_call
import os
def upload():
d = "/home/pi/Downloads/beep"
os.mkdir(d)
check_call(["ino", "init", "-t", "blink"],cwd=d)
check_call(["ino", "build"],cwd=d)
check_call(["ino", "upload"],cwd=d)
A non-zero exit status will raise CalledProcessError which you may want to catch but once successful you know the commands all returned a 0 exit status.

Related

Python CMD Directory Navigation

Ok, so I'm making a sort of Python middle man. Basically, it takes user input and throws it at Command Prompt, and then returns the output. Here's the code.
import os
console=True
while console==True:
command=input(">")
os.system(command)
The issue is that directory navigation does not seem to be working. The following is what happens when I use the cd command.
>cd
C:\Users\Username\Desktop\Stuff
>cd ..
>cd
C:\Users\Username\Desktop\Stuff
Any ideas?
the problem is that when you execute the cd command it is executed in another context, it is another independent process because your main process never changes directory. you should use the os.chdir (path) method
Changing working directory cannot be done via external commands. You have to parse the command line by yourself:
command = input("> ")
cmd = command.split()
if cmd[0] == "cd":
os.chdir(cmd[1])
Of course, the above code is only an example because the use of str.split() is too wild. You need to take care of quotes and escaped spaces if you want a fully working "shell".

running bash script from python file

I have a bash script which changes the path on my command line,
This one,
#!/usr/bin/env python
cd /mnt/vvc/username/deployment/
I have a python script which i wish to run after the path changes to the desired path,
The script,
#!/usr/bin/env python
import subprocess
import os
subprocess.call(['/home/username/new_file.sh'])
for folder in os.listdir(''):
print ('deploy_predict'+' '+folder)
I get this
File "/home/username/new_file.sh", line 2
cd /mnt/vvc/username/deployment/
^
SyntaxError: invalid syntax
Any suggestions on how can i fix this?thanks in advance
You need to explicitly tell subprocess which shell to run the sh file with. Probably one of the following:
subprocess.call(['sh', '/home/username/new_file.sh'])
subprocess.call(['bash', '/home/username/new_file.sh'])
However, this will not change the python program's working directory as the command is run in a separate context.
You want to do this to change the python program's working directory as it runs:
os.chdir('/mnt/vvc/username/deployment/')
But that's not really great practice. Probably better to just pass the path into os.listdir, and not change working directories:
os.listdir('/mnt/vvc/username/deployment/')

python: how to run a program with a command line call (that takes a user's keystroke as input) from within another program?

I can run one program by typing: python enable_robot.py -e in the command line, but I want to run it from within another program.
In the other program, I imported subprocess and had subprocess.Popen(['enable_robot', 'baxter_tools/scripts/enable_robot.py','-e']), but I get an error message saying something about a callback.
If I comment out this line, the rest of my program works perfectly fine.
Any suggestions on how I could change this line to get my code to work or if I shouldn't be using subprocess at all?
If enable_robot.py requires user input, probably it wasn't meant to run from another python script. you might want to import it as a module: import enable_robot and run the functions you want to use from there.
If you want to stick to the subprocess, you can pass input with communicate:
p = subprocess.Popen(['enable_robot', 'baxter_tools/scripts/enable_robot.py','-e'])
p.communicate(input=b'whatever string\nnext line')
communicate documentation, example.
Your program enable_robot.py should meet the following requirements:
The first line is a path indicating what program is used to interpret
the script. In this case, it is the python path.
Your script should be executable
A very simple example. We have two python scripts: called.py and caller.py
Usage: caller.py will execute called.py using subprocess.Popen()
File /tmp/called.py
#!/usr/bin/python
print("OK")
File /tmp/caller.py
#!/usr/bin/python
import subprocess
proc = subprocess.Popen(['/tmp/called.py'])
Make both executable:
chmod +x /tmp/caller.py
chmod +x /tmp/called.py
caller.py output:
$ /tmp/caller.py
$ OK

Run shell command in pdb mode

I want to run cd and ls in python debugger. I try to use !ls but I get
*** NameError: name 'ls' is not defined
Simply use the "os" module and you will able to easily execute any os command from within pdb.
Start with:
(Pdb) import os
And then:
(Pdb) os.system("ls")
or even
(Pdb) os.system("sh")
the latest simply spawns a subshell. Exiting from it returns back to debugger.
Note: the "cd" command will have no effect when used as os.system("cd dir") since it will not change the cwd of the python process. Use os.chdir("/path/to/targetdir") for that.
PDB doesn't let you run shell commands, unfortunately. The reason for the error that you are seeing is that PDB lets you inspect a variable name or run a one-line snippet using !. Quoting from the docs:
[!]statement
Execute the (one-line) statement in the context of the current stack frame. The exclamation point can be omitted unless the first word of the statement resembles a debugger command. To set a global variable, you can prefix the assignment command with a global command on the same line, e.g.:
(Pdb) global list_options; list_options = ['-l']
(Pdb)
Thus !ls mean "print the value of ls", which causes the NameError that you observed.
PDB works very similarly to the normal python console so packages can be imported and used as you would normally do in the python interactive session.
Regarding the directory listing you should use the os module (inside the PDB, confirming each line with return aka. enter key ;) ):
from os import listdir
os.listdir("/path/to/your/folder")
Or if you want to do some more advanced stuff like start new processes or catch outputs etc. you need to have a look on subprocess module.

Change working directory in shell with a python script

I want to implement a userland command that will take one of its arguments (path) and change the directory to that dir. After the program completion I would like the shell to be in that directory. So I want to implement cd command, but with external program.
Can it be done in a python script or I have to write bash wrapper?
Example:
tdi#bayes:/home/$>python cd.py tdi
tdi#bayes:/home/tdi$>
Others have pointed out that you can't change the working directory of a parent from a child.
But there is a way you can achieve your goal -- if you cd from a shell function, it can change the working dir. Add this to your ~/.bashrc:
go() {
cd "$(python /path/to/cd.py "$1")"
}
Your script should print the path to the directory that you want to change to. For example, this could be your cd.py:
#!/usr/bin/python
import sys, os.path
if sys.argv[1] == 'tdi': print(os.path.expanduser('~/long/tedious/path/to/tdi'))
elif sys.argv[1] == 'xyz': print(os.path.expanduser('~/long/tedious/path/to/xyz'))
Then you can do:
tdi#bayes:/home/$> go tdi
tdi#bayes:/home/tdi$> go tdi
That is not going to be possible.
Your script runs in a sub-shell spawned by the parent shell where the command was issued.
Any cding done in the sub-shell does not affect the parent shell.
cd is exclusively(?) implemented as a shell internal command, because any external program cannot change parent shell's CWD.
As codaddict writes, what happens in your sub-shell does not affect the parent shell. However, if your goal is to present the user with a shell in a different directory, you could always have Python use os.chdir to change the sub-shell's working directory and then launch a new shell from Python. This will not change the working directory of the original shell, but will leave the user with one in a different directory.
As explained by mrdiskodave
in Equivalent of shell 'cd' command to change the working directory?
there is a hack to achieve the desired behavior in pure Python.
I made some modifications to the answer from mrdiskodave to make it work in Python 3:
The pipes.quote() function has moved to shlex.quote().
To mitigate the issue of user input during execution, you can delete any previous user input with the backspace character "\x08".
So my adaption looks like the following:
import fcntl
import shlex
import termios
from pathlib import Path
def change_directory(path: Path):
quoted_path = shlex.quote(str(path))
# Remove up to 32 characters entered by the user.
backspace = "\x08" * 32
cmd = f"{backspace}cd {quoted_path}\n"
for c in cmd:
fcntl.ioctl(1, termios.TIOCSTI, c)
I shall try to show how to set a Bash terminal's working directory to whatever path a Python program wants in a fairly easy way.
Only Bash can set its working directory, so routines are needed for Python and Bash. The Python program has a routine defined as:
fob=open(somefile,"w")
fob.write(dd)
fob.close()
"Somefile" could for convenience be a RAM disk file. Bash "mount" would show tmpfs mounted somewhere like "/run/user/1000", so somefile might be "/run/user/1000/pythonwkdir". "dd" is the full directory path name desired.
The Bash file would look like:
#!/bin/bash
#pysync ---Command ". pysync" will set bash dir to what Python recorded
cd `cat /run/user/1000/pythonwkdr`

Categories

Resources