I've always wondered why cd
isn't a program, but never managed to find the answer.
Anyone know why this is the case?
I've always wondered why cd
isn't a program, but never managed to find the answer.
Anyone know why this is the case?
The cd
command modifies the "current working directory", right?
"current working directory" is a property that is unique to each process.
So, if cd
was a program it would work like this:
cd foo
cd
process startscd
process changes the directory for the cd processcd
process exitscd
was a program it would work like this" should be "when cd
is used in its external program implementation, it does work like this".
– jlliagre
May 19 '12 at 12:21
cd
command in dash
: https://git.kernel.org/pub/scm/utils/dash/dash.git/tree/src/cd.c
– Daniel F
Oct 19 '23 at 15:44
cd
in addition to being a shell builtin, is actually also a program on POSIX compliant OSes. They must provide independent executables for regular utilities, like cd
. This is for example the case with Solaris, AIX, HP-UX and OS X.
Obviously, a builtin cd
is still mandatory as its external implementation doesn't change the current shell directory. However, the latter can still be useful. Here is an example showing how POSIX envision how this cd
command could be used:
find . -type d -exec cd {} \;
On a POSIX system, this oneliner will report an error message for all directories you aren't allowed to cd
in. On most Gnu/Linux distributions, it fails with that error message though:
find: `cd': No such file or directory
And here is the answer to your question, "Why is cd not a program?" by one of the original Unix co-author. On a very early Unix implementation, cd
(spelled chdir
at that time) was an external program. It just stopped working unexpectedly after fork
was first implemented.
Quoting Dennis Ritchie:
In the midst of our jubilation, it was discovered that the chdir (change current directory) command had stopped working. There was much reading of code and anxious introspection about how the addition of fork could have broken the chdir call. Finally the truth dawned: in the old system chdir was an ordinary command; it adjusted the current directory of the (unique) process attached to the terminal. Under the new system, the chdir command correctly changed the current directory of the process created to execute it, but this process promptly terminated and had no effect whatsoever on its parent shell! It was necessary to make chdir a special command, executed internally within the shell. It turns out that several command-like functions have the same property, for example login.
Source: Dennis M. Ritchie, “The Evolution of the Unix Time-sharing System”, AT&T Bell Laboratories Technical Journal 63(6), Part 2, Oct. 1984, pp.1577–93
Unix Version 1 (March 1971) chdir manual page states:
Because a new process is created to execute each command, chdir would be ineffective if it were written as a normal command. It is therefore recognized and executed by the Shell.
cd
as builtin command and actually calls that external command?
– Nils
May 16 '12 at 21:06
cd
is a "regular built-in utility", which "shall be implemented in a manner so that they can be accessed via the exec family of functions [...] and can be invoked directly by those standard utilities that require it (env
, find
, nice
, nohup
, time
, xargs
)". Yet the spec for cd
itself says that "if it is called in a subshell or separate utility execution environment, [...] it does not affect the working directory of the caller's environment."
– Ilmari Karonen
May 16 '12 at 21:37
cd
executable, but that it shall do nothing (except possibly emit error messages if called with the wrong arguments). Weird.
– Ilmari Karonen
May 16 '12 at 21:39
builtin echo ${0##*/} | tr \[:upper:] \[:lower:]
${1+"$@"}` so the only thing it does is act as an alias to execute the builtin command
/usr/bin/cd
and cd
are completely different things.
– Kaz
May 17 '12 at 05:14
cd
must exist. Bizarre.
– Warren Young
May 17 '12 at 05:42
chdir
has a hidden implicit argument: the identity of the calling process, on whose current working directory variable it operates. This means that a chdir in process A and a chdir in process B are not the same operation (even if they are called with the same absolute path). Think of a database transaction. Is a $100 deposit into my bank account the same operation as a $100 deposit into your bank account? If so, you should not mind if the bank mixes them up.
– Kaz
May 18 '12 at 06:13
cd
makes sense, if you want to check, if you are able to execute the built-in cd
successfully. Great - this is just what I currently need for a script of mine...
– Nils
May 18 '12 at 19:52
cd
! The page you link says "The utilities named in Regular Built-In Utilities [cd
is one of them] are frequently provided in built-in form". The cd
page says "Since cd affects the current shell execution environment, it is always provided as a shell regular built-in". Why do you say they must exist as an external program?
– Totor
Mar 21 '13 at 23:24
find . -type d -exec cd {} \;
do anything? I'd think not, beyond creating a short-lived child process which changes directory and then exits. In particular, one could not do anything in that find
command, or anywhere after it, from within that directory. This is the case with all such "use cases" POSIX envisions, which is why no volunteer wastes time implementing it. If you are paid, however, for work in a committee, I can imagine that people don't mind spending half an hour on writing a script that does nothing anyway for a use case which is senseless.
– Peter - Reinstate Monica
Nov 20 '18 at 15:50
find
command that make use of this failing cd
command and thus act depending on whether you can cd
to a directory or not.
– jlliagre
Nov 21 '18 at 21:58
From the Bash introduction (What is a shell?):
Shells also provide a small set of built-in commands (builtins) implementing functionality impossible or inconvenient to obtain via separate utilities. For example,
cd
,break
,continue
, andexec
) cannot be implemented outside of the shell because they directly manipulate the shell itself. Thehistory
,getopts
,kill
, orpwd
builtins, among others, could be implemented in separate utilities, but they are more convenient to use as builtin commands. All of the shell builtins are described in subsequent sections.
For April Fool's this year, I wrote a standalone version of cd
.
No one got the joke. Sigh.
Anyone who isn't sure that cd
must be built into the shell should download it, build it, and try it.
Read its man page, too. :)
/bin/cd
. If you want to take my code and make that your own personal quest, you're welcome to do so.
– Warren Young
Nov 20 '18 at 16:01
The cd
command in shell cannot be a separate process because in Unix there is no mechanism to change the current working directory of a different process (not even the parent process).
If cd
was a different process then it would have to change the current working directory of its parent (shell) which is not possible in Unix.
Instead cd
is a special built in command. The shell calls functions like chdir()
and fchdir()
changing its own current working directory.
Note : the kernel stores the inode number of the current working directory for every process. The child process inherits it's cwd
from its parent.
cd is a shell built-in command. As easy as is. The man cd says it all. the cd command changes the working directory for all interpreters and (in a threaded environment) all threads.
cd
is built-in. I would suggest you read the highest ranked answers and consider how your answer can be improved.
– Thorbjørn Ravn Andersen
May 17 '12 at 16:22
I think one thing missing in people answer is that current directory is a environment variable that each program can change. If you use 'export' command to see your current environment variables list, you will have:
declare -x PWD="/home/erfan"
in your results. Thus by 'cd' command we just want to modify this internal variable. I think if we try, we can chage the PWD variable of any pty in shell, of course. Like:
cder #change current PTY $PWD variable
But I think there s no need in normal cases. In another word, we take help from bash(or any shell) to modify its internal variable defined.
..
path, not the path you started it from: #include <stdlib.h>
int main(void) { chdir(".."); puts(getenv("PWD")); }
(C shells expose the CWD as %cwd instead, by the way.)
– Warren Young
May 23 '12 at 16:59
#include <unistd.h>
int main(void) { char ac[99]; setenv("PWD", "/", 1); puts(getcwd(ac, sizeof(ac))); }
It will show the directory you started the program from, not /
.
– Warren Young
May 25 '12 at 08:02
$PWD
only has meaning to the Bourne shell. It is just a way for the shell to communicate something it knows to shell scripts so they dont have to call pwd
to find it. Any standalone program depending on the value of $PWD
will be unreliable.
– Warren Young
May 25 '12 at 09:26
cd
command was a separate program. The shell handled it specially in that it did notfork
, justexec
. And whencd
was done, it would execsh
. I don't know if this is a true story. – camh May 17 '12 at 02:18chdir
syscall. sources: v1 v5 v7 (first version with Bourne shell) – Mikel May 17 '12 at 05:33cd
that I had read. I was clearly wrong about aspect of it, now that @jlliagre has filled in the details. – camh May 17 '12 at 08:23