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

时间:2009-03-12 14:48:43

标签: bash file-io scripting

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

#!/bin/bash

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

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

#!/bin/bash

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

20 个答案:

答案 0 :(得分:4122)

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

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

答案 1 :(得分:574)

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 - 检查文件是否为非零大小
-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 

使用!运算符

可以取消测试表达式
#!/bin/bash
file=./file
if [ ! -e "$file" ]; then
    echo "File does not exist"
else 
    echo "File exists"
fi 

答案 2 :(得分:273)

您可以使用“!”来否定表达式:

#!/bin/bash
FILE=$1

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

内置bash命令的相关联机帮助页面为man test或等效man [ - 或help testhelp [

答案 3 :(得分:126)

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

此外,该文件可能是破损的符号链接,或非常规文件,例如,套接字,设备或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

答案 4 :(得分:89)

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

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

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

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

答案 5 :(得分:63)

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

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

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

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

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

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

答案 6 :(得分:48)

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

-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

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

-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

示例脚本:

#!/bin/bash
FILE=$1

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

答案 7 :(得分:33)

你可以这样做:

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

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

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

答案 8 :(得分:30)

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

$ [ -f ]
$ echo $?
0
$ [ -f "" ]
$ echo $?
1

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

#!/bin/sh
FILE=$1

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

答案 9 :(得分:21)

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

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

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

    或者:

    ! [ -e "$file" ] && echo "file does not exist"
    
  2. 取消测试命令[内的测试(这是之前大多数答案的方式):

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

    或者:

    [ ! -e "$file" ] && echo "file does not exist"
    
  3. 对测试结果采取否定行为(||而不是&&):

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

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

    !

答案 10 :(得分:19)

[ -f "$file" ]

[命令对存储在stat()中的路径执行lstat()(非$file)系统调用,如果该系统返回 true 调用成功,stat()返回的文件类型为“常规”。

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

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

  • 该文件不存在
  • 该文件存在,但不是常规文件(可能是设备,fifo,目录,套接字......)
  • 该文件存在,但您没有对父目录的搜索权限
  • 文件存在,但访问它的路径太长
  • 该文件是常规文件的符号链接,但您没有对符号链接解析中涉及的某些目录的搜索权限。
  • ... 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

要确定该文件不存在,我们需要stat()系统调用才能返回错误代码ENOENTENOTDIR告诉我们其中一个路径组件不是目录是我们可以通过该路径告诉该文件不存在的另一种情况)。不幸的是[命令不让我们知道。无论错误代码是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

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

使用zsh shell,您可以在失败的$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

(小心$errnos support was broken with some versions of zsh when built with recent versions of gcc)。

答案 11 :(得分:10)

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

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

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

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

或者您可以使用:

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

或者,共同主张:

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

可以写成(使用“和”运算符:&&)作为:

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

看起来像这样短:

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

答案 12 :(得分:9)

此代码也有效。

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

答案 13 :(得分:8)

test事情也可能算在内。它对我有用(基于 Bash Shell: Check File Exists or Not ):

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

答案 14 :(得分:6)

最简单的方法

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

答案 15 :(得分: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

答案 16 :(得分:3)

有时使用&&和和||运算符。

喜欢(如果你有命令“test”):

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

test -b $FILE || echo File there!

答案 17 :(得分:1)

如果要使用test而不是[],则可以使用!取反:

if ! test "$FILE"; then
  echo "does not exist"
fi

答案 18 :(得分:0)

您还可以在一个衬里中组合多个命令

[ -f "filename" ] || ( echo test1 && echo test2 && echo test3 )

[ -f "filename" ] || { echo test1 && echo test2 && echo test3 ;}

如果没有退出文件名,则输出为

test1
test2
test3

注意:(...)在子shell中运行,{...;}在同一shell中运行。大括号表示法仅适用于bash。

答案 19 :(得分:0)

envfile=.env

if [ ! -f "$envfile" ]
then
    echo "$envfile does not exist"
    exit 1
fi