54

This question already has an answer here:

Possible Duplicate:
How linux handles multiple path separators (/home////username///file)

Most commands I use in linux behave exactly the same whether I include the trailing slash / character on the end of a directory name or not.

For example:

ls /home/cklein
ls /home/cklein/

cp foo bar
cp foo/ bar/

When does this trailing slash matter? What is the semantic meaning of the trailing slash?

marked as duplicate by slm Aug 9 '17 at 2:27

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • I think the answers here cover the subject okay—it doesn't seem direly in need of new answers—but @djsmith is correct; it's not a duplicate. The other question is related but not at all the same. – Wildcard Jan 19 '17 at 22:57
  • Honestly, this isn't a duplicate at all. This is about trailing slashes on a directory, not multiple consecutive slashes. I just wrote a good test case with rsync that I want to post here for illustration of the different cases, but I can't until the question is reopened. – Wildcard Aug 8 '17 at 22:24
  • Agreed - I added my nomination to reopen. – Cory Klein Aug 8 '17 at 22:25
  • I've reopened because unix.stackexchange.com/questions/870/… is a better duplicate. – Gilles Aug 8 '17 at 22:35
  • 1
    Since you're still around, would you mind at least not accepting a one-liner answer that didn't even get its meager facts right? – Gilles Aug 8 '17 at 22:39
43

One good example is moving a file into a directory:

mv some_file foo

vs.

mv some_file foo/

If foo doesn't exist, the first will rename some_file to foo, rather than the intended foo/some_file; the second will complain, which is what you want.

If foo does exists but isn't a directory, the first can clobber the foo file; again, the second will complain.

cp presents similar issues.

Working on some old versions of SunOS, I developed the habit of appending /., because the system actually ignored a trailing / on a file name; for example, /etc/motd/ would refer to the file rather than being an error. Later versions of SunOS / Solaris don't seem to have that problem.

37

It is completely dependent on the tool. rm won't let you remove a symlink to a directory if there's a slash at the end, and rsync does different things if the source file specification has a slash at the end.

  • 22
    Pay very close attention when using rsync!!! The trailing slash really matters. – Josh Oct 10 '12 at 19:48
  • 19
    For the most part, a trailing / means “treat this as a directory, dereference the symlink if it is one, complain if it isn't a directory”. This behavior is mandated for utilities specified by POSIX. Rsync's source argument is a notable exception. – Gilles Oct 10 '12 at 23:42
  • 2
    Note that by default, chown -R /dir1/symlink1 will not perform recursion when the target is a symbolic link; however, chown -R /dir1/symlink1/ will do what you would expect. – chrisfargen Nov 17 '13 at 8:08
  • 1
    Even though the OP asked specific for Linux, it may be worth noting that the OS or flavor of tools used may make a difference. One notable example is cp which has a different behavior when using the -r option on OS X (BSD cp) and Linux (GNU cp). cp -r src/ dest will only copy the contents of src into dest when using BSD cp but will copy the direcory src itself into dest when using GNU cp. (see jondavidjohn.com/linux-vs-osx-the-cp-command) – matlehmann Sep 17 '15 at 15:27
  • 1
    @mathlehmann Nice find. Devs wanting to be too clever by half again. Instead of a clear-as-day additional option ("--copy-unto" for example), let's use obscure syntax that no-one ever remembers how to use. – David Tonhofer Aug 8 '16 at 14:40
15

foo/ is like foo/., so if foo is a symlink to a directory, foo/ is a directory (not a symlink), and if foo is not a directory or a symlink to a directory, then you get a ENOTDIR error for anything trying to access foo/. That's the behavior on Linux.

Behavior may differ on other systems.

See here and here and here to see what POSIX/SUS have to say about it.

  • I've edited the first two links to POSIX specifications but I'm not fully confident about the third link - which I presume should be to pubs.opengroup.org/onlinepubs/9699919799/xrat/… – Anthony Geoghegan Nov 8 '16 at 16:12
  • 1
    Thanks. Yes it's annoying that the TC2 update is now available at the same URL as the previous versions but with completely different HTML anchors. Many of the links are even broken there, so I'd expect it will change again. Might be better to link to the web archive to get consistent links. – Stéphane Chazelas Nov 8 '16 at 16:44
6

In rsync, the man page reads as follows:

   A trailing slash on the source changes this behavior to avoid  creating
   an  additional  directory level at the destination.  You can think of a
   trailing / on a source as meaning "copy the contents of this directory"
   as  opposed  to  "copy  the  directory  by name", but in both cases the
   attributes of the containing directory are transferred to the  contain-
   ing  directory on the destination.  In other words, each of the follow-
   ing commands copies the files in the same way, including their  setting
   of the attributes of /dest/foo:

          rsync -av /src/foo /dest
          rsync -av /src/foo/ /dest/foo

The trailing slash on the destination doesn't matter at all. Only on the source. (And then, of course, it only matters if the source is a directory rather than a single file or a glob.)

To illustrate the directory to directory use case:

$ mkdir foo bar baz
$ chmod 700 foo
$ chmod 750 bar
$ chmod 705 baz
$ echo hello > foo/file1
$ chmod 606 foo/file1 
$ ls -n
total 0
drwxr-x---  2 501  20   68 Aug  8 15:29 bar/
drwx---r-x  2 501  20   68 Aug  8 15:29 baz/
drwx------  3 501  20  102 Aug  8 15:30 foo/
$ ls -n foo
total 8
-rw----rw-  1 501  20  6 Aug  8 15:30 file1
$ rsync -a foo bar
$ rsync -a foo baz/
$ rsync -a foo bif
$ rsync -a foo bonk/
$ ls -n
total 0
drwxr-x---  3 501  20  102 Aug  8 15:30 bar/
drwx---r-x  3 501  20  102 Aug  8 15:30 baz/
drwxr-xr-x  3 501  20  102 Aug  8 15:30 bif/
drwxr-xr-x  3 501  20  102 Aug  8 15:30 bonk/
drwx------  3 501  20  102 Aug  8 15:30 foo/
$ ls -n *
bar:
total 0
drwx------  3 501  20  102 Aug  8 15:30 foo/

baz:
total 0
drwx------  3 501  20  102 Aug  8 15:30 foo/

bif:
total 0
drwx------  3 501  20  102 Aug  8 15:30 foo/

bonk:
total 0
drwx------  3 501  20  102 Aug  8 15:30 foo/

foo:
total 8
-rw----rw-  1 501  20  6 Aug  8 15:30 file1
$ rm -rf b*
$ mkdir bar baz
$ chmod 750 bar
$ chmod 705 baz
$ rsync -a foo/ bar
$ rsync -a foo/ baz/
$ rsync -a foo/ bif
$ rsync -a foo/ bonk/
$ ls -n
total 0
drwx------  3 501  20  102 Aug  8 15:30 bar/
drwx------  3 501  20  102 Aug  8 15:30 baz/
drwx------  3 501  20  102 Aug  8 15:30 bif/
drwx------  3 501  20  102 Aug  8 15:30 bonk/
drwx------  3 501  20  102 Aug  8 15:30 foo/
$ ls -n *
bar:
total 8
-rw----rw-  1 501  20  6 Aug  8 15:30 file1

baz:
total 8
-rw----rw-  1 501  20  6 Aug  8 15:30 file1

bif:
total 8
-rw----rw-  1 501  20  6 Aug  8 15:30 file1

bonk:
total 8
-rw----rw-  1 501  20  6 Aug  8 15:30 file1

foo:
total 8
-rw----rw-  1 501  20  6 Aug  8 15:30 file1
$ 
  • 2
    +1. I use rsync all the time and have done so for many years, and I can still never remember the exact details of rsync's handling of a trailing slash on the source dir. I always have to --dry-run it first or read the man page. It's good to see this answer, but it's unlikely to fix my memory :( – cas Aug 9 '17 at 1:51

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