#!/bin/bash
FILE=$1
if [ -f $FILE ]; then
echo "File $FILE exists."
else
echo "File $FILE does not exist."
fi
如何只检查文件是否不存在?
test
命令(此处写作[
)具有“非”逻辑运算符!
(感叹号):
if [ ! -f /tmp/foo.txt ]; then
echo "File not found!"
fi
if [ ! \( -f "f1" -a -f "f2" \) ] ; then echo MISSING; fi
if [ ! -f "f1" ] || [ ! -f "f2" ] ; then echo MISSING; fi
- mivk/tmp/foo.txt
存在,那么什么也不做,否则输出"File not found!"。 - David W.-e: 如果文件存在,则返回真值
-f: 如果文件存在且是普通文件,则返回真值
-r: 如果文件存在且可读,则返回真值
-w: 如果文件存在且可写,则返回真值
-x: 如果文件存在且可执行,则返回真值
-d: 如果存在且是目录,则返回真值
- SD.!-f
与&&
以及使用-f
与||
时存在一种不对称性。这与非/存在检查返回的退出代码有关。如果您需要使您的行始终以退出代码0干净地退出(有时您可能不想要这个约束),则这两种方法不能互换。或者,只需使用一个if
语句,您就不再需要担心非/存在检查的退出代码。 - AsclepiusBash文件测试
-b filename
- 检查是否为块设备特殊文件
-c filename
- 检查是否为字符设备特殊文件
-d directoryname
- 检查目录是否存在
-e filename
- 检查文件是否存在,不考虑类型(节点、目录、套接字等)
-f filename
- 检查常规文件是否存在而非目录
-G filename
- 检查文件是否存在并且属于有效组ID
-G filename set-group-id
- 如果文件存在并设置了set-group-id,则为true
-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
-n String
- 检查字符串的长度是否不为零。或者您是指 file1 -nt file2
- 检查文件1是否比文件2更新(您也可以使用 -ot 来检查是否更旧)。 - BlueCacti-G
运算符,据我所知,这两者略有不同。根据chmod
手册中的“SETUID和SETGID位”部分,在root用户的情况下,这两个值会有所不同,不是吗?我特别指的是“除非用户具有适当的权限”部分。无论如何,回答非常好。因为这个问题,我会收藏它。 - Nate T!
对 test
中的表达式(对于该表达式,[
是其别名)取反:#!/bin/bash
FILE=$1
if [ ! -f "$FILE" ]
then
echo "File $FILE does not exist"
fi
相关的 man 手册是 man test
或等效地,man [
-- 或使用内置 bash 命令的 help test
或 help [
。
另外(不常用),您可以使用以下方式否定 test
的结果:
if ! [ -f "$FILE" ]
then
echo "File $FILE does not exist"
fi
该语法在“man 1 bash”中的“Pipelines”和“Compound Commands”章节中有描述。
[
是一个内置命令。因此,相关信息可以通过 help [
获得……但是这表明 [
是 test
内置命令的同义词,因此相关信息更适合通过 help test
来获取。另请参阅手册中的 Bash Conditional Expression 部分。 - gniourf_gniourf[
命令的行为与外部的[
命令非常相似,因此无论是man test
还是man [
都可以让你了解它的工作原理。 - Keith Thompson[
之外,bash 内置命令 [
还有更多的开关......一般来说,我认为阅读特定工具的文档比阅读另一个含糊相关的工具的文档更好。尽管我可能是错的 ;)
- gniourf_gniourf[[ -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
-a
选项,但也因为 -a
等同于 -e
,无论文件类型是否存在都会返回 true,在第二个示例中添加管道或套接字的检查时可能会遇到问题。 - ormaaj值得一提的是,如果您需要执行单个命令,您可以缩写
if [ ! -f "$file" ]; then
echo "$file"
fi
test -f "$file" || echo "$file"
或者[ -f "$file" ] || echo "$file"
A
为真,则在 A || B
中 B
是无关紧要的。 - sb813322我更喜欢使用以下一行代码,在POSIX兼容格式中:
$ [ -f "/$DIR/$FILE" ] || echo "$FILE NOT FOUND"
$ [ -f "/$DIR/$FILE" ] && echo "$FILE FOUND"
对于一些像在脚本中使用的命令:
$ [ -f "/$DIR/$FILE" ] || { echo "$FILE NOT FOUND" ; exit 1 ;}
一旦我开始这样做,我就很少再使用完全输入类型的语法了!!
[
或test
内置默认会测试参数的文件存在性(而不是-e
)?这不是含糊不清吗?据我所知(以及AIUI的“条件表达式”部分),你的方法只测试了参数不为空(或未定义),在这种情况下,这是一个重言(让$DIR =''
和$FILE =''
,那么参数仍然是'//'
)。 - PointedEarsls /foo
,结果为 ls: 无法访问 /foo: 没有那个文件或目录
。[ /foo ] && echo 42
,结果为 42
。GNU bash,版本 4.2.37(1)-release (i486-pc-linux-gnu)。 - PointedEars[ $condition ] && if_true || if_false
容易出错。无论如何,我发现[ ! -f "$file" ] && if_not_exists
比[ -f "$file" ] || if_not_exists
更易于阅读和理解。 - PointedEars要测试文件是否存在,参数可以是以下任意一个:
-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
[[ ! -f "$FILE" ]] && echo "File doesn't exist"
或者
if [[ ! -f "$FILE" ]]; then
echo "File doesn't exist"
fi
-e
选项而不是-f
。-e
对于普通文件、目录、套接字、字符特殊文件、块特殊文件等都返回true。[
工具相比并没有太多优势。 - Stephane Chazelas[ -e
将测试文件是否存在(包括常规、FIFO、目录等任何类型),在符号链接解析之后。 - Stephane Chazelas-e
,他需要-f
。 - Jahid你需要注意对未加引号的变量运行test
命令,因为它可能会产生意外结果:
$ [ -f ]
$ echo $?
0
$ [ -f "" ]
$ echo $?
1
通常建议将被测试的变量用双引号括起来:
#!/bin/sh
FILE=$1
if [ ! -f "$FILE" ]
then
echo "File $FILE does not exist."
fi
在
[ -f "$file" ]
[
命令对存储在$file
中的路径执行stat()
(而不是lstat()
)系统调用,并且如果该系统调用成功并且stat()
返回的文件类型为“regular”,则返回true。
因此,如果[ -f "$file" ]
返回true,则可以确定该文件确实存在且是普通文件或最终解析为普通文件的符号链接(或者至少在stat()
的时间上是这样)。
但是,如果它返回false(或者[ ! -f "$file" ]
或! [ -f "$file" ]
返回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
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
至少ls
告诉我它失败不是因为文件不存在,而是因为它无法确定文件是否存在。 [
命令只是忽略了这个问题。
使用zsh
shell,在失败的[
命令之后,您可以使用$ERRNO
特殊变量查询错误代码,并使用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;;
(*) syserror -p "can't tell: " "$err"
esac
fi
(请注意,当使用最新版本的gcc
构建时,$errnos
支持与某些版本的zsh
存在故障。)
if [ -f $FILE ]; then; else; echo "File $FILE does not exist."; fi;
很幸运我找到了这个问题,学会了一种更合适的方法。 :) (备注:已经翻译成中文) - Alderath-e
。-f
无法识别目录、符号链接等。 - BenubirdFILE=$1
->FILE="$1"
和if [ -f $FILE ];
->if [ -f "$FILE" ];
。 - kevinarpe