Comment puis-je "cd" en Python?


Answers

Voici un exemple de gestionnaire de contexte pour modifier le répertoire de travail. C'est plus simple qu'une version d'ActiveState mentionnée ailleurs, mais cela fait le travail.

Gestionnaire de contexte: cd

import os

class cd:
    """Context manager for changing the current working directory"""
    def __init__(self, newPath):
        self.newPath = os.path.expanduser(newPath)

    def __enter__(self):
        self.savedPath = os.getcwd()
        os.chdir(self.newPath)

    def __exit__(self, etype, value, traceback):
        os.chdir(self.savedPath)

Ou essayez l' équivalent plus concis (ci-dessous) , en utilisant ContextManager .

Exemple

import subprocess # just to call an arbitrary command e.g. 'ls'

# enter the directory like this:
with cd("~/Library"):
   # we are in ~/Library
   subprocess.call("ls")

# outside the context manager we are back wherever we started.
Question

cd comme dans la commande shell pour changer le répertoire de travail.

Comment changer le répertoire de travail actuel en Python?




os.chdir() est la version Pythonic de cd .




Comme déjà mentionné par d'autres, toutes les solutions ci-dessus ne changent que le répertoire de travail du processus en cours. Ceci est perdu lorsque vous revenez au shell Unix. Si désespéré vous pouvez changer le répertoire de shell parent sur Unix avec ce hack horrible:

def quote_against_shell_expansion(s):
    import pipes
    return pipes.quote(s)

def put_text_back_into_terminal_input_buffer(text):
    # use of this means that it only works in an interactive session
    # (and if the user types while it runs they could insert characters between the characters in 'text'!)
    import fcntl, termios
    for c in text:
        fcntl.ioctl(1, termios.TIOCSTI, c)

def change_parent_process_directory(dest):
    # the horror
    put_text_back_into_terminal_input_buffer("cd "+quote_against_shell_expansion(dest)+"\n")



Si vous souhaitez effectuer quelque chose comme "cd .." option, il suffit de taper:

os.chdir ("..")

il est le même que dans Windows cmd: cd .. Bien sûr, importer os est nécessaire (par exemple, tapez-le en 1ère ligne de votre code)




Changer le répertoire courant du processus de script est trivial. Je pense que la question est en fait comment changer le répertoire courant de la fenêtre de commande à partir de laquelle un script python est appelé, ce qui est très difficile. Un script Bat dans Windows ou un script Bash dans un shell Bash peut le faire avec une commande cd ordinaire car le shell lui-même est l'interpréteur. Dans Windows et Linux, Python est un programme et aucun programme ne peut directement modifier l'environnement de ses parents. Cependant, la combinaison d'un script shell simple avec un script Python faisant la plupart des choses difficiles peut atteindre le résultat souhaité. Par exemple, pour faire une commande cd étendue avec l'historique de traversée pour revisiter vers l'arrière / vers l'avant / select, j'ai écrit un script Python relativement complexe appelé par un simple script bat. La liste de parcours est stockée dans un fichier, avec le répertoire cible sur la première ligne. Lorsque le script python revient, le script bat lit la première ligne du fichier et en fait l'argument de CD. Le script de chauve-souris complet (moins les commentaires pour la brièveté) est:

if _%1 == _. goto cdDone
if _%1 == _? goto help
if /i _%1 NEQ _-H goto doCd
:help
echo d.bat and dSup.py 2016.03.05. Extended chdir.
echo -C = clear traversal list.
echo -B or nothing = backward (to previous dir).
echo -F or - = forward (to next dir).
echo -R = remove current from list and return to previous.
echo -S = select from list.
echo -H, -h, ? = help.
echo . = make window title current directory.
echo Anything else = target directory.
goto done

:doCd
%~dp0dSup.py %1
for /F %%d in ( %~dp0dSupList ) do (
    cd %%d
    if errorlevel 1 ( %~dp0dSup.py -R )
    goto cdDone
)
:cdDone
title %CD%
:done

Le script python, dSup.py est:

import sys, os, msvcrt

def indexNoCase ( slist, s ) :
    for idx in range( len( slist )) :
        if slist[idx].upper() == s.upper() :
            return idx
    raise ValueError

# .........main process ...................
if len( sys.argv ) < 2 :
    cmd = 1 # No argument defaults to -B, the most common operation
elif sys.argv[1][0] == '-':
    if len(sys.argv[1]) == 1 :
        cmd = 2 # '-' alone defaults to -F, second most common operation.
    else :
        cmd = 'CBFRS'.find( sys.argv[1][1:2].upper())
else :
    cmd = -1
    dir = os.path.abspath( sys.argv[1] ) + '\n'

# cmd is -1 = path, 0 = C, 1 = B, 2 = F, 3 = R, 4 = S

fo = open( os.path.dirname( sys.argv[0] ) + '\\dSupList', mode = 'a+t' )
fo.seek( 0 )
dlist = fo.readlines( -1 )
if len( dlist ) == 0 :
    dlist.append( os.getcwd() + '\n' ) # Prime new directory list with current.

if cmd == 1 : # B: move backward, i.e. to previous
    target = dlist.pop(0)
    dlist.append( target )
elif cmd == 2 : # F: move forward, i.e. to next
    target = dlist.pop( len( dlist ) - 1 )
    dlist.insert( 0, target )
elif cmd == 3 : # R: remove current from list. This forces cd to previous, a
                # desireable side-effect
    dlist.pop( 0 )
elif cmd == 4 : # S: select from list
# The current directory (dlist[0]) is included essentially as ESC.
    for idx in range( len( dlist )) :
        print( '(' + str( idx ) + ')', dlist[ idx ][:-1])
    while True :
        inp = msvcrt.getche()
        if inp.isdigit() :
            inp = int( inp )
            if inp < len( dlist ) :
                print( '' ) # Print the newline we didn't get from getche.
                break
        print( ' is out of range' )
# Select 0 means the current directory and the list is not changed. Otherwise
# the selected directory is moved to the top of the list. This can be done by
# either rotating the whole list until the selection is at the head or pop it
# and insert it to 0. It isn't obvious which would be better for the user but
# since pop-insert is simpler, it is used.
    if inp > 0 :
        dlist.insert( 0, dlist.pop( inp ))

elif cmd == -1 : # -1: dir is the requested new directory.
# If it is already in the list then remove it before inserting it at the head.
# This takes care of both the common case of it having been recently visited
# and the less common case of user mistakenly requesting current, in which
# case it is already at the head. Deleting and putting it back is a trivial
# inefficiency.
    try:
        dlist.pop( indexNoCase( dlist, dir ))
    except ValueError :
        pass
    dlist = dlist[:9] # Control list length by removing older dirs (should be
                      # no more than one).
    dlist.insert( 0, dir ) 

fo.truncate( 0 )
if cmd != 0 : # C: clear the list
    fo.writelines( dlist )

fo.close()
exit(0)



cd() est facile à écrire en utilisant un générateur et un décorateur.

from contextlib import contextmanager
import os

@contextmanager
def cd(newdir):
    prevdir = os.getcwd()
    os.chdir(os.path.expanduser(newdir))
    try:
        yield
    finally:
        os.chdir(prevdir)

Ensuite, le répertoire est restauré même après qu'une exception est levée:

os.chdir('/home')

with cd('/tmp'):
    # ...
    raise Exception("There's no place like home.")
# Directory is now back to '/home'.