如何判断Bash中是否存在常规文件?

Bil*_*ard 3069 bash scripting file-io

我使用以下脚本来查看文件是否存在:

#!/bin/bash

FILE=$1     
if [ -f $FILE ]; then
   echo "File $FILE exists."
else
   echo "File $FILE does not exist."
fi
Run Code Online (Sandbox Code Playgroud)

如果我只想检查文件是否存在,使用的语法是什么?

#!/bin/bash

FILE=$1     
if [ $FILE does not exist ]; then
   echo "File $FILE does not exist."
fi
Run Code Online (Sandbox Code Playgroud)

Joh*_*lla 4296

测试命令([在这里)有一个"非"逻辑运算符是感叹号(类似于许多其他语言).试试这个:

if [ ! -f /tmp/foo.txt ]; then
    echo "File not found!"
fi
Run Code Online (Sandbox Code Playgroud)

  • 更简洁地说:[!-f /tmp/foo.txt] &&回显“找不到文件!” (186认同)
  • @DavidWinterbottom更加多汁:`[ - f /tmp/foo.txt] || echo"找不到文件!"` (141认同)
  • 我努力寻找"如果两个文件中不存在任何文件"的正确语法.以下两者都有效:`if [!\(-f"f1"-a -f"f2"\)]; 然后回声MISSING; 如果[!] -f"f1"] || [!-f"f2"]; 然后回声MISSING; fi` (36认同)
  • 参数可以是以下任何一种:`-e:返回true值,如果file存在``-f:返回true值,如果file存在且常规文件``-r:返回true值,如果file存在且可读``-w:返回true值,如果文件存在且可写``-x:返回true值,如果file存在且可执行``-d:返回true值,如果存在且是目录` (24认同)
  • 使用`时存在不对称性!-f`与`&&`使用`-f`和`||`.这与非/存在检查返回的退出代码有关.如果您需要使用退出代码0来彻底退出行(有时您不需要此约束),则这两种方法不可互换.或者,只需使用`if`语句,您就不必再担心非/存在检查的退出代码. (5认同)
  • 如果要在if操作中使用2个条件,请使用-a运算符,这意味着AND.我认为如果使用[[]]运算符,也可以使用& (2认同)
  • 在“[”和“!”之间保留一个“空格”,否则将不起作用 (2认同)

Blu*_*cti 617

Bash文件测试

-b filename- 阻止特殊文件
-c filename- 特殊字符文件
-d directoryname- 检查目录是否存在
-e filename- 检查文件是否存在,无论类型(节点,目录,套接字等)
-f filename- 检查常规文件是否存在而不是目录
-G filename- 检查文件是否存在且是否属于有效组ID
-G filename set-group-id- 如果文件存在则为真且为set-group-id
-k filename- 粘滞位
-L filename- 符号链接
-O filename- 如果文件存在并且由有效用户ID拥有则为真
-r filename- 检查文件是否可读
-S filename- 检查文件是否为套接字
-s filename- 检查是否file是非零大小
-u filename- 检查文件set-user-id位是否设置
-w filename- 检查文件是否可写
-x filename- 检查文件是否可执行

如何使用:

#!/bin/bash
file=./file
if [ -e "$file" ]; then
    echo "File exists"
else 
    echo "File does not exist"
fi 
Run Code Online (Sandbox Code Playgroud)

测试表达可以通过使用被否定!操作者

#!/bin/bash
file=./file
if [ ! -e "$file" ]; then
    echo "File does not exist"
else 
    echo "File exists"
fi 
Run Code Online (Sandbox Code Playgroud)

  • 关于 -n:“一元运算符 -z 测试空字符串,而如果字符串不为空,则 -n 或根本不返回 True。” ~ http://www.ibm.com/developerworks/library/l -bash-测试/index.html (4认同)
  • @0x90 如果您愿意,您可以自由编辑我的帖子并将其添加到列表中。我猜你的意思是:`-n String` - 检查字符串的长度是否不为零。或者你的意思是 `file1 -nt file2` - 检查 file1 是否比文件 2 新(你也可以使用 -ot 来表示较旧的文件) (2认同)
  • 为什么没有添加像 function contains() { ⏎ if [ -e "$1" ]; 这样的函数 然后 echo "$1 存在" else echo "$1 不存在" fi } (2认同)

小智 283

你可以用"!"来否定表达式:

#!/bin/bash
FILE=$1

if [ ! -f "$FILE" ]
then
    echo "File $FILE does not exist"
fi
Run Code Online (Sandbox Code Playgroud)

相关的手册页是man test或者等效地man [- help test或者help [对于内置的bash命令.

  • @KeithThompson除了_bash_ builtin` [`有比我在系统上找到的外部命令`[`更多的开关...一般来说我认为最好阅读特定于给定工具的文档,而不是特定于另一个工具的文档模糊相关的.我可能错了,虽然`;)` (8认同)
  • 在[tag:bash]中,`[`是内置的.所以相关信息是通过`help [`...得到的...但是这表明```是`test`内置的同义词,因此相关信息是通过`help test`获得的.另请参阅手册中的[Bash条件表达式部分](http://www.gnu.org/software/bash/manual/bashref.html#Bash-Conditional-Expressions). (4认同)

gun*_*uns 130

[[ -f $FILE ]] || printf '%s does not exist!\n' "$FILE"
Run Code Online (Sandbox Code Playgroud)

此外,文件可能是破坏的符号链接,或非常规文件,例如套接字,设备或fifo.例如,要添加对损坏的符号链接的检查:

if [[ ! -f $FILE ]]; then
    if [[ -L $FILE ]]; then
        printf '%s is a broken symlink!\n' "$FILE"
    else
        printf '%s does not exist!\n' "$FILE"
    fi
fi
Run Code Online (Sandbox Code Playgroud)

  • 双括号是"现代"的延伸; 例如,他们不会进行单词拆分(例如带有空格的文件名),并且仍然适用于空字符串:http://mywiki.wooledge.org/BashFAQ/031 (29认同)
  • 我可以问为什么两个"["s在测试中?(例如[[!-a $ FILE]]).我尝试了在solaris盒子上提到的所有选项,只有那个工作,非常感激,但为什么呢? (9认同)
  • 根据http://tldp.org/LDP/abs/html/fto.html -a与-e的效果相同.它已被"弃用",并且不鼓励使用它.无论如何+1提及检查破损的符号链接 (7认同)
  • 我投了这个,因为它使用了[[.它是一种广泛使用的扩展.如果您知道您正在使用bash,那么没有理由不使用它.它比[更不容易出错]. (7认同)
  • @dimitrismistriotis two"["是由zsh&bash实现的(不同的)非便携式扩展; 一般来说,如果可能的话你应该避免它. (4认同)

Ela*_*ich 97

值得一提的是,如果你需要执行一个命令,你可以缩写

if [ ! -f "$file" ]; then
    echo "$file"
fi
Run Code Online (Sandbox Code Playgroud)

test -f "$file" || echo "$file"
Run Code Online (Sandbox Code Playgroud)

要么

[ -f "$file" ] || echo "$file"
Run Code Online (Sandbox Code Playgroud)


J. *_*ker 67

我更喜欢以POSIX shell兼容格式执行以下单行程序:

$ [ -f "/$DIR/$FILE" ] || echo "$FILE NOT FOUND"

$ [ -f "/$DIR/$FILE" ] && echo "$FILE FOUND"
Run Code Online (Sandbox Code Playgroud)

对于一些命令,就像我在脚本中所做的那样:

$  [ -f "/$DIR/$FILE" ] || { echo "$FILE NOT FOUND" ; exit 1 ;}
Run Code Online (Sandbox Code Playgroud)

一旦我开始这样做,我很少再使用完全类型化的语法!


SD.*_*SD. 53

要测试文件是否存在,参数可以是以下任何一个:

-e: Returns true if file exists (regular file, directory, or symlink)
-f: Returns true if file exists and is a regular file
-d: Returns true if file exists and is a directory
-h: Returns true if file exists and is a symlink
Run Code Online (Sandbox Code Playgroud)

以下所有测试都适用于常规文件,目录和符号链接:

-r: Returns true if file exists and is readable
-w: Returns true if file exists and is writable
-x: Returns true if file exists and is executable
-s: Returns true if file exists and has a size > 0
Run Code Online (Sandbox Code Playgroud)

示例脚本:

#!/bin/bash
FILE=$1

if [ -f "$FILE" ]; then
   echo "File $FILE exists"
else
   echo "File $FILE does not exist"
fi
Run Code Online (Sandbox Code Playgroud)


Jah*_*hid 36

你可以这样做:

[[ ! -f "$FILE" ]] && echo "File doesn't exist"
Run Code Online (Sandbox Code Playgroud)

要么

if [[ ! -f "$FILE" ]]; then
    echo "File doesn't exist"
fi
Run Code Online (Sandbox Code Playgroud)

如果要同时检查文件和文件夹,请使用-e选项代替-f.-e对常规文件,目录,套接字,字符特殊文件,块特殊文件等返回true.

  • 这不是特定于 bash 的。语法来自 Korn shell,在 zsh 和 bash 中也可用。不过,与标准的 `[` 实用程序相比,它的优势有限。 (2认同)
  • @StephaneChazelas:我在任何地方都没有看到任何 ksh 或 zsh 标签。我们谈论的是 bash 或大多数 UNIX 系统上标准化的东西。因此,在上下文中,它是特定于 bash 的。OP 不需要知道所有的 shell :D (2认同)

art*_*nil 33

你应该小心运行test一个不带引号的变量,因为它可能会产生意想不到的结果:

$ [ -f ]
$ echo $?
0
$ [ -f "" ]
$ echo $?
1
Run Code Online (Sandbox Code Playgroud)

建议通常是让测试变量用双引号括起来:

#!/bin/sh
FILE=$1

if [ ! -f "$FILE" ]
then
   echo "File $FILE does not exist."
fi
Run Code Online (Sandbox Code Playgroud)

  • 建议将**每个**变量用双引号括起来,除非你确切地知道你有一个罕见的情况是不必要的,或者是一个更罕见的情况,它是有害的.(不,这不是其中之一.) (8认同)
  • 我的意思是:这不是罕见的不必要或有害的案例之一.shell程序员应该习惯用双引号括起(几乎)每个变量; 这条规则不仅限于"[...]`. (4认同)

小智 22

有三种不同的方法可以做到这一点:

  1. 用bash否定退出状态(没有其他答案说过这个):

    if ! [ -e "$file" ]; then
        echo "file does not exist"
    fi
    
    Run Code Online (Sandbox Code Playgroud)

    要么:

    ! [ -e "$file" ] && echo "file does not exist"
    
    Run Code Online (Sandbox Code Playgroud)
  2. 否定测试命令中的测试[(这是之前大多数答案的方式):

    if [ ! -e "$file" ]; then
        echo "file does not exist"
    fi
    
    Run Code Online (Sandbox Code Playgroud)

    要么:

    [ ! -e "$file" ] && echo "file does not exist"
    
    Run Code Online (Sandbox Code Playgroud)
  3. 根据测试结果为负(||而不是&&):

    只要:

    [ -e "$file" ] || echo "file does not exist"
    
    Run Code Online (Sandbox Code Playgroud)

    这看起来很愚蠢(IMO),除非您的代码必须可移植到/bin/sh缺少管道否定operator(!)的Bourne shell(如Solaris 10或更早版本),否则不要使用它:

    if [ -e "$file" ]; then
        :
    else
        echo "file does not exist"
    fi
    
    Run Code Online (Sandbox Code Playgroud)

  • `![`[对于shell管道的POSIX 2.9.2(任何命令)](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_09_02)`否则,退出状态应为逻辑NOT最后一个命令的退出状态和`[!`[是POSIX for test](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html#tag_20_128)`!expression如果expression为false,则为true.如果表达式为真,则返回false.因此,两者都是POSIX,根据我的经验,两者都得到广泛支持. (3认同)

Ste*_*las 21

[ -f "$file" ]
Run Code Online (Sandbox Code Playgroud)

[命令对存储在其中的路径执行stat()(非lstat())系统调用,如果系统调用成功并且返回的文件类型为"regular" ,则$file返回truestat().

因此,如果[ -f "$file" ]返回true,则可以告诉文件确实存在,并且是常规文件或符号链接最终解析为常规文件(或者至少它是在当时stat()).

但是,如果它返回false(或者if [ ! -f "$file" ]! [ -f "$file" ]return true),则有许多不同的可能性:

  • 该文件不存在
  • 该文件存在但不是常规文件
  • 该文件存在,但您没有父目录的搜索权限
  • 该文件存在,但访问它的路径太长
  • 该文件是常规文件的符号链接,但您没有对符号链接解析中涉及的某些目录的搜索权限.
  • ... stat()系统调用可能失败的任何其他原因.

简而言之,它应该是:

if [ -f "$file" ]; then
  printf '"%s" is a path to a regular file or symlink to regular file\n' "$file"
elif [ -e "$file" ]; then
  printf '"%s" exists but is not a regular file\n' "$file"
elif [ -L "$file" ]; then
  printf '"%s" exists, is a symlink but I cannot tell if it eventually resolves to an actual file, regular or not\n' "$file"
else
  printf 'I cannot tell if "%s" exists, let alone whether it is a regular file or not\n' "$file"
fi
Run Code Online (Sandbox Code Playgroud)

要确定该文件不存在,我们需要stat()系统调用返回错误代码ENOENT(ENOTDIR告诉我们其中一个路径组件不是目录是另一种情况,我们可以告诉该文件不存在于那条道路上).不幸的是,[命令并没有让我们知道.无论错误代码是ENOENT,EACCESS(权限被拒绝),ENAMETOOLONG还是其他任何内容,它都将返回false.

[ -e "$file" ]测试也可以做ls -Ld -- "$file" > /dev/null.在这种情况下,ls会告诉你为什么stat()失败,虽然信息不能轻易地以编程方式使用:

$ file=/var/spool/cron/crontabs/root
$ if [ ! -e "$file" ]; then echo does not exist; fi
does not exist
$ if ! ls -Ld -- "$file" > /dev/null; then echo stat failed; fi
ls: cannot access '/var/spool/cron/crontabs/root': Permission denied
stat failed
Run Code Online (Sandbox Code Playgroud)

至少ls告诉我这不是因为文件不存在而失败了.这是因为它无法判断文件是否存在.该[命令只是忽略了这个问题.

使用zshshell,您可以$ERRNO在失败[命令后使用特殊变量查询错误代码,并使用模块中的$errnos特殊数组解码该数字zsh/system:

zmodload zsh/system
ERRNO=0
if [ ! -f "$file" ]; then
  err=$ERRNO
  case $errnos[err] in
    ("") echo exists, not a regular file;;
    (ENOENT|ENOTDIR)
       if [ -L "$file" ]; then
         echo broken link
       else
         echo does not exist
       fi;;
    (*) syserror -p "can't tell: " "$err"
  esac
fi
Run Code Online (Sandbox Code Playgroud)

(请注意$errnos,zsh在使用最新版本构建的某些版本时gcc,支持会被破坏).


kta*_*kta 18

envfile=.env

if [ ! -f "$envfile" ]
then
    echo "$envfile does not exist"
    exit 1
fi
Run Code Online (Sandbox Code Playgroud)


小智 10

要反转测试,请使用"!".这相当于其他语言中的"非"逻辑运算符.试试这个:

if [ ! -f /tmp/foo.txt ];
then
    echo "File not found!"
fi
Run Code Online (Sandbox Code Playgroud)

或以稍微不同的方式书写:

if [ ! -f /tmp/foo.txt ]
    then echo "File not found!"
fi
Run Code Online (Sandbox Code Playgroud)

或者您可以使用:

if ! [ -f /tmp/foo.txt ]
    then echo "File not found!"
fi
Run Code Online (Sandbox Code Playgroud)

或者,将所有人放在一起:

if ! [ -f /tmp/foo.txt ]; then echo "File not found!"; fi
Run Code Online (Sandbox Code Playgroud)

可以写入(使用"和"运算符:&&)作为:

[ ! -f /tmp/foo.txt ] && echo "File not found!"
Run Code Online (Sandbox Code Playgroud)

看起来像这样短:

[ -f /tmp/foo.txt ] || echo "File not found!"
Run Code Online (Sandbox Code Playgroud)


and*_*per 9

test事可算过.它适用于我(基于Bash Shell:检查文件是否存在):

test -e FILENAME && echo "File exists" || echo "File doesn't exist"
Run Code Online (Sandbox Code Playgroud)


Lem*_*azi 9

这段代码也有效.

#!/bin/bash
FILE=$1
if [ -f $FILE ]; then
 echo "File '$FILE' Exists"
else
 echo "The File '$FILE' Does Not Exist"
fi
Run Code Online (Sandbox Code Playgroud)


小智 6

最简单的方法

FILE=$1
[ ! -e "${FILE}" ] && echo "does not exist" || echo "exists"
Run Code Online (Sandbox Code Playgroud)


And*_*dré 6

有时使用 && 和 || 可能很方便 运营商。

就像在(如果你有命令“测试”):

test -b $FILE && echo File not there!
Run Code Online (Sandbox Code Playgroud)

或者

test -b $FILE || echo File there!
Run Code Online (Sandbox Code Playgroud)


Sim*_*ant 5

此Shell脚本也可用于在目录中查找文件:

echo "enter file"

read -r a

if [ -s /home/trainee02/"$a" ]
then
    echo "yes. file is there."
else
    echo "sorry. file is not there."
fi
Run Code Online (Sandbox Code Playgroud)

  • 尚不清楚这会添加其他答案尚未给出的任何内容。它对路径名进行硬编码。由于该问题被标记为[tag:bash],因此可以使用`read -p“ Enter file name:” -ra`来提示和阅读。它确实在变量周围使用引号;很好,但是应该解释。如果回显文件名可能会更好。然后检查文件是否存在并且不为空(这是-s的含义),而问题将询问是否存在任何文件为空(对于哪个文件,-f更合适)。 (3认同)