Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

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?

share|improve this question

3 Answers 3

up vote 19 down vote accepted

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
}
share|improve this answer
    
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 Feb 9 at 17:48
    
Make sure you quote "$@" so that any arguments containing whitespace are handled correctly. –  glenn jackman Feb 10 at 0:09

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.

share|improve this answer
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 Feb 9 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. –  Gilles Feb 9 at 16:03

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.

share|improve this answer
5  
An alias is passable. A script is the same problem he already has. This question screams shell function. –  Ricky Beam Feb 8 at 21:49

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.