News for hackers. Stuff that matters.
Re:Unix Recovery Legend (1986) by teddyh on Wednesday September 02, 2015 @01:28PM (#10160720)
"cd" is always a shell built-in. It is not even possible to have a /bin/cd binary which does what "cd" does.
Re:Unix Recovery Legend (1986) by acveilleux on Wednesday September 02, 2015 @04:09PM (#10161612)
Good point. I'd never really thought about that, just noticed that all shells seemed to include id...
Re:Unix Recovery Legend (1986) by GTP on Wednesday September 02, 2015 @01:37PM (#10160791)
Why is impossible? Maybe I've understood why it is always built in: without it the shell wouldn't be able to navigate through the directory tree to find the executables of the commands. But once the shell has it, I think it would be rendundant (so nobody does it) but still possible to have a /bin/cd that navigates directories.
Re:Unix Recovery Legend (1986) by duaneb on Wednesday September 02, 2015 @01:39PM (#10160807)
You can't change the environment of the parent process, including CWD. `/bin/cd` would either be another process like all executables run by the shell, and not work, or special cased, at which point why make it an executable at all?
Re:Unix Recovery Legend (1986) by JoshTriplett on Thursday September 03, 2015 @12:30AM (#10163346)
I can think of one way to write "cd" out-of-process from the shell: exec /bin/cd /some/path, which does chdir("/some/path") and execs your shell. You'd lose your history and similar state, but if you had a shell that didn't even put cd in-process, it probably doesn't have history either.

Sample:

    /tmp$ exec /tmp/cd /bin
    /bin$ exec /tmp/cd /home
    /home$ exec /tmp/cd /usr
    /usr$ 
Sample code:

    #include <err.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    int main(int argc, char *argv[])
    {
        char *shell;
        if (argc != 2)
            errx(1, "Usage: exec cd /some/path");
        if (chdir(argv[1]) == -1)
            err(1, "chdir");
        shell = getenv("SHELL");
        if (!shell || !*shell)
            shell = "/bin/sh";
        execl(shell, shell, NULL);
        err(1, "exec");
    }
Re:Unix Recovery Legend (1986) by duaneb on Thursday September 03, 2015 @12:44AM (#10163384)
Hah, hadn't thought of that. Kind of CPS for processes. I'm not sure what that would gain you, though, as you'd have to either a) write both the cd and the user of the cd, and there are less awkward ways to do that than exec'ing, or b) you'd have to pass something ELSE to exec to return control after cd finishes.

This seems a little awkward and I'm not sure what is being proven. :P

Re:Unix Recovery Legend (1986) by aardvark179 on Thursday September 03, 2015 @03:39AM (#10163738)
It's how very early version of Unix effectively did stuff, they exceed a program, and when it exited they exceed the shel again.

When they introduced something like the fork/exec model we now have they discovered cd didn't work any more and had to write it as a built in.

Now, for bonus points, work out how goto worked when it wasn't a built in.

Re:Unix Recovery Legend (1986) by JoshTriplett on Thursday September 03, 2015 @12:01PM (#10165669)
> It's how very early version of Unix effectively did stuff, they exceed a program, and when it exited they exceed the shel again.

Makes sense, since those systems might not have enough memory to run the shell and another program at the same time.

Re:Unix Recovery Legend (1986) by acveilleux on Thursday September 03, 2015 @02:24PM (#10166682)
This would cause an eventual exhaustion of process table entry / pid and/or addressable memory as the previous shell is left in the background.
Re:Unix Recovery Legend (1986) by cperciva on Thursday September 03, 2015 @02:47PM (#10166800)
There's nothing being left in the background. It's one process which is calling exec repeatedly; no forking going on.
Re:Unix Recovery Legend (1986) by schoen on Wednesday September 02, 2015 @01:47PM (#10160867)
The parent comment's explanation is exactly right (although I might not use "CWD" in this context, because a reader might mistakenly think the working directory is determined by an environment variable). As an example, try

python -c 'import os; os.chdir("/")'

Notice that the working directory of your shell is unaffected. :-)

Or:

bash -c 'export foo=bar'; echo $foo

Re:Unix Recovery Legend (1986) by Someone1234 on Wednesday September 02, 2015 @03:40PM (#10161464)
Those examples are trying to change the directory on the shell's child process, not on the shell itself.

That being said, aside from a kernel patch there is definitely no official way of doing it. This is the hacky way:

http://stackoverflow.com/questions/2375003/how-do-i-set-the-...

Re:Unix Recovery Legend (1986) by schoen on Wednesday September 02, 2015 @05:31PM (#10162012)
I meant for my examples just to illustrate that a child process can't change the working directory or environment of the parent process.
Re:Unix Recovery Legend (1986) by rleigh on Wednesday September 02, 2015 @04:49PM (#10161815)
It's impossible because it simply calls chdir(2). The "current directory" is a property of a process; having it built-in means it changes the directory of the current process. If it was a separate executable, you'd change the directory in a separate child process for that executable, and the current directory of the shell would be unchanged, making it entirely useless.