102

One of the tutorials I've been following briefly stated that cd . has no use. When trying to replicate issue shown by OP in Symbolic link recursion - what makes it “reset”?, I also tried cd ., which showed the same effect OP described (growing $PWD variable), which can be countered with cd -P.

This makes me wonder, is there any case where one does in fact would want to use cd . ?

  • 20
    I have a custom .zshrc that runs various checks on the directory when switching directory, for example one of the check is to automatically activate/deactivate a matching virtualenv when moving directories. Occasionally, I might start a new shell or whatever, and those checks don't run, and I usually use cd . to trigger those checks because it's short and simple. Though I think you intended the question to be for a vanilla environment. – Lie Ryan Jan 22 '19 at 06:46
  • @LieRyan No, I didn't really intend it to be restricted to vanilla environment only. The only concert here is whether or not cd . is useful, and whether there's more to it than just face-value navigation to same directory. You can convert your comment into an answer, as it may be useful to others. – Sergiy Kolodyazhnyy Jan 22 '19 at 07:21
  • 29
    Besides the (obvious) effect on $PWD, cd . also changes $OLDPWD to the current directory. I have (currently) no idea why this might be useful, but for the sake of completeness… – Andreas Wiese Jan 22 '19 at 22:44
  • 5
    I don't think I've ever needed cd ., though seeing the answers below, I might in the future, but I have on occasion used pushd . when I wanted to be able to popd back to this directory later. e.g. when running a build script that does configure, cd output... and make, and when it's done I'll want to go back to the original directory. Rather than maintaining my own copy of the buildscript that's different than what everyone else expects, I just run it as pushd .; ./BuildScriptName.sh; popd, and this also gives me the freedom to not popd sometimes, and then popd later instead. – 3D1T0R Jan 23 '19 at 00:47
  • 5
    Not to mention of course that '.' and '..' are not implemented in the cd command itself, so no-one set out to make that specific feature, it's just a combination of things that serves no real purpose. – David S Jan 23 '19 at 14:48
  • cd is a shell built-in command. What shell do you ask about? – enkryptor Jan 24 '19 at 15:32
  • @enkryptor It is a built-in in most shells, but on some systems it's also available as /bin/cd and IIRC is required by POSIX. There's no specific restriction to which shell this question applies, and I as shown in linked question and some of the already existing answers - behavior of cd . can vary by shell, so addressing multiple cases is necessary. – Sergiy Kolodyazhnyy Jan 25 '19 at 00:07
  • @SergiyKolodyazhnyy: Re: "on some systems it's also available as /bin/cd": Wait, how does that work? Are there Unixlike systems where an executable program is allowed to mess with the parent process's execution environment? – ruakh Jan 25 '19 at 06:56
  • 1
    @ruakh Nope, external programs should not affect shell execution environment. It's mostly for POSIX compliance which requires some of the utilities to exist outside of the shell, and evaluating exit status of external commands. You can read about the purpose of /bin/cd here https://unix.stackexchange.com/q/50058/85039 – Sergiy Kolodyazhnyy Jan 25 '19 at 07:18
  • @SergiyKolodyazhnyy: Fascinating; thanks for the link! – ruakh Jan 25 '19 at 07:24
  • @ruakh It's worth noting, though, that in original Unix there was external chdir that did affect shell's execution environment, according to Dennis Ritchie's article The Evolution of the Unix Time-sharing System*. According to it, when they realized that it stopped working with newly added fork() syscall, they decided to make it a shell built-in, or so I understand. Eventually chdir was dropped, apparently in Version 7 (source) – Sergiy Kolodyazhnyy Jan 25 '19 at 07:35
  • 1
    Esoteric perhaps, but I use the fish shell with the git branch plugin. If I checkout a new branch in a different terminal window, then I run cd . to cause the plugin to display the correct branch. – Jared Smith Jan 26 '19 at 00:33
  • I use cd -P . almost every day, does that count? When you've cd'ed somewhere through symlinks, that can be very useful to figure out where you really are. Is that relevant or are you only asking about cd . with no flags? – terdon Jan 28 '19 at 11:46

10 Answers10

156

I think this is overthinking the problem. cd . may not be something that one would manually run in the usual course of things, but it definitely is something that can come up in programmatic execution (think of any situation where you might cd to the directory containing a file, whose path is supplied by the user). Therefore, it doesn't have to have some specific use: as long as it fulfills the usual semantics of cd <some-path>, it is useful.

Olorin
  • 4,656
  • 12
    Agreed, . should be treated as a valid path specified by cd syntax just fine. – Sergiy Kolodyazhnyy Jan 22 '19 at 04:52
  • 18
    You can add the following example: Loops like while IFS= read Dir; do cd "$Dir"; do_something; done < <(find . -type d). During its course, find produces . as path, so that the command cd "$Dir" expands to cd .. So, in scripts, it is perfectly useful. – rexkogitans Jan 22 '19 at 09:43
  • 1
    @rexkogitans your illustration is clear but the code would fail on its second iteration. You would need to put the cd and subsequent code in a subshell so that the relative directory path remained relative to the starting point rather than to the previous iteration. – Chris Davies Jan 22 '19 at 11:39
  • @roaima Feel free to add cd - to do_something – rexkogitans Jan 22 '19 at 11:46
  • 5
    For example, a script actually runs cd ${path_to_directory}, but at some point it turns out the directory is the current directory, and path_to_directory = . so you would need cd . to work just in case. – Demis Jan 23 '19 at 07:46
  • 5
    In other words, its utility is in the fact that it makes extra code (if checks and else clauses, any kind of special casing) unnecessary. – jpmc26 Jan 24 '19 at 18:27
  • 2
    So it's useful in the sense that x+0 or x*1 are useful - the specific operation isn't useful per se, but it means that you can handle 0 and 1 the same as any other value, without having to treat them as a special case. – Michael Kay Jan 27 '19 at 23:29
  • @user32929 that's kinda the opposite. The axioms defining operations like addition or multiplication typically include 0 and 1 within them, since those are the respective identities. Here, though, it just follows from the definition of . in paths and what cd is supposed to do with paths. – Olorin Jan 28 '19 at 01:43
127

The path of the directory could have changed since the last command was executed, and without cd . the bash and ksh93 shells will rely on the logical working directory described in the post linked in the question, so calling cd . which makes the shell issue the getcwd() syscall will ensure your current path is still valid.

Steps to reproduce in bash:

  1. In a terminal tab issue mkdir ./dir_no_1; cd ./dir_no_1
  2. In a different terminal tab issue mv dir_no_1 dir_no_2
  3. In the first terminal tab issue echo $PWD and pwd. Notice that the directory has been externally renamed; the shell's environment has not been updated.
  4. Issue cd .; pwd; echo $PWD. Notice the value has been updated.

ksh93, however, does not update the environment information, so cd . in ksh93 may in fact be useless. In /bin/dash on Ubuntu and other Debian-based systems, cd . returns dash: 3: cd: can't cd to . error, however cd -P . works (unlike in ksh93).

psmears
  • 465
  • 3
  • 8
  • 22
    Good to know: I'll add that to my list of useless informations. ^^) – jayooin Jan 22 '19 at 06:39
  • 12
    @jayooin Glad I could contribute to the list ;) – Sergiy Kolodyazhnyy Jan 22 '19 at 07:53
  • 8
    I think you can do mv ../dir_no_1 ../dir_no_2 in the same terminal/bash. – ctrl-alt-delor Jan 22 '19 at 09:00
  • 3
    @ctrl-alt-delor Confirmed, works :) – Sergiy Kolodyazhnyy Jan 22 '19 at 09:12
  • It's also possible that pwd might be a shell builtin that bypasses the syscall to getcwd() and is basically an alias for echo $PWD - see https://unix.stackexchange.com/questions/145479/strange-difference-between-pwd-and-bin-pwd. I can't test that there's a difference since my shells use the "real" pwd, but you might want to explicitly specify /bin/pwd just in case. Shells sure are fun, eh? – ymbirtt Jan 22 '19 at 09:44
  • 1
    @ymbirtt In most shells, pwd is in fact a built in, however invoking /bin/pwd has no effect on shell's environment - external utilities in general don't affect the shell environment. The reason why /bin/cd and /bin/pwd exist is for POSIX conformance, among other things. There's a good discussion about external cd some of which probably applies to /bin/pwd as well – Sergiy Kolodyazhnyy Jan 22 '19 at 09:52
  • Thank you for saving me writing an answer... – Harper - Reinstate Monica Jan 22 '19 at 16:36
  • Common reason this happens to me: I have a tmux session open from a place where I run various administrative commands, but the deployment process for new code checks out the code in a temporary location and then moves it over so as to make the process atomic. cd . then ensures that I'm in the correct most-recent deployed version of the code. – Xiong Chiamiov Jan 26 '19 at 17:54
55

Another use case of cd . would be when the directory you currently are in has been deleted and then made again. Consider trying the following -

  1. Create a directory temp
  2. cd temp and then do an ls
  3. Open another terminal and delete and then recreate that directory temp
  4. Back from the first terminal, try doing an ls. This would result in an error - ls: cannot open directory .: Stale file handle
  5. cd . and then doing an ls works fine
  • 3
    This doesn't always work. In dash, for example, you'll get: cd: can't cd to . Now that I look at it, this is already mentioned in Sergiy's answer (moving, deleting/recreating - essentially the same: the directory you're in is no longer what was in the original path) – Olorin Jan 22 '19 at 07:16
  • 12
    I use this a lot testing remote deploys. The directory I'm in will be deleted then recreated by some automation and I'll need to issue cd . to move to the new directory with the same name. – HP Williams Jan 22 '19 at 10:22
  • 2
    I use cd . all the time when I have a shell whose current working directory was mounted with sshfs but the ssh session has been closed and reopened. – jamesdlin Jan 22 '19 at 21:52
  • 5
    In such a case I do "cd $PWD". Other variants might work, but this one clearly expresses the intent: extract what is supposed to be my current path (i.e. read content of PWD environment variable), then walk the filesystem hierarchy from the root, down to a directory that happens to be reachable via that path, whether it is actually the same directory or not. This fits exactly the use case in this answer. – Stéphane Gourichon Jan 23 '19 at 14:32
  • @roaima it can definitely occur outside of NFS. For instance, while working with Git. (I wrote an answer to that effect.) – Wildcard Jan 24 '19 at 04:36
  • 2
    @Wildcard, ah. It's dependent on the shell being used. For example bash translates cd . to cd "$PWD" but not every shell does this. – Chris Davies Jan 24 '19 at 13:22
  • 3
    I'm really surprised, shocked even, that cd . works when the directory has been unlinked and a new, different directory is created at the same file-system path. The current working directory has been unlinked and presumably as part of that, it no longer has a . or .. entry, and even if it did, the . entry should continue to point to itself. It looks like the shell or the kernel is executing the cd command based on what the directory path name was rather than simply accessing the . entry. Can anyone confirm that behaviour? – Adrian Pronk Jan 25 '19 at 09:45
  • 2
    @AdrianPronk See roaima's comment above. – jamesdlin Jan 26 '19 at 00:14
  • I just did that, and after deleting the directory in the other terminal, a call of stat . in the first terminal gave me the same inode as before, so the inode seems to still exist immediately after the removal. Also ls -la does not give an error for me, but says total 0. – Stefan Hamcke Jan 28 '19 at 16:02
36

You can clear $OLDPWD with a quick cd ., if there should be a case where you don't want it to point anywhere "interesting". It'll also affect cd -.

mike3996
  • 1,549
16

Programmatically it's useful as a no-op. Consider a path provided from external input.

read -p "Path to file: " p
dirn=$(dirname "$p")
file=$(basename "$p")
echo "dirn=$dirn, file=$file"
cd "$dirn"
ls -ld "$file"

With a path such as "fred.txt" the directory will become ., leading to cd .

Chris Davies
  • 116,213
  • 16
  • 160
  • 287
  • 1
    It's useful that it doesn't throw an error if you're already in the directory that you're navigating to, but I wouldn't say that it is useful as a no-op. – Captain Man Jan 22 '19 at 14:05
  • 2
    @CaptainMan not throwing an error if you're already in the directory is (effectively) a no-op. The dirname command generates . where necessary to avoid breaking code that expects to be able to split a path. – Chris Davies Jan 22 '19 at 16:16
14

This is common if you had to work with a bad USB cable. After a device get disconnected and connected again, and automounted to the same directory, you have to use cd . to get it work again.

user23013
  • 1,087
  • 1
  • 9
  • 18
  • 1
    Won't that depend upon what sort of device, how it's being accessed, its filesystem, the OS, &c? – gidds Jan 24 '19 at 10:09
  • OS, maybe. It's unlikely the filesystem is relevant, as long as the kernel can find its way unmounting it while it is being used. In any case, the command has its use in the exactly right situation. – user23013 Jan 24 '19 at 10:39
11

Note that "." is the proper way to specify the name of the file that is open as the current working directory of any process (including a shell process of course), and "." is always a valid name of a file in any and all directories, including the current working directory. The name . may not be a valid name for a file for a given instance of a process if, say, the underlying current working directory has been removed (or gone "bad", e.g. a stale NFS handle), but it is a valid name of a file that is guaranteed to exist in every valid directory.

So . must be a valid argument for any command that accepts the name of a directory, and thus in the standard shell cd . must be a valid command.

Whether cd . is useful or not depends on the shell implementation. As mentioned it can be useful if the shell resets its internal idea of the full pathname of the current working directory after calling the underlying chdir system call, say for example if the underlying directory (or some parent of it) has been renamed.

At least some shells I know (/bin/sh on FreeBSD and NetBSD) will convert cd "" into cd ., which can arguably be described a feature to support programmatic use in a shell script where a variable might be used as a parameter (i.e. converting an empty variable substitution into a "do nothing" result), though the FreeBSD commit history says the change was directly due to adding POSIX support to prevent a failure from chdir(""), which POSIX mandates must fail.

Some other shells will replace the . with whatever they have stored as the fully qualified pathname to their current working directory, and thus for them this may allow for the behaviour mentioned in Sahil Agarwal's answer.

Toby Speight
  • 8,678
4

I used this command just today when I rebased the branch I was working on in Git, from within a directory which had first been created on that same branch. The rebase went fine but afterwards, git status threw an error. After cd . everything was normal.

(I was working in MobaXterm on Windows, incidentally. Just in case you're trying to reproduce this. It may not happen on other systems.)


I also have used this command in directories that are refreshed by an automated process that moves aside the old directory and replaces it with a new one (so it is as close to atomic as possible). Not a common situation but cd . is exactly what's needed.


After reading this excellent answer from Stephane Chazelas:

I now understand that my use cases above only work because I am using bash, in which cd . is equivalent to cd "$PWD". I highly recommend reading the linked answer.

Wildcard
  • 36,499
1

I use cd . to rerun the stuff I've overloaded cd with via a bash function.

From my ~/.bashrc:

# from the "xttitle(1)" man page - put info in window title
update_title()
{
    [[ $TERM = xterm ]] || [[ $TERM = xterm-color ]]  && xttitle "[$$] ${USER}@${HOSTNAME}:$PWD"
}

cd()
{
    [[ -z "$*" ]] && builtin cd $HOME
    [[ -n "$*" ]] && builtin cd "$*"
    update_title
}
waltinator
  • 4,865
0

EDIT: This has already been suggested by Sahil previously.

This is useful if you are inside a folder that got deleted and recreated by another process. For example, assuming the two terminal sessions $1 and $2:

$1 mkdir d
$1 cd d
$1 touch f

$2 rm -rf /path/to/d # delete the folder where $1 is in ...
$2 mkdir /path/to/d # ... and recreate it

$1 touch g # cannot create file g because current dir doesn't exist anymore
touch: cannot touch ‘g’: Stale file handle
$1 cd . # go to the newly created dir (same path)
$1 touch g # works fine now

I am not sure whether where exactly (OS, SHELL, ...?) the root cause of this behavior is.

Rolf
  • 902