cd - это команда оболочки для изменения рабочего каталога.
Как изменить текущий рабочий каталог в Python?
Интересно в этом контексте: Найти текущий каталог и каталог с файлом: os.getcwd()






os.chdir() - это питоническая версия cd.
os.chdir() - правильный путь.
Вы можете изменить рабочий каталог с помощью:
import os
os.chdir(path)
При использовании этого метода следует придерживаться двух рекомендаций:
Изменение текущего рабочего каталога в подпроцессе не изменяет текущий рабочий каталог в родительском процессе. Это верно и для интерпретатора Python. Вы не можете использовать os.chdir() для изменения CWD вызывающего процесса.
Облегченный ответ на основе декоратораcdunn2001 - идеальный подход для современного Python. Приведенный выше ответ демонстрирует, почему. Никогда не вызывайте os.chdir() вне контекстного менеджера,, если вы не думаете, что знаете, что делаете. (Вероятно, вы этого не сделаете.)
Думаю, это самый простой способ в интерактивной оболочке. Обратите внимание, что в Windows вы должны использовать косую черту, например os.chdir("C:/path/to/location").
Единственное, о чем следует знать, - это то, что если вы сделаете свою программу python исполняемым файлом и запустите ее в cron, она запустится в вашем домашнем каталоге. Поэтому лучше использовать полностью определенный путь. Это определенно работает, но я все еще использую полностью определенные пути в любом скрипте, который могу вызвать из Python, потому что нет гарантии, что это будет применяться вне самой программы Python.
Я бы использовал os.chdir вот так:
os.chdir("/path/to/change/to")
Кстати, если вам нужно выяснить ваш текущий путь, используйте os.getcwd().
Подробнее здесь
Если вы используете относительно новую версию Python, вы также можете использовать диспетчер контекста, например Вот этот:
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
ОБНОВИТЬ
Если вы предпочитаете кататься самостоятельно:
import os
from contextlib import contextmanager
@contextmanager
def working_directory(directory):
owd = os.getcwd()
try:
os.chdir(directory)
yield directory
finally:
os.chdir(owd)
Хорошая общая идея. Здесь Рецепт Activestate без других зависимостей.
contextlib.contextmanager хорош. См. ответ на основе декоратораcdunn2001, который в идеале был бы сейчас принятым ответом.
Вот пример диспетчера контекста для изменения рабочего каталога. Это проще, чем упоминаемый в другом месте Версия ActiveState, но он выполняет свою работу.
cdimport 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)
Или попробуйте более лаконичный эквивалент (ниже), используя ContextManager.
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.
Если вам когда-нибудь понадобится узнать, из какого каталога вы изменили, вы можете просто добавить return self в конец __enter__. Таким образом, вы можете сделать with cd('foo') as cm: и получить доступ к предыдущему каталогу как cm.savedPath.
Обратите внимание, что есть случаи, когда возврат в старый каталог (тот, который хранится в «savedPath») невозможен. Например, если более привилегированный процесс выполняет менее привилегированный процесс, второй процесс наследует рабочий каталог первого процесса, даже в тех случаях, когда второй процесс не может войти в этот рабочий каталог со своими собственными возможностями.
Я получаю следующее предупреждающее сообщение: Attribute 'savedPath' defined outside __init__ [attribute-defined-outside-init]
Как уже указывалось другими, все вышеперечисленные решения изменяют только рабочий каталог текущего процесса. Это теряется, когда вы возвращаетесь в оболочку Unix. Если вы в отчаянии, вы может измените родительский каталог оболочки в Unix с помощью этого ужасного взлома:
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")
Далее в направлении, указанном Брайаном и основанном на ш (1.0.8+)
from sh import cd, ls
cd('/tmp')
print ls()
cd() легко написать с помощью генератора и декоратора.
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)
Затем каталог возвращается в исходное состояние даже после создания исключения:
os.chdir('/home')
with cd('/tmp'):
# ...
raise Exception("There's no place like /home.")
# Directory is now back to '/home'.
Также обратите внимание на эта потенциальная ошибка (чтобы забыть о try/finally).
Почему yield, а не return? Это должен быть генератор?
Прокомментируйте, пожалуйста, соотношение доходности и доходности!
@NicoBerrogorry, это генератор. См. Документы на contextlib.contextmanager. Это очень полезный шаблон в Python, который стоит изучить.
Я хотел бы наконец спросить об использовании. Мы знаем, что, наконец, всегда происходит после попытки, исключения или нет. Хотя это нормально, когда есть исключение, это также означает, что в любом случае вы вернетесь в предыдущий каталог, а это не то, что планировалось. Разве os.chdir (prevdir) не должен находиться под оператором else? Кроме того, мне интересно, почему python subprocess.call ("cd / path") на самом деле не работает ...
Почему в конце блока raise Exception стоит with?
@AndoJurai Я действительно думаю, что всегда следует возвращаться в предыдущий каталог. Таким образом, структура вашего кода соответствует структуре каталогов, и вам не нужно устанавливать cd('../'), о котором легко забыть.
Изменение текущего каталога процесса сценария тривиально. Я думаю, что на самом деле вопрос заключается в том, как изменить текущий каталог командного окна, из которого вызывается скрипт python, что очень сложно. Сценарий Bat в Windows или сценарий Bash в оболочке Bash может сделать это с помощью обычной команды cd, поскольку интерпретатором является сама оболочка. И в Windows, и в Linux Python - это программа, и никакая программа не может напрямую изменять родительскую среду. Однако сочетание простого сценария оболочки со сценарием Python, выполняющим большую часть сложных задач, может достичь желаемого результата. Например, чтобы создать расширенную команду cd с историей обхода для обратного / прямого / выбора повторного посещения, я написал относительно сложный сценарий Python, вызываемый простым сценарием летучей мыши. Список обхода сохраняется в файле с целевым каталогом в первой строке. Когда сценарий python возвращается, сценарий bat считывает первую строку файла и делает ее аргументом для cd. Полный сценарий летучей мыши (без комментариев для краткости):
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
Скрипт python dSup.py:
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)
Хотя это хороший ответ, OP выбрал ответ, в котором говорится, что он не об изменении CWD родительского процесса. Это устраняет любую возможную путаницу в том, что означает вопрос.
Toin Man - этот ответ был выбран до того, как я опубликовал свое предложение. Я думаю, что широкий диапазон ответов мог сбить с толку. cd в данном процессе (например, скрипт Python) настолько прост, что я не знаю, почему кто-то может спросить об этом.
Собственно этот ответ был выбран годы назад. Если бы это было неуместно, то с тех пор его вызывали бы много раз.
Я думаю, что путаница сохраняется. Совсем недавно вопрос «имитировать команду linux« cd »в python и сохранить изменение каталога после выхода из программы [дубликат]» был отклонен, поскольку здесь был дан ответ, но на самом деле этот вопрос не рассматривается в выбранном ответе. Мое предложение относится к Windows, но в Linux проблемы те же.
Если вы хотите выполнить что-то вроде опции «cd ..», просто введите:
os.chdir ("..")
это то же самое, что и в Windows cmd: cd .. Конечно, импорт ОС необходим (например, введите его как 1-ю строку вашего кода)
import os
abs_path = 'C://a/b/c'
rel_path = './folder'
os.chdir(abs_path)
os.chdir(rel_path)
Вы можете использовать оба с os.chdir (abs_path) или os.chdir (rel_path), нет необходимости вызывать os.getcwd () для использования относительного пути.
Работает хорошо. Можно использовать os.getcwd () для проверки текущего каталога как до, так и после изменения каталога.
Если вы используете Spyder и любите графический интерфейс, вы можете просто нажать кнопку папки в правом верхнем углу экрана и перемещаться по папкам / каталогам, которые вы хотите использовать в качестве текущего каталога. После этого вы можете перейти на вкладку проводника в окне в spyder IDE и увидеть все файлы / папки, которые там присутствуют. чтобы проверить текущий рабочий каталог перейдите в консоль IDE Spyder и просто введите
pwd
он напечатает тот же путь, который вы выбрали ранее.
Объекты Path в библиотеке дорожка предлагают для этой цели как диспетчер контекста, так и метод chdir:
from path import Path
with Path("somewhere"):
...
Path("somewhere").chdir()
Так в интерпретаторе
os.chdir(os.path.join(os.path.abspath(os.path.curdir),u'subfolder'))- или?