Como altero o diretório de trabalho no Python?


Respostas:


765

Você pode alterar o diretório de trabalho com:

import os

os.chdir(path)

Existem duas práticas recomendadas a serem seguidas ao usar esse método:

  1. Capture a exceção (WindowsError, OSError) no caminho inválido. Se a exceção for lançada, não execute operações recursivas, especialmente destrutivas. Eles irão operar no caminho antigo e não no novo.
  2. Retorne ao seu diretório antigo quando terminar. Isso pode ser feito de maneira segura contra exceções, envolvendo sua chamada chdir em um gerenciador de contexto, como Brian M. Hunt fez em sua resposta .

Alterar o diretório de trabalho atual em um subprocesso não altera o diretório de trabalho atual no processo pai. Isso também vale para o intérprete Python. Você não pode os.chdir()alterar o CWD do processo de chamada.


3
A resposta leve e baseada em decorador do cdunn2001 é a abordagem ideal para o Python moderno. A resposta acima demonstra o porquê. Nunca ligue para os.chdir()fora de um gerente de contexto, a menos que você pense que sabe o que está fazendo. ( Você provavelmente não. )
Cecil Curry

6
Essa é a maneira mais fácil em um shell interativo, eu acho. Observe que no Windows, você precisa usar barras, comoos.chdir("C:/path/to/location")
Josiah

A única coisa a ter em atenção é que, se você tornar seu programa python um executável e executá-lo no cron, ele será iniciado no diretório inicial. Portanto, é melhor usar um caminho completo. Isso definitivamente funciona, mas ainda uso caminhos totalmente qualificados em qualquer script que eu possa chamar do Python, porque não há garantia de que isso se aplique fora do próprio programa Python.
precisa saber é o seguinte

310

Aqui está um exemplo de um gerenciador de contexto para alterar o diretório de trabalho. É mais simples que uma versão do ActiveState referida em outro lugar, mas isso faz o trabalho.

Gerenciador de Contexto: 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 tente o equivalente mais conciso (abaixo) , usando o ContextManager .

Exemplo

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.

Se você precisar saber em qual diretório você mudou, basta adicionar return selfno final de __enter__. Dessa forma, você pode fazer with cd('foo') as cm:e acessar o diretório anterior comocm.savedPath
Sam F

Observe que há casos em que não é possível retornar ao diretório antigo (aquele armazenado em "savedPath"). Por exemplo, se um processo mais privilegiado executa um processo menos privilegiado, o segundo processo herda o diretório de trabalho dos primeiros processos, mesmo naqueles casos em que o segundo processo não pode entrar nesse diretório de trabalho com seus próprios recursos.
Kai Petzke 11/02/19

140

Eu usaria os.chdirassim:

os.chdir("/path/to/change/to")

A propósito, se você precisar descobrir seu caminho atual, use os.getcwd() .

Mais aqui


117

cd() é fácil escrever usando um gerador e um decorador.

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)

Em seguida, o diretório é revertido mesmo depois que uma exceção é lançada:

os.chdir('/home')

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

3
Além disso, observe esse erro potencial (para esquecer o try/finally).
cdunn2001

5
Brilho! Se o comentário introdutório da resposta aceita fosse injetado nessa resposta, isso seria incomensuravelmente ideal. Ainda assim, a implementação concisa e Pythonically segura desta resposta garante todos os votos positivos que tenho para dar.
Cecil Curry

3
Por que yielde não return? Isso deveria ser um gerador?
EKons 5/08/16

Por favor, comente a relevância do rendimento versus retorno!
NicoBerrogorry

1
@NicoBerrogorry, é um gerador. Veja os documentos em contextlib.contextmanager . Este é um padrão muito útil em Python, que vale a pena aprender.
cdunn2001

25

Se você estiver usando uma versão relativamente nova do Python, também poderá usar um gerenciador de contexto, como este :

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

ATUALIZAR

Se você preferir lançar seu próprio:

import os
from contextlib import contextmanager

@contextmanager
def working_directory(directory):
    owd = os.getcwd()
    try:
        os.chdir(directory)
        yield directory
    finally:
        os.chdir(owd)

1
Boa ideia geral. Aqui está uma receita do Activestate sem outras dependências.
Cfi

4
Dependências são ruins. O contextlib.contextmanagerdecorador embutido do Python é bom. Veja cdunn2001 's resposta à base de decorador , que seria idealmente a resposta aceita agora.
Cecil Curry

14

Como já apontado por outros, todas as soluções acima alteram apenas o diretório de trabalho do processo atual. Isso é perdido quando você volta para o shell Unix. Se estiver desesperado, você pode alterar o diretório do shell pai no Unix com este hack horrível:

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")

4
Hack insano e frágil recebe votos obrigatórios. Ninguém deve fazer isso, principalmente com isso "e se o usuário digitar enquanto executa ...", ressalte. Ainda assim, me excita a barba rebelde em mim ao ver que mudar o CWD principal é uma espécie de, mas não realmente viável. Upvotes! Upvotes para todos!
Cecil Curry


11

os.chdir()é a versão Pythonic de cd.


8
import os

abs_path = 'C://a/b/c'
rel_path = './folder'

os.chdir(abs_path)
os.chdir(rel_path)

Você pode usar os.chdir (abs_path) ou os.chdir (rel_path), não há necessidade de chamar os.getcwd () para usar um caminho relativo.


Funciona bem. Pode-se usar os.getcwd () para verificar o diretório atual, tanto antes como depois de mudar o diretório ..
vinsinraw

6

Mais adiante, na direção apontada por Brian e baseada em sh (1.0.8+)

from sh import cd, ls

cd('/tmp')
print ls()

3

Se você deseja executar algo como a opção "cd ..", digite:

os.chdir ("..")

é o mesmo que no Windows cmd: cd. É claro que o import os é necessário (por exemplo, digite-o como a primeira linha do seu código)


0

Se você usa o Spyder e adora a GUI, pode simplesmente clicar no botão de pasta no canto superior direito da tela e navegar pelas pastas / diretórios que deseja como diretório atual. Depois disso, você pode ir para a guia explorador de arquivos da janela no spyder IDE e pode ver todos os arquivos / pastas presentes lá. Para verificar seu diretório de trabalho atual, acesse o console do Spyder IDE e digite

pwd

ele imprimirá o mesmo caminho que você selecionou anteriormente.


-1

Alterar o diretório atual do processo de script é trivial. Eu acho que a questão é realmente como alterar o diretório atual da janela de comando a partir da qual um script python é chamado, o que é muito difícil. Um script Bat no Windows ou um script Bash em um shell Bash pode fazer isso com um comando cd comum, porque o próprio shell é o intérprete. No Windows e no Linux, Python é um programa e nenhum programa pode alterar diretamente o ambiente de seus pais. No entanto, a combinação de um script de shell simples com um script Python fazendo a maioria das coisas difíceis pode alcançar o resultado desejado. Por exemplo, para criar um comando cd estendido com histórico de travessia para revisar para trás / para frente / selecionar, escrevi um script Python relativamente complexo, invocado por um simples script bat. A lista de travessia é armazenada em um arquivo, com o diretório de destino na primeira linha. Quando o script python retorna, o script bat lê a primeira linha do arquivo e o torna o argumento para cd. O script bastão completo (menos comentários por brevidade) é:

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

O script 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)

Embora seja uma boa resposta, o OP selecionou uma resposta que diz que não se trata de alterar o CWD do processo pai. Isso esclarece qualquer possível confusão sobre o que a pergunta significa.
the Tin Man

Para Tin Man - essa resposta foi selecionada antes de eu postar minha sugestão. Eu acho que as respostas abrangentes podem ter sido confusas. O cd dentro de um determinado processo (ou seja, um script python) é tão simples que não sei por que alguém perguntaria.
David McCracken

1
Na verdade, essa resposta foi selecionada anos atrás. Se não fosse apropriado, teria sido chamado várias vezes desde então.
the Tin Man

Eu acho que essa confusão permanece. Mais recentemente, a questão "simulando o comando" cd "do linux em python e persistindo a alteração do diretório após a saída do programa [duplicado]" foi descartada como tendo sido respondida aqui, mas, na verdade, essa questão não é abordada pela resposta selecionada. Minha sugestão é para o Windows, mas os problemas são os mesmos no Linux.
David McCracken
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.