简体   繁体   中英

python3 chdir() does not seem to work

As an newcomer to python I figured I'd write a little python3 script to help me switch directories on the command line (ubuntu trusty). Unfortunately os.chdir() does not seems to work. I've tried tinkering with it in various ways such as placing quotes around the path, removing the leading slash (which obviously doesn't work) and even just hardcoding it, but I can't get it to work - can anybody tell me what I'm missing here?

The call to chdir() happens towards the end - you can see the code in github too

#!/usr/bin/env python3
# @python3
# @author sabot <sabot@inuits.eu>
"""Switch directories without wearing out your slash key"""
import sys
import os
import json
import click

__VERSION__ = '0.0.1'

# 3 params are needed for click callback
def show_version(ctx, param, value):
    """Print version information and exit."""
    if not value:
        return
    click.echo('Goto %s' % __VERSION__)
    ctx.exit() # quit the program

def add_entry(dictionary, filepath, path, alias):
    """Add a new path alias."""
    print("Adding alias {} for path {} ".format(alias,path))
    dictionary[alias] = path

    try:
        jsondata = json.dumps(dictionary, sort_keys=True)
        fd = open(filepath, 'w')
        fd.write(jsondata)
        fd.close()
    except Exception as e:
        print('Error writing to dictionary file: ', str(e))
        pass

def get_entries(filename):
    """Get the alias entries in json."""
    returndata = {}
    if os.path.exists(filename) and os.path.getsize(filename) > 0:
        try:
            fd = open(filename, 'r')
            entries = fd.read()
            fd.close()
            returndata = json.loads(entries)

        except Exception as e:
            print('Error reading dictionary file: ', str(e))
            pass
    else:
        print('Dictionary file not found or empty- spawning new one in', filename)
        newfile = open(filename,'w')
        newfile.write('')
        newfile.close()

    return returndata

@click.command()
@click.option('--version', '-v', is_flag=True, is_eager=True,
              help='Print version information and exit.', expose_value=False,
              callback=show_version)
@click.option('--add', '-a', help="Add a new path alias")
@click.option('--target', '-t', help="Alias target path instead of the current directory")
@click.argument('alias', default='currentdir')
@click.pass_context
def goto(ctx, add, alias, target):
    '''Go to any directory in your filesystem''' 

    # load dictionary
    filepath = os.path.join(os.getenv('HOME'), '.g2dict')
    dictionary = get_entries(filepath)

    # add a path alias to the dictionary
    if add:
        if target: # don't use current dir as target
            if not os.path.exists(target):
                print('Target path not found!')
                ctx.exit()
            else:
                add_entry(dictionary, filepath, target, add)
        else: # use current dir as target
            current_dir = os.getcwd()
            add_entry(dictionary, filepath, current_dir, add)

    elif alias != 'currentdir':
        if alias in dictionary:
            entry = dictionary[alias]
            print('jumping to',entry)
            os.chdir(entry)
        elif alias == 'hell':
            print("Could not locate C:\Documents and settings")
        else:
            print("Alias not found in dictionary - did you forget to add it?")

if __name__ == '__main__':
    goto()

The problem is not with Python, the problem is that what you're trying to do is impossible.

When you start a Python interpreter (script or interactive REPL), you do so from your "shell" (Bash etc.). The shell has some working directory, and it launches Python in the same one. When Python changes its own working directory, it does not affect the parent shell, nor do changes in the working directory of the shell affect Python after it has started.

If you want to write a program which changes the directory in your shell, you should define a function in your shell itself. That function could invoke Python to determine the directory to change to, eg the shell function could be simply cd $(~/myscript.py) if myscript.py prints the directory it wants to switch to.

Here's Python 3 version of @ephemient's C solution :

#!/usr/bin/env python3
"""Change parent working directory."""
#XXX DIRTY HACK, DO NOT DO IT
import os
import sys
from subprocess import Popen, PIPE, DEVNULL, STDOUT

gdb_cmd = 'call chdir("{dir}")\ndetach\nquit\n'.format(dir=sys.argv[1])
with Popen(["gdb", "-p", str(os.getppid()), '-q'],
           stdin=PIPE, stdout=DEVNULL, stderr=STDOUT) as p:
    p.communicate(os.fsencode(gdb_cmd))
sys.exit(p.wait())

Example:

# python3 cd.py /usr/lib && python3 -c 'import os; print(os.getcwd())'

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM