124

When defining a path to a directory as a variable or constant, should it end with a trailing slash? What is the convention?

pwd in Unix shows your current directory without a trailing slash, while the tab complete of cd /var/www/apps/ includes the trailing slash, which left me unsure.

Melanie Palen
  • 2,645
  • 6
  • 31
  • 50
meleyal
  • 32,252
  • 24
  • 73
  • 79
  • 2
    This question should be separated into "for Windows" or "for various flavors of Unix", because the recommendations are slightly different. – Rich Lysakowski PhD Feb 12 '22 at 00:22
  • No, the recommendation would be the same for both Unix and Windows. See how Microsoft expects directories to be represented in variables: https://learn.microsoft.com/en-us/windows/deployment/usmt/usmt-recognized-environment-variables – Karl Wilbur Jun 01 '23 at 17:38

14 Answers14

126

I go with the trailing slash because:

  1. "If it ends with a slash, it's a directory. If not, it's a file." is an easy convention to remember.

  2. At least on the operating systems I commonly use, doubling the slash causes no problems, while omitting the slash causes big ones. It is, therefore, safest to both put the slash into the variable and use "$path/$file" when making use of it.

Dave Sherohman
  • 45,363
  • 14
  • 64
  • 102
  • 15
    A directory path is only distinguishable from a file path if the directory path has a trailing slash. – Darwin Apr 27 '12 at 08:41
  • 7
    Multiple slashes are equivalent to one slash, unless the path starts with double slash. See http://unix.stackexchange.com/questions/1910/how-linux-handles-multiple-path-separators-home-username-file – jdh8 Sep 02 '13 at 20:42
  • 7
    Additionally adding slash at the end of vaariable allows for "$path$file" instead of "$path/$file", which allows for empty $path - meaning current working directory. But never use backslash instead of slash. – Fantastory Feb 03 '15 at 16:12
  • File descriptors are useful too – Francesco Gualazzi Jul 28 '15 at 14:11
  • @jdh8 Even if the path starts with double slashes it should still be equivalent to one slash. Although this may change from implementation to implementation. The unix standards state that `A pathname that begins with two successive slashes may be interpreted in an implementation-defined manner, although more than two leading slashes shall be treated as a single slash.` For the most part it's been observed that double slashes usually are interpreted as a single slash in common implementations. – Xtrinity Jan 11 '16 at 02:48
  • 1
    @Xtrinity The path `/stackoverflow.com` is the same as `///stackoverflow.com`, but different from `//stackoverflow.com`. – jdh8 Jan 17 '16 at 18:05
  • `"doubling the slash causes no problems, while omitting the slash causes big ones."` This along with what user jdh8 pointed out above, is what made this answer go from a really good one to what should be considered the "right" answer. – TheKarateKid Aug 01 '18 at 20:45
  • 1
    A directory path is only distinguishable from a file path if the directory path has a trailing slash and a period. A trailing slash alone represents all files within a directory. Not the directory itself. – TamusJRoyce Jun 23 '20 at 16:11
  • 1
    @TamusJRoyce So `rmdir foo/` removes directories within `foo` not `foo` itself? No. I don't think _"A trailing slash alone represents all files within a directory"_ matches common usage or utilities. – Jonathan Wakely Feb 09 '22 at 12:56
  • This is the best answer for Windows. – Rich Lysakowski PhD Feb 12 '22 at 00:23
  • It's sad that the most upvoted answer is at odds with UNIX conventions. Slash is a separator, not a part of the name. A directory name does not end in slash. Filenames cannot contain slashes and everything (including a directory) is a file in UNIX. – pjboro Jun 29 '22 at 12:06
45

I know that this is 10 years old, but I wanted to throw in my very opinionated $0.02.

No. No. Absolutely no.

We are talking about a Unix system. In reference to the directory itself, it is a node like any other. When referring to the directory, it should not ever have an unescaped slash in its name (ref: dirname, pwd, ~, echo $HOME, echo $PATH, the output from ls, et al).

When referring to a directory's contents, then you need a slash. That is to say, ls /home/karl/ is more appropriate than ls /home/karl (FTR, I almost always do the latter because ...well, lazy).

When utilizing a variable containing a directory to create the full path to a file, you would always expect to include the slash (i.,e: cp ${HOME}/test ${OTHER_DIR}/).

It is expected that a directory not end in a slash. Any expectation that a directory ends in a slash is wrong. Thus adding a slash to the end of a *_DIR variable's value would be subverting expectations.

As for tab completion, the expectation here is that you are going into that directory. Thus, the assistance provided by tab completion is to get you into that directory so that you can make the next choice based on its contents.

(reference from comments: Filepath Misconceptions, from Wikipedia's Talk:Path_(computing) page. Thanks, john c. j.)

It is worth noting that just because it is wrong doesn't mean that tools/packages/libraries never do it. It is a far-too-common occurrence that such things add a trailing slash when none should exist. Therefore, as Bevan and Paul F both suggested, when using 3rd party tools, it is best to remove any trailing slashes that might exist in directory names.

Unix Inodes

The inode (index node) is a data structure in a Unix-style file system that describes a file-system object such as a file or a directory.

-- https://en.wikipedia.org/wiki/Inode

Filesystem Hierarchy Standard

The standard for the Unix filesystem (the Filesystem Hierarchy Standard, AKA FHS) clearly show that directories are not thought of as having a trailing slash, but rather directory contents begins with a slash (the only exception to this is / because we will not refer to the filesystem root by using an empty string ...and one should never be creating files there anyway.)

-- http://www.pathname.com/fhs/pub/fhs-2.3.html

-- https://en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard

Karl Wilbur
  • 5,898
  • 3
  • 44
  • 54
  • 3
    Excellent answer. I've tended to use this approach but never been entirely complete as to my reasoning why. This is the only answer that nails it. – wardw Jan 08 '19 at 11:29
  • 7
    It's the root `/` that breaks the pattern. And if you were to start your reasoning from here (recursively) you can then get to the contradictions that may be at the heart of the diverging practices (as evidenced from the answers here). But once you accept this as the exception then everything else falls in line. – wardw Jan 08 '19 at 11:38
  • I see. Took a bit playing with dirname. If you intend to explicitly store a directory in a path, end the path with a “/.”, where the dot represents the current directory. – TamusJRoyce Feb 24 '19 at 10:12
  • 2
    You would *never* end a with a `/.`, this is just a terrible idea; in addition to injecting very unusual content leading to unexpected trouble, it looks just plain silly. – Karl Wilbur Aug 14 '19 at 15:25
  • 2
    @wardw you could think of the root directory as being named empty string, while "/" is an empty string followed by a slash and means "the contents of the root directory". – bobpaul Aug 15 '19 at 15:35
  • @bobpaul, Exactly! Thanks. – Karl Wilbur Aug 15 '19 at 20:27
  • 1
    This answer should be upvoted more. See also _[Filepath Misconceptions](https://en.wikipedia.org/wiki/Talk:Path_(computing)#Filepath_Misconceptions)_ section in the Wiki. – john c. j. Nov 04 '19 at 06:14
  • It is funny how Apple documentation is inconsistent about it. It seems slashed and unslashed variations are mixed in an arbitrary way withing the single article: https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/FileSystemOverview/FileSystemOverview.html – john c. j. Nov 04 '19 at 08:07
  • 1
    @bobpaul You could think that the empty string is a name of the root directory but this idea breaks if you try to refer to the root directory by empty string (without a slash) :) – pabouk - Ukraine stay strong Feb 21 '22 at 15:34
  • True. Thanks, @pabouk – Karl Wilbur Feb 21 '22 at 16:14
  • Example: I claim `find -name path/to/dir/ -prune -o ...` will not prune correctly with the trailing slash – Eric Auld Oct 03 '22 at 20:12
  • 1
    Also something I realized with CMake is a path with a trailing slash causes errors when installing into directories not owned by the user where the permissions are different. Plus what you stated makes sense, so no trailing slashes. – betafractal Oct 19 '22 at 16:25
  • I was expecting to get confirmation that the opposite is true, because I prefer trailing slashes for visibility (ie. _usability_). But you just proved me wrong. Well written! – alexpanter May 01 '23 at 08:29
27

I don't include the trailing slash when I, for example, define a directory for storing files. That is because I will use it like

$store_file = "$store_path/$file_id";

I will always add a trailing slash before using a variable that's supposed to hold a directory path. I think it's better to always add one than to wonder if the trailing slash is included.

Melanie Palen
  • 2,645
  • 6
  • 31
  • 50
Johan Soderberg
  • 2,650
  • 1
  • 15
  • 12
  • 32
    Not having a trailing slash means that its unclear if the path in $store_path is a file or a directory. "/tmp/store_data" is it a file or a directory ? – Darwin Apr 27 '12 at 08:54
  • 4
    When using something like PHP's [realpath()](http://php.net/manual/en/function.realpath.php) function, it will not print the trailing slash. Your system and tools might dictate your convention. – jmbertucci Dec 27 '12 at 17:53
  • 11
    Having multiple slashes anywhere usually will be interpreted as a single slash. So you could even have something like `'///' + $root + '//' + $file + '/'` and it wouldn't matter. Although having the trailing slash is a good way to discern whether or not the path is a file or a directory it would be better to append to paths like `'/' + $root` rather than `$root + '/'` as you can't be positive that the path being appended to has a trailing slash, but you can be relatively assured that multiple slashes will be interpreted as a single slash in most environments. – Xtrinity Jan 11 '16 at 02:52
  • @johan Soderberg, I recently needed to verify a trailing slash from user input for use with rsync. As you have stated, you cannot assume that the path ends in a slash, therefore you are compelled to add one. I came up with the following as a graceful way of assuming neither and adding one only when not present (for the example there is a variable called STR): `${STR}$(printf \\$(printf '%03o' $(($(printf '%d' "'${STR:(-1)}")==47?0:47))))` I also documented it in a gist for clarity: [add or remove trailing slash in bash](https://gist.github.com/jmmitchell/a6eacafadefb5292c9abdadc8bab7852) – John Mark Mitchell Apr 05 '16 at 14:39
  • 1
    @Darwin: there are other ways to know whether a path represents a file or directory. In PHP for example: is_file($path), is_dir($path). SplFileInfo class (generated by FileSystemIterator type objects) has $obj->IsDir(), $obj->IsFile() methods; etc. – Matthew Slyman Apr 20 '16 at 08:55
  • 3
    @MatthewSlyman, My point was that everybody expects this `/tmp/store_data/` to be a directory, while its unclear what the same path without a traling slash is `/tmp/store_data` – Darwin Apr 21 '16 at 05:50
  • 7
    The problem with this is: If a variable not exist, it is the same as empty, and a `rm -rf $foo/$bar` can end in `rm -rf /` – 12431234123412341234123 Feb 01 '17 at 12:08
  • 1
    @12431234123412341234123 True, but the risk is low, given most distributions out there now require `--no-preserve-root` to do serious damage. – J.D. Mallen Feb 23 '19 at 19:38
  • 1
    @Darwin : I think the name of the variables should express this meaning, not their values – André Sousa Dec 16 '19 at 14:42
8

Yes, it should, as:

Pathname + filename = fully qualified file location.

SO the slash between the last directory and the filename needs to be either at the end of the pathname or the start of the filename. Prefixing filenames with a / means you need to take this into account if you just want to open a file (i.e if you assume that an unqualified filename is in the current working directory).

Melanie Palen
  • 2,645
  • 6
  • 31
  • 50
pauljwilliams
  • 19,079
  • 3
  • 51
  • 79
  • 7
    .. and failing to take it into account means you're possibly inadvertently messing with /, and that way madness lies – JustJeff Jun 11 '09 at 11:39
  • 1
    I disagree, because string concatenation is the wrong abstraction for filesystem paths. As [@Duncan's answer says](https://stackoverflow.com/a/66980684/981959), use an API for paths. e.g. C++'s `filesystem::path` overloads `operator/` so you do `pathname / filename`, or in Python `os.join(pathname, filename)`. In a scripting language with variable interpolation you can do something like `"$pathname/$filename"` (adding the directory separator explicitly between the components). Relying on the slash being present so that you can just use unstructured string concatenation is very fragile. – Jonathan Wakely Feb 09 '22 at 12:59
7

Whenever I store directory paths or return them from APIs, I try and stick with the convention of keeping a trailing slash. This avoids the whole 'is it a file or a directory' ambiguity.

Addendum:
This is not intended to be a substitute for using methods that can tolerate either a trailing slash or its absence. Even using this convention I still always use Path.Combine(...) and similar methods.

Melanie Palen
  • 2,645
  • 6
  • 31
  • 50
jerryjvl
  • 19,723
  • 7
  • 40
  • 55
6

I guess this is one of those rare cases where the correct theoretically and practically answer is different.

It seems @Karl Wilbur's answer for sure is correct in a theoretical sense, as you should be able to distinguish a reference to the directory node itself from the directory's content.

But in practice I'll argue the correct answer is the opposite:

  • The most important reason is you can tell with certainty that the path /home/FSObjectX/ is a folder, whereas /home/FSObjectX is ambiguous. No one can tell if this is a file of folder.
    Specifications shall always be precise and unambiguous whenever possible.

  • In a vast majority of cases, you will always reference the content of a folder, not the dir node itself.
    In those rare cases where you actually do, it can easily be handled in the code by removing any optional trailing dir-separator.

  • Using double dir-separators will not do any harm, although missing one will for sure.
    In theory a bad argument as your shouldn't code by "chance", but in practice, errors happen, and perhaps using trailing dir-sep might end up with a few fewer runtime errors at an end-user.

Reading through this interesting thread I haven't found any disadvantages of using trailing dir-sep, only that it's wrong in a theoretical sense. Or did I miss something?

Cadoiz
  • 1,446
  • 21
  • 31
MrCalvin
  • 1,675
  • 1
  • 19
  • 27
  • 1
    in actual practice you will find that the proper expectation is not to contain a trailing slash. Just look at every tool that you use which was written by competent developers. – Karl Wilbur Oct 26 '20 at 14:52
  • 1
    I understand your reasoning however you're unlikely to hardcode your paths (and if you do you'd hardcode both the path and the filename). If I saw `$homedir = "/home/FSObjectX";` I'd be reasonably certain that it's a directory. If I was feeling particularly untrusting I could ask the filesystem to verify it. Specifications do need to be precise and unambiguous, but `/home/FSObjectX/` is unambiguously a reference to the contents and `/homeFSObjectX` is unambiguously a reference to the node in a lot of specs. Spend a few hours playing with `rsync` to really understand the difference :) – Duncan Apr 07 '21 at 06:18
  • Somewhat duplicate to https://stackoverflow.com/a/980611/4575793 ? – Cadoiz Jun 15 '21 at 23:54
6

Maybe you should think about what your decision would mean for files. If you don't include the trailing slash at the end of a directory name you'll have to add it to the start of the file name.

Now, if for some reason, the path leading up to the file is missing when you concatenate strings, you end up with something like /filename which is not just a file but an absolute path from the root directory (wherever that may be in that context).

That's why I end my paths with a slash and keep files as files.

Melanie Palen
  • 2,645
  • 6
  • 31
  • 50
DanMan
  • 11,323
  • 4
  • 40
  • 61
  • 2
    The alternative here is to express your filename as `./filename`. But in general it should be the responsibility of the code concatenating the paths to do it properly - and not make assumptions either way. – wardw Jan 08 '19 at 11:10
5

In php, since dirname(__FILE __) function returns the directory name without a slash at the end. I tend to stick to that convention.

Otherwise, using a slash at the end of a directory name will conflict with the way dirname(..) works and then you are stuck with handling the two cases since you don't know if the directory name came from a dirname(..) function or a content defined with a trailing slash.

Bottom Line: Don't use a trailing slash since dirname(..) doesn't.

// PHP Example
dirname(__FILE__); // returns c:\my\directory without a trailing slash, so stick to it!

For other languages, check the function that extracts a pathname, and see if it is using a trailing slash or not, then stick to the language's convention.

Melanie Palen
  • 2,645
  • 6
  • 31
  • 50
Basil Musa
  • 8,198
  • 6
  • 64
  • 63
  • 2
    An exception: dirname('/test')='/' — rather than returning an empty string, dirname returns a single slash in this case! See the notes [here](http://php.net/manual/en/function.dirname.php). – Matthew Slyman Apr 20 '16 at 12:57
4

I know this is an old thread but I thought I'd share what I do. If possible, I'd normally allow for both and do something like this (if it was PHP):

$fullPath = rtrim($directory, '/') . '/filename.txt');

That way, if the directory is defined in a config file, it doesn't matter whether the next person to change it includes the trailing slash or not.

Paul F
  • 59
  • 1
  • 4
3

The convention is to be consistent. Importantly, realise that the argument as to whether the / belongs to the directory or the filename is a false dichotomy; it belongs to neither because it is a path separator.

The correct answer, IMO, is where possible you should use path manipulation libraries if they are provided by your language (or write your own), and ignore the internal structure of a path just because it looks like a string. This will eliminate the problem of knowing where to put the slash, and also make your code more portable between systems.

Duncan
  • 2,056
  • 13
  • 11
3

I tend to just add the trailing slash as I am more than likely going to use that directory to add/retrieve files...

In terms of web referencing, it can actually increase performance leaving the trailing slash in

http://www.netmechanic.com/news/vol4/load_no11.htm

Melanie Palen
  • 2,645
  • 6
  • 31
  • 50
James
  • 80,725
  • 18
  • 167
  • 237
3

Yes, there are lots of filesystems that support files without any extensions, so always add the trailing slash to avoid any problems.

maxp
  • 24,209
  • 39
  • 123
  • 201
  • I know this is a tad bit late. That is why I always include a file extension on all files I create. bashscript.sh is better than using bashscript. – fixit7 Sep 27 '22 at 10:41
1

I've never seen a firm convention either way.

Pretty sure, though, that whatever you settle upon, someone else will be 100% sure it should be the other way. So, the best idea is to tolerate things being set either way.

In the .NET world, Path.Combine() gives you a way to handle this - there are equivalents in other environments, from cmd files on up.

Melanie Palen
  • 2,645
  • 6
  • 31
  • 50
Bevan
  • 43,618
  • 10
  • 81
  • 133
0

I favor the convention of not have a trailing slash. My reason is that I think of paths as things that can be extended. Whenever something needs to be extended, it should be assembled like Lego pieces, with a male connector on one end and female on the other. This is how intervals and looping are best structured to avoid awkward edge cases, or off-by-one errors.

The connector in this case is the slash. But which end should it go on, left or right? I think it should clearly go on the left.

The Unix standard of making "/" the root is what misleads us, temporarily, into considering the right. But Unix is just wrong here. We need to remember that Unix is a seat-of-your-pants OS, sloppy in its design and lacking conceptual principles, so we take its design principles with a grain of salt. Using the connector symbol as the name of one of the directories makes no sense. Given that, the best we can do is smooth over it and try to be as consistent as we can be. If the root were anything other than "/", it would be obvious that we want the connector on the left: rootdir, rootdir/subdir, rootdir/subdir/subsubdir, ... The thing we're adding at each step is "/" + "name".

I reject the following arguments:

  1. We can distinguish between files and directories based on whether they the name ends in a slash.
  2. It causes no harm to have two slashes in a row, so we can always add a slash without fear.
  3. If we have a slash in path names, we can extend by something like $path$file.

All of these assume that we aren't completely sure what our code is doing, so it's good to use constructions that work even if our code is a little wrong. I disagree. My philosophy is that if your code is ever wrong at all, you want it to break as soon as possible so you don't build on an incorrect foundation.

Addlai
  • 121
  • 4