Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Don't do that, it's not only subject to race conditions, but also the <code>[ -e /path/file ]</code> checks if you can do a <code>stat(2)</code> on a file, so it will return false for different reasons, not only because the file cannot exist.</p> <p>An example is a symlink to a file that doesn't exist or a file in a directory you don't have search permission to.</p> <p>A much better approach is to use the right flags to the <code>open(2)</code> system call here, that is <code>O_CREAT|O_EXCL</code>. That way, the <code>open()</code> fails if the file didn't already exist without you having to do the check several millions of CPU clock ticks earlier.</p> <p>With a Bourne-like shell:</p> <pre><code>if (set -C &amp;&amp; : &gt; "$file") 2&gt; /dev/null; then print '%s\n' "$file has been created else print '%s\n' "It hasn't, possibly because it was already there" fi </code></pre> <p>(<code>set -C</code> is to enable the <code>O_EXCL</code> flag).</p> <p>Also, why would you want to create an empty file? Chances are you want to store something in that file. Then, just do it:</p> <pre><code>set -C { echo blah other-commands that-generate-the-content } &gt; "$file" </code></pre> <p>Then, that command group is only executed if the <code>file</code> didn't exist already (and it was possible to create it).</p> <p>If you want to test for file existence, write it at least:</p> <pre><code>[ -e "$file" ] || [ -L "$file" ] </code></pre> <p>or</p> <pre><code>ls -d -- "$file" &gt; /dev/null 2&gt;&amp;1 </code></pre> <p>if you care about it potentially being a symlink. That will still return false if the file does exist but you don't have the right to verify it.</p> <hr> <p>Now, if you want a longer and historical answer about testing for file existence:</p> <p>Initially, the <code>test</code> command (in Unix v7 where it first appeared) <a href="http://www.freebsd.org/cgi/man.cgi?manpath=v7&amp;query=test" rel="nofollow">had no <code>-e</code> (nor <code>-h</code>/<code>-L</code> option or <code>-a</code> unary)</a> option.</p> <p>The way to test for file existence was with <code>ls</code>. <code>ls</code> (with <code>-d</code>) lists the file and reports an error (and returns a <em>false</em> exit status) if it can't look up the file for a reason or another. Unix initially didn't have symlinks, but when they were introduced, <code>ls</code> was modified to do a <code>lstat(2)</code> on a file instead of a <code>stat(2)</code>. That is, in case of symlink <code>ls</code> returns information about the symlink file itself, not the file at the path the symlink points to.</p> <p>An option to <code>test</code> (aka <code>[</code>) for testing for file <em>"existence"</em> was first introduced in the <a href="http://www2.research.att.com/sw/download/man/man1/ksh88.html" rel="nofollow">Korn shell <code>test</code> builtin</a>. That was <code>-a</code>, not <code>-e</code>. <code>-a</code> is for <em>accessible</em> (I believe) which is a more accurate term than <em>existing</em>.</p> <p>I don't know when or what introduced <code>-e</code>, possibly POSIX. POSIX <a href="http://pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html" rel="nofollow">says</a> that <code>-e</code> was chosen over <code>-a</code> to avoid the possible confusion with the <code>-a</code> <em>binary</em> operator (for <em>and</em>).</p> <p>In any case both <code>-a</code> and <code>-e</code> attempt a <code>stat(2)</code> on the file, not a <code>lstat(2)</code>. That is:</p> <pre><code>[ -e "$file" ] </code></pre> <p>is equivalent to:</p> <pre><code>ls -Ld -- "$file" &gt; /dev/null 2&gt;&amp;1 </code></pre> <p>So, strictly speaking, it returns true if, at the time the test was done, it was possible to lookup the path after resolving the symlinks, and if the <code>stat(2)</code> fails, the reason for the failure is ignored.</p> <p><code>stat</code> may fail if the file doesn't exist (<code>ENOENT</code>), that is if the file doesn't exist or it exists but is a symlink to a file that doesn't exist, but also for plenty other reasons. Looking at <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/stat.html#tag_16_174_05" rel="nofollow">the possible error codes of <code>stat(2)</code></a> gives a few ideas:</p> <ul> <li><code>EACCESS</code>: during resolution of the path (and that can be any path component and in the path of any symlink), you don't have <em>search</em> permission for one directory component (note that you may still have access to the file via another path).</li> <li><code>ELOOP</code>: impossible to resolve the path because of too many symlinks resolved to get there.</li> <li><code>ENOTDIR</code>. For instance on <code>/etc/passwd/foo</code> or a symlink to it.</li> </ul>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
    1. COClaiming it's subject to race conditions is premature. The OP hasn't stated where this file comes from, and it's possible the script might be the only thing that creates it. Also saying that `[ -e /path/file ]` shouldn't be used because it can incorrectly fail isn't a good argument. If the test incorrectly fails and it tries to create the file, the create will error. By removing the test and using O_EXCL, the create will error for the exact same reason the test would have. Plus it might be a program which creates the file, in which `set -C` won't prevent the program from overwriting it.
      singulars
    2. CO@Patrick. No if the file is a symlink to an inexisting file in an existing directory, `[ -e "$file" ]` will return false, the create will succeed without O_EXCL (which is where it's dangerous as an attacker can force you to create files where you wouldn't want to), and would fail with O_EXCL (which implies no-follow).
      singulars
    3. COAlso, it may very well be "premature" for the OP. It might very well be that he runs only one instance of the script at a time, that nothing else may write to that file, that the file is in very tame area where only one user has write access to, and that that user is never involved with dealing with "foreign/alien/uncontrolled" data, but on stackexchange, the answers are intended for everybody, so IMO, the risk should be pointed out. And given that that method is safer and less expensive (only one system call, though a fork in the 1st, no external command run), the method should be preferred.
      singulars
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload