Korzystając z tej metody, należy przestrzegać dwóch najlepszych praktyk:
Złap wyjątek (WindowsError, OSError) na niepoprawnej ścieżce. Jeśli zgłoszony zostanie wyjątek, nie wykonuj żadnych operacji rekurencyjnych, szczególnie destrukcyjnych. Będą działać na starej, a nie nowej ścieżce.
Po zakończeniu wróć do starego katalogu. Można to zrobić w sposób wyjątkowo bezpieczny, zawijając połączenie chdir w menedżerze kontekstu, tak jak zrobił to Brian M. Hunt w swojej odpowiedzi .
Zmiana bieżącego katalogu roboczego w podprocesie nie zmienia bieżącego katalogu roboczego w procesie nadrzędnym. Dotyczy to również interpretera języka Python. Nie można użyć os.chdir()do zmiany CWD procesu wywołującego.
cdunn2001 lekki „s odpowiedź dekorator oparte jest podejście idealne dla nowoczesnych Python. Powyższa odpowiedź pokazuje, dlaczego. Nigdy nie dzwoń os.chdir()poza menedżerem kontekstu, chyba że uważasz, że wiesz, co robisz. ( Prawdopodobnie nie. )
Cecil Curry
6
To chyba najłatwiejszy sposób w interaktywnej powłoce. Pamiętaj, że w systemie Windows musisz używać ukośników, takich jakos.chdir("C:/path/to/location")
Josiah
Jedyną rzeczą, o której należy pamiętać, jest to, że jeśli uczynisz program python wykonywalnym i uruchomisz go w cronie, uruchomi się on w twoim katalogu domowym. Dlatego najlepiej jest użyć w pełni kwalifikowanej ścieżki. To zdecydowanie działa, ale nadal używam w pełni kwalifikowanych ścieżek w każdym skrypcie, który mógłbym wywołać z Pythona, ponieważ nie ma gwarancji, że będzie to miało zastosowanie poza samym programem Python.
SDsolar
310
Oto przykład menedżera kontekstu do zmiany katalogu roboczego. Jest to prostsze niż wersja ActiveState, o której mowa w innym miejscu, ale wykonuje to zadanie.
Menedżer kontekstu: cd
import osclass 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)
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.
Jeśli kiedykolwiek będziesz potrzebować wiedzieć, z którego katalogu zmieniłeś, możesz po prostu dodać return selfna końcu __enter__. W ten sposób możesz uzyskać with cd('foo') as cm:dostęp do poprzedniego katalogu jakocm.savedPath
Sam F
Zauważ, że zdarzają się przypadki, w których powrót do starego katalogu (zapisanego w „savePath”) nie jest możliwy. Na przykład, jeśli proces bardziej uprzywilejowany uruchamia proces mniej uprzywilejowany, drugi proces dziedziczy katalog roboczy pierwszych procesów, nawet w tych przypadkach, w których drugi proces nie może wejść do tego katalogu roboczego z własnymi możliwościami.
Kai Petzke,
141
Użyłbym os.chdirtak:
os.chdir("/path/to/change/to")
Nawiasem mówiąc, jeśli chcesz obliczyć swoją obecną ścieżkę, użyj os.getcwd().
Blask! Gdyby do tej odpowiedzi wprowadzono komentarz wprowadzający do zaakceptowanej odpowiedzi, byłoby to niezmiernie idealne. Mimo to zwięzła, bezpieczna implementacja Pythona uzasadnia wszystkie opinie, które muszę udzielić.
Cecil Curry
3
Dlaczego yieldnie return? Czy to ma być generator?
EKons,
Proszę skomentować związek między wydajnością a zwrotem!
NicoBerrogorry
1
@NicoBerrogorry, to generator. Zobacz dokumentację na contextlib.contextmanager . Jest to bardzo przydatny wzorzec w Pythonie, którego warto się nauczyć.
cdunn2001
25
Jeśli używasz stosunkowo nowej wersji Pythona, możesz również użyć menedżera kontekstu, takiego jak ten :
from __future__ import with_statement
from grizzled.os import working_directory
with working_directory(path_to_directory):# code in here occurs within the directory# code here is in the original directory
AKTUALIZACJA
Jeśli wolisz rzucić własny:
import os
from contextlib import contextmanager
@contextmanagerdef working_directory(directory):
owd = os.getcwd()try:
os.chdir(directory)yield directory
finally:
os.chdir(owd)
Zależności są złe. Wbudowany contextlib.contextmanagerdekorator Pythona jest dobry. Zobacz cdunn2001 „s dekorator oparte na odpowiedź , która najlepiej byłoby zaakceptowanej odpowiedzi teraz.
Cecil Curry
14
Jak już zauważyli inni, wszystkie powyższe rozwiązania zmieniają tylko katalog roboczy bieżącego procesu. Jest to tracone, gdy wracasz do powłoki Unix. Jeśli jesteś zdesperowany, możesz zmienić katalog powłoki nadrzędnej w Uniksie za pomocą tego okropnego włamania:
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")
Szalony, kruchy hack otrzymuje obowiązkowe głosy poparcia. Nikt nigdy nie powinien tego robić, szczególnie z tym zastrzeżeniem „i jeśli użytkownik pisze podczas pracy ...”. Mimo to budzi we mnie buntowniczą brodę, widząc, że zmiana macierzystej CWD jest w pewnym sensie, ale nie jest tak naprawdę możliwa. Pozytywne opinie! Pozytywne opinie dla wszystkich!
Jeśli używasz GUI spyder i love, możesz po prostu kliknąć przycisk folderu w prawym górnym rogu ekranu i poruszać się po folderach / katalogach, które chcesz jako bieżący katalog. Po zrobieniu tego możesz przejść do zakładki eksploratora plików w oknie w spyder IDE i możesz zobaczyć wszystkie obecne tam pliki / foldery. aby sprawdzić bieżący katalog roboczy, przejdź do konsoli spyder IDE i po prostu wpisz
pwd
wydrukuje tę samą ścieżkę, którą wcześniej wybrałeś.
Zmiana bieżącego katalogu procesu skryptu jest banalna. Myślę, że tak naprawdę chodzi o to, jak zmienić bieżący katalog okna poleceń, z którego wywoływany jest skrypt Pythona, co jest bardzo trudne. Skrypt Bat w systemie Windows lub skrypt Bash w powłoce Bash może to zrobić za pomocą zwykłego polecenia cd, ponieważ sama powłoka jest tłumaczem. Zarówno w systemie Windows, jak i Linux Python jest programem i żaden program nie może bezpośrednio zmienić środowiska swojego rodzica. Jednak połączenie prostego skryptu powłoki ze skryptem Python wykonującym większość trudnych zadań może osiągnąć pożądany rezultat. Na przykład, aby wykonać rozszerzoną komendę cd z historią przechodzenia do ponownego przeglądania wstecz / do przodu / wybierz, napisałem stosunkowo złożony skrypt Pythona wywoływany przez prosty skrypt nietoperzy. Lista przejść jest przechowywana w pliku, z katalogiem docelowym w pierwszym wierszu. Kiedy skrypt python powraca, skrypt nietoperza odczytuje pierwszy wiersz pliku i staje się argumentem cd. Kompletny skrypt nietoperza (bez komentarzy dla zwięzłości) to:
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 andreturn to previous.
echo -S = select from list.
echo -H,-h,?= help.
echo .= make window title current directory.
echo Anythingelse= target directory.
goto done
:doCd
%~dp0dSup.py %1for/F %%d in(%~dp0dSupList )do(
cd %%d
if errorlevel 1(%~dp0dSup.py -R )
goto cdDone
):cdDone
title %CD%:done
Skrypt Pythona, dSup.py to:
import sys, os, msvcrt
def indexNoCase ( slist, s ):for idx in range( len( slist )):if slist[idx].upper()== s.upper():return idx
raiseValueError# .........main process ...................if len( sys.argv )<2:
cmd =1# No argument defaults to -B, the most common operationelif 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])whileTrue:
inp = msvcrt.getche()if inp.isdigit():
inp = int( inp )if inp < len( dlist ):print('')# Print the newline we didn't get from getche.breakprint(' 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 ))exceptValueError: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)
Chociaż jest to dobra odpowiedź, OP wybrał odpowiedź, która mówi, że nie chodzi o zmianę CWD procesu nadrzędnego. To usuwa wszelkie możliwe nieporozumienia dotyczące znaczenia pytania.
Tin Man
Tin Man - ta odpowiedź została wybrana, zanim opublikowałem moją sugestię. Myślę, że szerokie spektrum odpowiedzi mogło być mylące. cd w ramach danego procesu (tj. skryptu Pythona) jest tak prosty, że nie wiem, dlaczego ktokolwiek miałby go zadawać.
David McCracken,
1
Właściwie ta odpowiedź została wybrana lata temu. Gdyby to nie było właściwe, odtąd byłby wielokrotnie wzywany.
Tin Man
Myślę, że zamieszanie pozostaje. Niedawno pytanie „symulujące komendę„ cd ”linuxa w pythonie i utrzymujące zmianę katalogu po wyjściu programu [duplikat]” zostało odrzucone jako udzielone tutaj, ale w rzeczywistości to pytanie nie zostało rozwiązane przez wybraną odpowiedź. Moja sugestia dotyczy systemu Windows, ale problemy są takie same w systemie Linux.
os.chdir(os.path.join(os.path.abspath(os.path.curdir),u'subfolder'))
- czy?os.getcwd()
Odpowiedzi:
Możesz zmienić katalog roboczy za pomocą:
Korzystając z tej metody, należy przestrzegać dwóch najlepszych praktyk:
Zmiana bieżącego katalogu roboczego w podprocesie nie zmienia bieżącego katalogu roboczego w procesie nadrzędnym. Dotyczy to również interpretera języka Python. Nie można użyć
os.chdir()
do zmiany CWD procesu wywołującego.źródło
os.chdir()
poza menedżerem kontekstu, chyba że uważasz, że wiesz, co robisz. ( Prawdopodobnie nie. )os.chdir("C:/path/to/location")
Oto przykład menedżera kontekstu do zmiany katalogu roboczego. Jest to prostsze niż wersja ActiveState, o której mowa w innym miejscu, ale wykonuje to zadanie.
Menedżer kontekstu:
cd
Lub wypróbuj bardziej zwięzły odpowiednik (poniżej) , używając ContextManager .
Przykład
źródło
return self
na końcu__enter__
. W ten sposób możesz uzyskaćwith cd('foo') as cm:
dostęp do poprzedniego katalogu jakocm.savedPath
Użyłbym
os.chdir
tak:Nawiasem mówiąc, jeśli chcesz obliczyć swoją obecną ścieżkę, użyj
os.getcwd()
.Więcej tutaj
źródło
cd()
łatwo jest napisać za pomocą generatora i dekoratora.Następnie katalog jest przywracany nawet po zgłoszeniu wyjątku:
źródło
try/finally
).yield
niereturn
? Czy to ma być generator?Jeśli używasz stosunkowo nowej wersji Pythona, możesz również użyć menedżera kontekstu, takiego jak ten :
AKTUALIZACJA
Jeśli wolisz rzucić własny:
źródło
contextlib.contextmanager
dekorator Pythona jest dobry. Zobacz cdunn2001 „s dekorator oparte na odpowiedź , która najlepiej byłoby zaakceptowanej odpowiedzi teraz.Jak już zauważyli inni, wszystkie powyższe rozwiązania zmieniają tylko katalog roboczy bieżącego procesu. Jest to tracone, gdy wracasz do powłoki Unix. Jeśli jesteś zdesperowany, możesz zmienić katalog powłoki nadrzędnej w Uniksie za pomocą tego okropnego włamania:
źródło
os.chdir()
jest właściwą drogą.źródło
os.chdir()
to wersja Pythoniccd
.źródło
Możesz używać obu z os.chdir (abs_path) lub os.chdir (rel_path), nie ma potrzeby wywoływania os.getcwd () w celu użycia ścieżki względnej.
źródło
Dalej w kierunku wskazanym przez Briana i opartym na sh (1.0.8+)
źródło
Jeśli chcesz wykonać coś takiego jak opcja „cd ..”, po prostu wpisz:
os.chdir („..”)
jest taki sam jak w Windows cmd: cd .. Oczywiście import os jest niezbędny (np. wpisz go jako 1 wiersz kodu)
źródło
Jeśli używasz GUI spyder i love, możesz po prostu kliknąć przycisk folderu w prawym górnym rogu ekranu i poruszać się po folderach / katalogach, które chcesz jako bieżący katalog. Po zrobieniu tego możesz przejść do zakładki eksploratora plików w oknie w spyder IDE i możesz zobaczyć wszystkie obecne tam pliki / foldery. aby sprawdzić bieżący katalog roboczy, przejdź do konsoli spyder IDE i po prostu wpisz
wydrukuje tę samą ścieżkę, którą wcześniej wybrałeś.
źródło
Zmiana bieżącego katalogu procesu skryptu jest banalna. Myślę, że tak naprawdę chodzi o to, jak zmienić bieżący katalog okna poleceń, z którego wywoływany jest skrypt Pythona, co jest bardzo trudne. Skrypt Bat w systemie Windows lub skrypt Bash w powłoce Bash może to zrobić za pomocą zwykłego polecenia cd, ponieważ sama powłoka jest tłumaczem. Zarówno w systemie Windows, jak i Linux Python jest programem i żaden program nie może bezpośrednio zmienić środowiska swojego rodzica. Jednak połączenie prostego skryptu powłoki ze skryptem Python wykonującym większość trudnych zadań może osiągnąć pożądany rezultat. Na przykład, aby wykonać rozszerzoną komendę cd z historią przechodzenia do ponownego przeglądania wstecz / do przodu / wybierz, napisałem stosunkowo złożony skrypt Pythona wywoływany przez prosty skrypt nietoperzy. Lista przejść jest przechowywana w pliku, z katalogiem docelowym w pierwszym wierszu. Kiedy skrypt python powraca, skrypt nietoperza odczytuje pierwszy wiersz pliku i staje się argumentem cd. Kompletny skrypt nietoperza (bez komentarzy dla zwięzłości) to:
Skrypt Pythona, dSup.py to:
źródło