Change working directory in shell with a python script - python

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`

Related

Python: change file/folder attributes in windows OS

I have made a folder using python3 script, and to apply multiple attributes (+h +s) to the folder I have to run ATTRIB command in Command Prompt.
But I want to know how it can be done from the same python3 script.
import os
os.makedir("C:\\AutoSC")
# Now I want the code to give the same result such that I have opned CMD and writen following command
# C:\> attrib +h +s AutoSC
# Also show in the code, necessary imported modules
I want the folder to be created and immediately hidden as system folder.
Which is not visible even after show hidden files.
Use the subprocess module or use os.system to send commands directly to OS.
import subprocess
subprocess.run(["ls","-l"])# in linux, for windows, it may change.
import os
os.system('attrib +h +s AutoSC')

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/')

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

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.

python subprocess shouldn't run from within the folder

I am trying to use the C&C NLP library in my mac and it uses terminal as its interface. so naturally I'm trying to run the command from my python, but here's what happens:
candc:could not open model configuration file for reading:models/config
turns out candc should not be called from the same directory, and should be called from outside of the binary folder, something like "bin/candc".
how can I make this work?
this is my code:
cmd="candc/bin/candc --models models"
subprocess.check_output('{} | tee /dev/stderr'.format( cmd ), shell=True)
Pass the cwd argument with your desired working directory.
For example, if you want to run it as bin/candc from the candc directory:
import os
cmd="bin/candc --models models"
subprocess.check_output('{} | tee /dev/stderr'.format( cmd ), shell=True, cwd=os.path.abspath('candc'))
(I'm not sure whether you actually need os.path.abspath. Do test both with and without it.)
Use the full path in cmd:
cmd = "/home/your-username/python-programs/cnc/candc/bin/canc --models models
Whatever that full path might be. You can use (if you're on linux) pwd inside the candc directory to find out what it is.

Categories

Resources