如何判断bash中是否不存在文件?

 2019-04-20 

How do I tell if a regular file does not exist in Bash?

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

1
2
3
4
5
6
7
8
#!/bin/bash

FILE=$1    
if [ -f $FILE ]; then
   echo"File $FILE exists."
else
   echo"File $FILE does not exist."
fi

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

1
2
3
4
5
6
#!/bin/bash

FILE=$1    
if [ $FILE does not exist ]; then
   echo"File $FILE does not exist."
fi


test命令(这里是[)有一个"not"逻辑运算符,它是感叹号(类似于许多其他语言)。试试这个:

1
2
3
if [ ! -f /tmp/foo.txt ]; then
    echo"File not found!"
fi


bash文件测试

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

如何使用:

1
2
3
4
5
6
7
#!/bin/bash
file=./file
if [ -e"$file" ]; then
    echo"File exists"
else
    echo"File does not exist"
fi

使用!运算符可以否定测试表达式。

1
2
3
4
5
6
7
#!/bin/bash
file=./file
if [ ! -e"$file" ]; then
    echo"File does not exist"
else
    echo"File exists"
fi


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

1
2
3
4
5
6
7
#!/bin/bash
FILE=$1

if [ ! -f"$FILE" ]
then
    echo"File $FILE does not exist"
fi

相关的手册页是用于内置bash命令的man test或等效的man [help testhelp [


1
2
[[ -f $FILE ]] || printf '%s does not exist!
'
"$FILE"

此外,该文件可能是一个断开的符号链接,或者是一个非常规文件,例如套接字、设备或FIFO。例如,要添加对断开符号链接的检查:

1
2
3
4
5
6
7
8
9
if [[ ! -f $FILE ]]; then
    if [[ -L $FILE ]]; then
        printf '%s is a broken symlink!
'
"$FILE"
    else
        printf '%s does not exist!
'
"$FILE"
    fi
fi


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

1
2
3
if [ ! -f"$file" ]; then
    echo"$file"
fi

1
test -f"$file" || echo"$file"

1
[ -f"$file" ] || echo"$file"


我更喜欢使用与posix shell兼容的格式执行以下一行程序:

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

$ [ -f"/$DIR/$FILE" ] && echo"$FILE FOUND"

对于几个命令,就像在脚本中一样:

1
$ [ -f"/$DIR/$FILE" ] || { echo"$FILE NOT FOUND" ; exit 1 ;}

一旦我开始这样做,我就很少使用完整类型的语法了!!


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

1
2
3
4
-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

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

1
2
3
4
-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

示例脚本:

1
2
3
4
5
6
7
8
#!/bin/bash
FILE=$1

if [ -f"$FILE" ]; then
   echo"File $FILE exists"
else
   echo"File $FILE does not exist"
fi


您可以这样做:

1
[[ ! -f"$FILE" ]] && echo"File doesn't exist"

1
2
3
if [[ ! -f"$FILE" ]]; then
    echo"File doesn't exist"
fi

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


对于不带引号的变量运行test时应该小心,因为它可能会产生意外的结果:

1
2
3
4
5
6
$ [ -f ]
$ echo $?
0
$ [ -f"" ]
$ echo $?
1

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

1
2
3
4
5
6
7
#!/bin/sh
FILE=$1

if [ ! -f"$FILE" ]
then
   echo"File $FILE does not exist."
fi


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

  • 用bash否定退出状态(没有其他答案这样说):

    1
    2
    3
    if ! [ -e"$file" ]; then
        echo"file does not exist"
    fi

    或:

    1
    ! [ -e"$file" ] && echo"file does not exist"
  • 否定测试命令[中的测试(这是之前给出的大多数答案的方式):

    1
    2
    3
    if [ ! -e"$file" ]; then
        echo"file does not exist"
    fi

    或:

    1
    [ ! -e"$file" ] && echo"file does not exist"
  • 根据试验结果为阴性(||而不是&&进行试验):

    只有:

    1
    [ -e"$file" ] || echo"file does not exist"

    这看起来很愚蠢(imo),除非您的代码必须可移植到Bourne Shell(如Solaris 10或更早版本的/bin/sh),而缺少管道否定运算符(!)。

    1
    2
    3
    4
    5
    if [ -e"$file" ]; then
        :
    else
        echo"file does not exist"
    fi

  • 在 </P >

    1
    [ -f"$file" ]

    [命令不一stat()(不lstat())的系统调用的路径可存储在$file时返回true,如果和系统调用succeeds和类型的文件为returned用stat()是"正常的"。 </P >

    所以,如果[ -f"$file" ]时返回true,你可以告诉该文件是否存在和是一个正常的文件或一个符号,一个正则正则resolving文件(或至少是在时间的stat())。 </P >

    但是如果它时返回false(或如果[ ! -f"$file" ]! [ -f"$file" ]返回true),是有很多不同的可能性: </P >

    • 该文件不存在。
    • 在file exists,但是,是不是一个正常的文件(可以是一个设备,先进先出(FIFO),目录,插座…………………)
    • 在file exists,但你没有搜索到父目录的权限
    • "但那file exists路径来访问它是太长
    • 该文件是一个符号,一个正常的文件,但你没有寻找到一些权限的目录参与的分辨率的符号。
    • …………………任何其他的理由,如《stat()系统调用可能失败。

    在短的,它应该是: </P >

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    if [ -f"$file" ]; then
      printf '"%s" is a path to a regular file or symlink to regular file
    '
    "$file"
    elif [ -e"$file" ]; then
      printf '"%s" exists but is not a regular file
    '
    "$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
    '
    "$file"
    else
      printf 'I cannot tell if"%s" exists, let alone whether it is a regular file or not
    '
    "$file"
    fi

    知道这悲伤的方法中的文件不存在的,我们会需要的stat()系统调用与返回的错误代码ENOENT(美国的一个ENOTDIRtells的多径分量的是不是一个目录是在另一个案例,我们可以告诉该文件不存在,通过T路径)。不幸的[T命令不让我们知道。它将返回错误代码中的错误是否是enoent,eaccess(权限拒绝enametoolong),或任何其他的。 </P >

    [ -e"$file" ]试验也可以被用做ls -Ld --"$file"> /dev/null。。。。。。。在这情况下,ls会告诉你为什么在stat()失败,虽然在信息不易被用于以编程方式: </P >

    1
    2
    3
    4
    5
    6
    $ 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

    至少lstells我们这不是因为文件不存在,它fails T。。。。。。。这是因为它不能告诉是否在file exists或不。在[命令是不容忽视的问题。 </P >

    zsh壳,你可以查询中的错误代码与$ERRNO特殊变量在书中[命令,和解码-12864LCD那号码使用$errnos特殊阵列中的zsh/system模块: </P >

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    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

    (beware的$errnos支持是破碎的版本与一些大学本科zsh当与最近的版本中gcc)。 </P >


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

    1
    2
    3
    4
    if [ ! -f /tmp/foo.txt ];
    then
        echo"File not found!"
    fi

    或者用稍微不同的方式写:

    1
    2
    3
    if [ ! -f /tmp/foo.txt ]
        then echo"File not found!"
    fi

    或者你可以使用:

    1
    2
    3
    if ! [ -f /tmp/foo.txt ]
        then echo"File not found!"
    fi

    或者,一起预测:

    1
    if ! [ -f /tmp/foo.txt ]; then echo"File not found!"; fi

    可写为(使用then"和"operator:&;&;)如下:

    1
    [ ! -f /tmp/foo.txt ] && echo"File not found!"

    看起来比这短:

    1
    [ -f /tmp/foo.txt ] || echo"File not found!"

    此代码也有效。

    1
    2
    3
    4
    5
    6
    7
    #!/bin/bash
    FILE=$1
    if [ -f $FILE ]; then
     echo"File '$FILE' Exists"
    else
     echo"The File '$FILE' Does Not Exist"
    fi

    江户十一〔五〕事也算在内。它对我有效(基于bash shell:检查文件是否存在):

    1
    test -e FILENAME && echo"File exists" || echo"File doesn't exist"

    最简单的方法

    1
    2
    FILE=$1
    [ ! -e"${FILE}" ] && echo"does not exist" || echo"exists"

    此shell脚本还可用于在目录中查找文件:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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


    有时它可能会得心应手的使用&;&;和| |经营者。 </P >

    状细胞(如果你已经命令"测试"): </P >

    1
    test -b $FILE && echo File not there!

    或 </P >

    1
    test -b $FILE || echo File there!