简体   繁体   English

如果文件不存在,如何执行某些命令?

[英]How to execute certain commands if a file does NOT exist?

I would like to check if a file exists, then if it does not, create it. 我想检查文件是否存在,如果不存在,则创建它。

Consider an equivalent of the following C code but with shell scripting. 考虑使用以下C代码,但使用shell脚本。

if(!exist) {
    command;
    command;
}
else {
    command;
    command;
}

Checking if a file exists is a very common task. 检查文件是否存在是一项非常常见的任务。 To search for relevant questions, use the search bar (top right). 要搜索相关问题,请使用搜索栏(右上角)。 I got lots of results with the terms "bash script file exists" 我用术语“bash脚本文件存在”得到了很多结果

In any case, you want either the test builtin or its semantic equivalent [ ] : 在任何情况下,您都需要test内置或其语义等价物[ ]

[ ! -e your_file ] && >your_file

or 要么

test ! -e your_file && >your_file

which will first test that your_file does not ( ! ) exist ( -e ) and creates it if that's the case. 这将首先test your_file不存在( ! )(- -e )并创建它(如果是这种情况)。

For more information on the different tests you can run (other than -e ), you can type: 有关可以运行的不同测试的更多信息(除了-e ),您可以键入:

help -m test | less

You can use this: 你可以用这个:

if [ ! -e "$file" ]; then
       touch file
else
        ...
fi
if [ ! -e "$path" ]
then
    touch -- "$path"
fi

A simpler version would be to simply touch -- "$path" - it creates the file if it doesn't exist, and just updates the access and modification times if it does exist. 一个更简单的版本就是简单地touch -- "$path" - 它创建文件(如果它不存在),只是更新访问和修改时间(如果它存在)。 The double dash ( -- ) ensures that you can create the file even if it starts with a dash, and the quotes around $path are necessary. 双短划线-- )确保您可以创建文件,即使它以短划线开头,并且$path周围的引号也是必需的。

Don't do that, it's not only subject to race conditions, but also the [ -e /path/file ] checks if you can do a stat(2) on a file, so it will return false for different reasons, not only because the file cannot exist. 不要这样做,它不仅受竞争条件的限制,而且[ -e /path/file ]检查你是否可以对文件执行stat(2) ,因此它会因不同的原因返回false,不仅如此因为文件不能存在。

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. 一个示例是不存在的文件的符号链接或您没有搜索权限的目录中的文件。

A much better approach is to use the right flags to the open(2) system call here, that is O_CREAT|O_EXCL . 更好的方法是在这里使用open(2)系统调用的正确标志,即O_CREAT|O_EXCL That way, the open() fails if the file didn't already exist without you having to do the check several millions of CPU clock ticks earlier. 这样,如果文件不存在, open()失败,而您不必先检查数百万个CPU时钟周期。

With a Bourne-like shell: 使用类似Bourne的shell:

if (set -C && : > "$file") 2> /dev/null; then
  print '%s\n' "$file has been created
else
  print '%s\n' "It hasn't, possibly because it was already there"
fi

( set -C is to enable the O_EXCL flag). set -C是为了启用O_EXCL标志)。

Also, why would you want to create an empty file? 另外,为什么要创建一个空文件? Chances are you want to store something in that file. 您可能希望在该文件中存储某些内容。 Then, just do it: 然后,就这样做:

set -C
{
  echo blah
  other-commands that-generate-the-content
} > "$file"

Then, that command group is only executed if the file didn't exist already (and it was possible to create it). 然后,只有在file不存在的情况下才会执行该命令组(并且可以创建它)。

If you want to test for file existence, write it at least: 如果要测试文件是否存在,请至少写入:

[ -e "$file" ] || [ -L "$file" ]

or 要么

ls -d -- "$file" > /dev/null 2>&1

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. 如果文件确实存在但您无权对其进行验证,那么仍将返回false。


Now, if you want a longer and historical answer about testing for file existence: 现在,如果您想要有关测试文件存在的更长且历史性的答案:

Initially, the test command (in Unix v7 where it first appeared) had no -e (nor -h / -L option or -a unary) option. 最初, test命令(在它首次出现的Unix v7中) 没有-e (也不是-h / -L选项或-a一元)选项。

The way to test for file existence was with ls . 测试文件存在的方法是使用ls ls (with -d ) lists the file and reports an error (and returns a false exit status) if it can't look up the file for a reason or another. ls (带-d )列出文件并报告错误(并返回错误的退出状态),如果由于某种原因无法查找文件。 Unix initially didn't have symlinks, but when they were introduced, ls was modified to do a lstat(2) on a file instead of a stat(2) . Unix最初没有符号链接,但是当它们被引入时, ls被修改为对文件而不是stat(2)执行lstat(2) stat(2) That is, in case of symlink ls returns information about the symlink file itself, not the file at the path the symlink points to. 也就是说,在symlink ls情况下, ls返回有关符号链接文件本身的信息,而不是符号链接指向的路径上的文件。

An option to test (aka [ ) for testing for file "existence" was first introduced in the Korn shell test builtin . test (aka [ )测试文件“存在”的选项最初是在Korn shell test内置中引入的。 That was -a , not -e . 那是-a ,而不是-e -a is for accessible (I believe) which is a more accurate term than existing . -a可访问的 (我相信),这是一个比现有更准确的术语。

I don't know when or what introduced -e , possibly POSIX. 我不知道何时或什么介绍-e ,可能是POSIX。 POSIX says that -e was chosen over -a to avoid the possible confusion with the -a binary operator (for and ). POSIX 表示 -e被选中-a以避免与-a 二元运算符(for )混淆。

In any case both -a and -e attempt a stat(2) on the file, not a lstat(2) . 在任何情况下, -a-e都在文件上尝试stat(2) ,而不是lstat(2) That is: 那是:

[ -e "$file" ]

is equivalent to: 相当于:

ls -Ld -- "$file" > /dev/null 2>&1

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 stat(2) fails, the reason for the failure is ignored. 因此,严格地说,如果在测试完成时,可以在解析符号链接后查找路径,并且如果stat(2)失败,则忽略失败的原因,它返回true。

stat may fail if the file doesn't exist ( ENOENT ), 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. 如果文件不存在( ENOENT ),则stat可能会失败,即文件不存在或存在但是对于不存在的文件的符号链接,但也有很多其他原因。 Looking at the possible error codes of stat(2) gives a few ideas: 查看stat(2)的可能错误代码可以提供一些想法:

  • EACCESS : during resolution of the path (and that can be any path component and in the path of any symlink), you don't have search permission for one directory component (note that you may still have access to the file via another path). EACCESS :在解析路径期间(可以是任何路径组件和任何符号链接的路径),您没有一个目录组件的搜索权限(请注意,您可能仍然可以通过另一个路径访问该文件) 。
  • ELOOP : impossible to resolve the path because of too many symlinks resolved to get there. ELOOP :无法解决这条路径,因为太多的符号链接已经解决了。
  • ENOTDIR . ENOTDIR For instance on /etc/passwd/foo or a symlink to it. 例如在/etc/passwd/foo或它的符号链接上。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM