Reputation: 2921
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$>
Upvotes: 18
Views: 9712
Reputation: 849
Tried a bunch of the answers, none worked in Ubuntu 22.04
The termios.TIOCSTI does not work anymore or it may require sudo.
Eventually just opened another terminal in the new directory all invoked from my python script:
next_proj = '/home/myuserid/full/path/to/dir'
print(f'directory: {next_proj}')
os.system(f'gnome-terminal --tab '
f'-- bash -c \'cd {next_proj}; exec $SHELL\'')
Not exactly what the question is looking for but may help find a better answer. All that is needed is a way to close the previous terminal (the one the script is running in.)
Upvotes: 0
Reputation: 181
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:
pipes.quote()
function has moved to shlex.quote()
."\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)
Upvotes: 0
Reputation: 11227
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.
Upvotes: 2
Reputation: 31256
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
Upvotes: 23
Reputation: 99
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`
Upvotes: -5
Reputation: 477
cd
is exclusively(?) implemented as a shell internal command, because any external program cannot change parent shell's CWD.
Upvotes: 1
Reputation: 455410
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 cd
ing done in the sub-shell does not affect the parent shell.
Upvotes: 5