如何判断Bash中是否存在常规文件?
我已经使用以下脚本来查看文件是否存在:
#!/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
testing命令( [
这里]有一个“不”)逻辑运算符,这是感叹号(类似于许多其他语言)。 尝试这个:
if [ ! -f /tmp/foo.txt ]; then echo "File not found!" fi
Bash文件testing
-b filename
– 阻止特殊文件
-c filename
– 特殊字符文件
-d directoryname
– 检查目录是否存在
-e filename
– 检查文件是否存在,无论types(节点,目录,套接字等)
-f filename
– 检查常规文件存在不是一个目录
-G filename
– 检查文件是否存在,是否被有效的组ID所拥有
-G filename set-group-id
– 如果文件存在并且是set-group-id,则为真
-k filename
– 粘性位
-L filename
– 符号链接
-O filename
– 如果文件存在并由有效用户标识拥有,则为true
-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
testingexpression式可以通过使用!
操作者
#!/bin/bash file=./file if [ ! -e "$file" ]; then echo "File does not exist" else echo "File exists" fi
你可以用“!”否定expression式:
#!/bin/bash FILE=$1 if [ ! -f "$FILE" ] then echo "File $FILE does not exist" fi
相关的手册页是man test
或者等同于man [
– 或help test
或help [
为内置的bash命令。
[[ -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
值得一提的是,如果你需要执行一个单一的命令,你可以缩写
if [ ! -f "$file" ]; then echo "$file" fi
至
test -f "$file" || echo "$file"
要么
[ -f "$file" ] || echo "$file"
我更喜欢用POSIX兼容的格式来完成下面的一行代码:
$ [ -f "/$DIR/$FILE" ] || echo "$FILE NOT FOUND" $ [ -f "/$DIR/$FILE" ] && echo "$FILE FOUND"
对于一些命令,就像我在脚本中所做的那样:
$ [ -f "/$DIR/$FILE" ] || { echo "$FILE NOT FOUND" ; exit 1 ;}
一旦我开始这样做,我很less再使用完全types的语法!
要testing文件的存在,参数可以是以下任何一个:
-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
以下所有testing适用于常规文件,目录和符号链接:
-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
您应该小心运行未引用的variables的test
,因为它可能会产生意外的结果:
$ [ -f ] $ echo $? 0 $ [ -f "" ] $ echo $? 1
build议通常是将testingvariables包围在双引号内:
#!/bin/sh FILE=$1 if [ ! -f "$FILE" ] then echo "File $FILE does not exist." fi
有三种不同的方式来做到这一点:
-
用bash取消退出状态(没有其他答案说过这个):
if ! [ -e "$file" ]; then echo "file does not exist" fi
要么:
! [ -e "$file" ] && echo "file does not exist"
-
在testing命令内部否定testing
[
(这是大多数人在回答之前的答案):if [ ! -e "$file" ]; then echo "file does not exist" fi
要么:
[ ! -e "$file" ] && echo "file does not exist"
-
对testing结果采取负面行动(而不是
&&
):只要:
[ -e "$file" ] || echo "file does not exist"
这看起来很傻(IMO),不要使用它,除非你的代码必须可移植到缺lesspipe道否定运算符(
!
)的Bourne shell(如Solaris 10或更早版本的/bin/sh
):if [ -e "$file" ]; then : else echo "file does not exist" fi
要反转testing,请使用“!”。 这相当于其他语言中的“不”逻辑运算符。 尝试这个:
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!"
test
东西也可以算。 它为我工作(基于Bash Shell:检查文件是否存在 ):
test -e FILENAME && echo "File exists" || echo "File doesn't exist"
这个代码也工作。
#!/bin/bash FILE=$1 if [ -f $FILE ]; then echo "File '$FILE' Exists" else echo "The File '$FILE' Does Not Exist" fi
在
[ -f "$file" ]
[
命令对存储在$file
的path执行stat()
(不是lstat()
)系统调用,如果系统调用成功并且stat()
返回的文件types为“regular”,则返回true 。
因此,如果[ -f "$file" ]
返回true,那么可以告诉文件确实存在,并且是普通文件或符号链接,最终parsing为常规文件(或者至less在stat()
)。
但是,如果它返回false (或者如果[ ! -f "$file" ]
或! [ -f "$file" ]
返回true),则有许多不同的可能性:
- 该文件不存在
- 该文件存在,但不是一个普通的文件
- 该文件存在但您没有对父目录的search权限
- 该文件存在,但访问它的path太长
- 该文件是一个常规文件的符号链接,但是您不具有对符号链接parsing中涉及的某些目录的search权限。
- …为什么
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()
系统调用返回一个错误代码ENOENT
( ENOTDIR
告诉我们其中一个path组件不是一个目录是另一种情况,我们可以告诉该文件不存在该path)。 不幸的是,这个命令并不让我们知道。 无论错误代码是ENOENT,EACCESS(权限被拒绝),ENAMETOOLONG还是别的,它都会返回false。
[ -e "$file" ]
testing也可以用ls -Ld -- "$file" > /dev/null
。 在这种情况下, ls
会告诉你为什么stat()
失败,尽pipe信息不能以编程方式使用:
$ 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
至lessls
告诉我,这不是因为该文件不存在,它失败了。 这是因为它不能分辨文件是否存在。 [
命令刚刚忽略了这个问题。
通过zsh
shell,你可以在失败的命令后用$ERRNO
特殊variables查询错误代码,并使用zsh/system
模块中的$errnos
特殊数组来解码该数字:
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;; (*) echo "can't tell"; syserror "$err" esac fi
(注意, 当使用最新版本的gcc
构build时 , $errnos
支持已经被zsh
某些版本所破坏 )。
你可以使用特定的Bash:
[[ ! -f "$FILE" ]] && echo "File doesn't exist"
要么
if [[ ! -f "$FILE" ]]; then echo "File doesn't exist" fi
如果要检查文件和文件夹,则使用-e
选项而不使用-f
。
最简单的方法
FILE=$1 [ ! -e "${FILE}" ] && echo "does not exist" || echo "exists"
这个shell脚本也适用于在目录中查找文件:
echo "enter file" read -ra if [ -s /home/trainee02/"$a" ] then echo "yes. file is there." else echo "sorry. file is not there." fi
有时使用&&和||可能会很方便 运营商。
像在(如果你有命令“testing”):
test -b $FILE && echo File not there!
要么
test -b $FILE || echo File there!