Julia Evans

Weird unix thing: 'cd //'

Today my friend Mat told me an interesting trivia fact about cd!

Look at this interaction, where we try to cd /tmp, cd //tmp, and cd ///tmp, in bash and in fish.

[email protected]/> bash
[email protected]:/$ cd //tmp
[email protected]://tmp$ echo $PWD
//tmp
[email protected]:/tmp$ cd ///tmp
[email protected]:/tmp$ echo $PWD
/tmp
[email protected]://tmp$ fish
Welcome to fish, the friendly interactive shell
Type help for instructions on how to use fish
[email protected]:/tmp> cd //tmp
[email protected]:/tmp> echo $PWD
/tmp

What is //tmp? What is happening? Why is cd ///tmp different from cd //tmp? Here’s what we know so far:

are / and // the same file?

Yes. We can check this with stat. They both have the same inode number (256) so they are the same file.

[email protected]:~$ stat /
  File: '/'
  Size: 244       	Blocks: 0          IO Block: 4096   directory
Device: 16h/22d	Inode: 256         Links: 1
Access: (0755/drwxr-xr-x)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2017-02-08 23:13:55.647187990 -0500
Modify: 2017-01-10 13:01:30.987733887 -0500
Change: 2017-01-10 13:01:30.987733887 -0500
 Birth: -
[email protected]:~$ stat //
  File: '//'
  Size: 244       	Blocks: 0          IO Block: 4096   directory
Device: 16h/22d	Inode: 256         Links: 1
Access: (0755/drwxr-xr-x)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2017-02-08 23:13:55.647187990 -0500
Modify: 2017-01-10 13:01:30.987733887 -0500
Change: 2017-01-10 13:01:30.987733887 -0500
 Birth: -

Cool. But what is //? Why doesn’t bash just correct it to /?

the specification

The specification for cd is here

Here’s the relevant section

An implementation may further simplify curpath by removing any trailing <slash> characters that are not also leading <slash> characters, replacing multiple non-leading consecutive <slash> characters with a single <slash>, and replacing three or more leading <slash> characters with a single <slash>. If, as a result of this canonicalization, the curpath variable is null, no further steps shall be taken.

So! We can replace “three or more leading / characters with a single slash”. That does not say anything about what to do when there are 2 / characters though, which presumably is why cd //tmp leaves you at //tmp.

Why is this the specification? Mat pointed out there is a “Rationale” section in this spec, but it does not really explained.

In another specification, it says:

A pathname that begins with two successive slashes may be interpreted in an implementation-defined manner

So you can define //tmp to mean whatever you want? Like it could be different than /tmp? Why? Somebody on stack overflow said that this is related to the double slash in URLs (“http://“…) but didn’t provide a citation. Is that true?

If I find out, I will update this blog post with an answer.

update 1: there seems to be a pretty good answer in this stack overflow question