10

I want to write some code to allow me switching to some directories that I usually go to. Say this program is mycd, and /a/very/long/path/name is the directory that I want to go to.

So I can simply type mycd 2 instead of cd /a/very/long/path/name. Here I assume mycd knows 2 refers to that /a/very/long/path/name . There might also be mycd 1, mycd 3, ... etc.

The problem is I have to write mycd as a shell script and type . mycd 2 to do the desired thing because otherwise the script just get executed in a child script which doesn't change anything about the parent shell that I actually care about.

My question is:

  • can I do it without using source? because . mycd assumes mycd has to be a shell script and this might also introduce some functions that I don't want.

  • can I implement it in some other programming languages?

1
  • On a practical note: Does adding some symlinks to e.g. home suffice?
    – Simon
    Commented Apr 13, 2022 at 12:50

3 Answers 3

24

make mycd a function so the cd command executes in your current shell. Save it in your ~/.bashrc file.

function mycd {
    if (( $# == 0 )); then
        echo "usage: $FUNCNAME [1|2|3|...]"
        return
    fi
    case $1 in
        1) cd /tmp ;;
        2) cd /a/very/long/path/name ;;
        3) cd /some/where/else ;;
        *) echo "unknown parameter" ;;
    esac
}
2
  • Thank you, haven't thought about using functions, and this just enables everything: I can now let mycd pass $@ to any program I like.
    – Javran
    Commented Feb 9, 2014 at 17:48
  • Make sure you quote "$@" so that any arguments containing whitespace are handled correctly. Commented Feb 10, 2014 at 0:09
9

You cannot change a shell's current directory from another process. Only the process itself can change its own current directory. This also holds for some other characteristics such as environment variables and file descriptors.

It is actually possible to affect another process's current directory by causing it to execute a chdir system call via the ptrace system call, which is what lets debuggers work. However, if the process maintains some internal data structures that have to be consistent with the actual current directory, the program is likely to crash. For a shell, this approach has no chance to work.

You need to arrange for your code to be executed by the shell itself. The normal way of proceeding would be to make it a shell function and store it in your ~/.bashrc. If this is not possible, for example because it's code that you want to distribute, write a shell source file that contains the function definition, and tell people to have their interactive shell read your file with the . command.

2
  • 1
    There is actually a chance to make it "work", but it is nontrivial, error-prone and should be avoided at all costs. To show that it is actually "possible", consider this shell script where the parent is Bash: ws=$1; gdb -p $(ps h -o ppid -p $$) -ex "call chdir(\"$wd\")" -ex "call set_working_directory(\"$wd\")" -ex detach -ex q -batch. Execute as braindead-cd-parent /. You will see that pwd returns / and so does ls, etc. behave. But the prompt (PS1) is still unchanged, people's eyes are hurt, etc. So do not do this even if it is possible.
    – Lekensteyn
    Commented Feb 9, 2014 at 15:58
  • 1
    @Lekensteyn That's the ptrace method I mention. It works well on programs that don't care much about their current directory. In a shell, a lot of things (PWD variable, prompt, etc.) are going to become wrong, and the shell may crash or otherwise misbehave. Commented Feb 9, 2014 at 16:03
5

As you pointed out yourself, shell scripts are always executed in a subshell, which cannot influence its parent shell.

You can however...

  • use an alias:
    alias mycd2='cd /a/very/long/path/name'
  • have your script1 output a valid shell command ...

    #!/bin/bash
    if [ "x$1" = "x2" ]
    then
        echo "cd /a/very/long/path/name"
    fi
    

    ... and execute its output: $(mycd 2)

1: You'll probably want to use a case statement rather than the if condition in the example.

1
  • 5
    An alias is passable. A script is the same problem he already has. This question screams shell function.
    – Ricky
    Commented Feb 8, 2014 at 21:49

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .