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

问题描述:

这将检查文件是否存在:

#!/bin/bash

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

我如何只检查文件是否不存在?

解决方案1:

一个优秀的自由职业者,应该有对需求敏感和精准需求捕获的能力,而huntsbot.com提供了这个机会

test 命令(此处写为 [)有一个“非”逻辑运算符 !(感叹号):

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

更简洁:[! -f /tmp/foo.txt ] && echo "找不到文件!"

我努力为“如果两个文件中的任何一个不存在”找到正确的语法。以下两者都有效:if [ ! \( -f "f1" -a -f "f2" \) ] ; then echo MISSING; fi if [ ! -f "f1" ] || [ ! -f "f2" ] ; then echo MISSING; fi

@DavidWinterbottom 更加多汁:[ -f /tmp/foo.txt ] || echo "File not found!"

参数可以是以下任意一项:-e: Returns true value, if file exists -f: Return true value, if file exists and regular file -r: Return true value, if file exists and is readable -w: Return true value, if file exists and is writable -x: Return true value, if file exists and is executable -d: Return true value, if exists and is a directory

将 ! -f 与 && 一起使用与将 -f 与 || 一起使用存在不对称性。这与不/存在检查返回的退出代码有关。如果您需要您的线路始终以退出代码 0 干净地退出(有时您不希望此约束),则这两种方法不可互换。或者,只需使用 if 语句,您就不必再担心不/存在检查的退出代码。

解决方案2:

HuntsBot周刊–不定时分享成功产品案例,学习他们如何成功建立自己的副业–huntsbot.com

Bash 文件测试

-b filename - 阻止特殊文件 -c filename - 特殊字符文件 -d directoryname - 检查目录是否存在 -e filename - 检查文件是否存在,无论类型如何(节点、目录、套接字、等) -f filename - 检查常规文件是否存在而不是目录 -G filename - 检查文件是否存在并由有效组 ID 拥有 -G filename set-group-id - 如果文件存在且已设置则为真-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 

@0x90 如果需要,您可以自由编辑我的帖子并将其添加到列表中。我猜你的意思是:-n String - 检查字符串的长度是否不为零。还是您的意思是 file1 -nt file2 - 检查文件 1 是否比文件 2 新(您也可以使用 -ot 表示较旧的)

关于-n:The unary operator -z tests for a null string, while -n or no operator at all returns True if a string is not empty. ~ ibm.com/developerworks/library/l-bash-test/index.html

为什么有些人不添加类似 function exists() { ⏎ if [ -e "$1" ];然后 echo "$1 存在" else echo "$1 不存在" fi }

@MzA 因为我们需要使代码可读,没有人知道 $1 是什么。因此,将 $1 分配为 file,然后使用该 file 变量执行其他看起来比使用未知参数 $1 更具可读性的事情

关于 -G 运算符,据我了解,两者略有不同。通过 chmod 手册页的“SETUID & SETGID BITS”部分,两者在 root 用户的情况下会给出不同的值,不是吗?我专门指的是“除非用户具有适当的权限”部分。无论如何,出色的答案。仅为此添加书签。

解决方案3:

huntsbot.com汇聚了国内外优秀的初创产品创意,可按收入、分类等筛选,希望这些产品与实践经验能给您带来灵感。

使用 ! 否定 test 内的表达式([ 是别名):

#!/bin/bash
FILE=$1

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

对于内置 bash 命令,相关的手册页是 man test 或等效的 man [ – 或 help test 或 help [。

或者(不太常用)您可以使用以下命令否定 test 的结果:

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

该语法在“管道”和“复合命令”部分的“man 1 bash”中进行了描述。

在 bash 中,[ 是内置的。所以相关信息宁可通过 help [ 获得...但这表明 [ 是 test 内置函数的同义词,因此相关信息宁可通过 help test 获得。另见Bash Conditional Expression section in the manual。

@gniourf_gniourf:是的,但是 bash 内置 [ 命令的行为与外部 [ 命令非常相似,因此 man test 或 man [ 可以让您很好地了解它的工作原理。

@KeithThompson 除了 bash 内置 [ 具有比我系统上的外部命令 [ 更多的开关...一般来说,我认为最好阅读特定于给定工具的文档,而不是特定于另一个模糊相关的文档。我可能错了,虽然;)

解决方案4:

huntsbot.com提供全网独家一站式外包任务、远程工作、创意产品分享与订阅服务!

[[ -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 $FILE ]])。我尝试了solaris box上提到的所有选项,只有一个有效,非常感谢,但为什么呢?

双括号是“现代”扩展;例如,它们不会进行分词(例如对于带有空格的文件名)并且仍然适用于空字符串:mywiki.wooledge.org/BashFAQ/031

根据tldp.org/LDP/abs/html/fto.html -a 与 -e 效果相同。它已被“弃用”,不鼓励使用。无论如何+1也提到检查损坏的符号链接

@dimitrismistriotis 两个“[”是由 zsh 和 bash 实现(不同)的非便携式扩展;一般来说,如果可能的话,你应该避免它。

请参阅 SO 321348 了解为什么不能在单括号条件表达式中否定 -a 的充分理由。我建议完全避免使用 -a。

解决方案5:

huntsbot.com – 高效赚钱,自由工作

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

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

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

或者

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

谢谢!需要一个不使用 [[ ]] 的替代方案

解决方案6:

huntsbot.com提供全网独家一站式外包任务、远程工作、创意产品分享与订阅服务!

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

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

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

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

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

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

首先,未加引号的变量引用容易出错。也就是说,它在 any bash 手册页中的什么地方说 [ 或 test 内置默认情况下会测试参数的 file 存在(相反-e)?这不会模棱两可吗? AFAIK(和 AIUI 的“条件表达式”部分)唯一用您的方法测试的是参数不为空(或未定义),在这种情况下,这是一个重言式(让 $DIR = '' 和 $FILE = '' , 那么参数仍然是 '//')。

证明:ls /foo,结果 ls: cannot access /foo: No such file or directory。 [ /foo ] && echo 42,结果 42。 GNU bash,版本 4.2.37(1)-release (i486-pc-linux-gnu)。

@PointedEars:在我写这个答案的那一刻,我没有指定 -f 选项。显然,如果您不确定它是否是常规文件,您总是可以使用 -e。此外,在我所有的脚本中,我都引用了这些结构,我一定只是在没有充分校对的情况下提交了这个。

确认。但是您可能知道单行无法解决 if-else 问题:[ $condition ] && if_true || if_false 容易出错。无论如何,我发现 [ ! -f "$file" ] && if_not_exists 比 [ -f "$file" ] || if_not_exists 更容易阅读和理解。

解决方案7:

HuntsBot周刊–不定时分享成功产品案例,学习他们如何成功建立自己的副业–huntsbot.com

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

-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

解决方案8:

huntsbot.com提供全网独家一站式外包任务、远程工作、创意产品分享与订阅服务!

你可以这样做:

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

或者

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

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

这不是特定于 bash 的。该语法来自 Korn shell,也可用于 zsh 和 bash。不过,与此处的标准 [ 实用程序相比,它的优势有限。

常规文件(由-f检查)和目录只是许多不同类型的文件中的两种。还有套接字、符号链接、设备、fifos、门... [ -e 将测试文件是否存在(任何类型,包括常规、fifo、目录...)在符号链接解析后。

@StephaneChazelas:我在任何地方都看不到任何 ksh 或 zsh 标签。我们谈论的是 bash 或在大多数 unix 系统上标准化的东西。因此,在上下文中,它是特定于 bash 的。 OP 不需要知道外面的所有外壳:D

那是对您答案的“特定于 Bash”部分的评论。

@StephaneChazelas:是的,在上下文中(bash 和标准 sh),它是特定于 bash 的。我在您的第二条评论中看不到重点,这完全脱离了上下文。 OP 不需要 -e,他需要 -f。

解决方案9:

huntsbot.com精选全球7大洲远程工作机会,涵盖各领域,帮助想要远程工作的数字游民们能更精准、更高效的找到对方。

您应该小心为未引用的变量运行 test,因为它可能会产生意想不到的结果:

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

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

#!/bin/sh
FILE=$1

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

建议将每个变量都用双引号括起来,除非您确切知道您有一种不必要的罕见情况,或者是有害的更罕见情况之一。 (不,这不是其中之一。)

您是否愿意详细说明为什么不使用双引号?否则我看不到评论的用处。

我的意思是:这不是少数不必要或有害的情况之一。 shell 程序员应该习惯于(几乎)用双引号将每个变量括起来;此规则不限于 [ ... ]。

另请参阅stackoverflow.com/questions/10067266/…

解决方案10:

保持自己快人一步,享受全网独家提供的一站式外包任务、远程工作、创意产品订阅服务–huntsbot.com

[ -f "$file" ]

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

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

但是,如果它返回 false(或者如果 [ ! -f “ f i l e " ] 或 ! [ − f " file" ] 或 ! [ -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() 系统调用以返回错误代码 ENOENT(ENOTDIR 告诉我们其中一个路径组件不是目录是另一种情况我们可以通过该路径告诉文件不存在)。不幸的是,[ 命令并没有让我们知道这一点。无论错误代码是 ENOENT、EACCESS(权限被拒绝)、ENAMETOOLONG 还是其他任何内容,它都会返回 false。

[ -e “ f i l e " ] 测 试 也 可 以 用 l s − L d − − " file" ] 测试也可以用 ls -Ld -- " file"]lsLd"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

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

解决方案11:

huntsbot.com聚合了超过10+全球外包任务平台的外包需求,寻找外包任务与机会变的简单与高效。

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

用 bash 否定退出状态(没有其他答案这么说):如果! [ -e “ f i l e " ] ; 然 后 回 显 “ 文 件 不 存 在 ” f i 或 : ! [ − e " file" ];然后回显“文件不存在” fi 或:! [ -e " file"];fi[e"file” ] && echo “file does not exist” 在测试命令 [ 中否定测试(这是之前大多数答案的呈现方式): if [ ! -e “ 文 件 " ] ; 然 后 回 显 “ 文 件 不 存 在 ” f i 或 : [ ! − e " 文件" ];然后回显“文件不存在” fi 或:[! -e " "];fi[e"file” ] && echo “file does not exist” 对测试结果是否定的(|| 代替 &&)进行处理:仅: [ -e “ f i l e " ] ∣ ∣ e c h o " f i l e d o e s n o t e x i s t " 这 看 起 来 很 傻 ( I M O ) , 除 非 您 的 代 码 必 须 可 移 植 到 缺 少 管 道 否 定 运 算 符 的 B o u r n e s h e l l ( 如 S o l a r i s 10 或 更 早 版 本 的 / b i n / s h ) , 否 则 不 要 使 用 它 ( ! ) : i f [ − e " file" ] || echo "file does not exist" 这看起来很傻(IMO),除非您的代码必须可移植到缺少管道否定运算符的 Bourne shell(如 Solaris 10 或更早版本的 /bin/sh),否则不要使用它( !): if [ -e " file"]echo"filedoesnotexist"IMOBourneshellSolaris10/bin/sh使!):if[e"file” ];然后:否则回显“文件不存在”fi

! [ 和 [ ! 之间的可移植性有何不同?

! [ is POSIX for shell pipelines 2.9.2 (any command) Otherwise, the exit status shall be the logical NOT of the exit status of the last command 和 [ ! is POSIX for test ! expression True if expression is false. False if expression is true. 因此,它们都是 POSIX,并且根据我的经验,它们都得到了广泛的支持。

@FrozenFlame,Bourne shell 没有 Korn shell 引入的 ! 关键字。不过,除了 Solaris 10 和更早版本,您现在不太可能遇到 Bourne shell。

原文链接:https://www.huntsbot.com/qa/Yl4K/how-do-i-tell-if-a-regular-file-does-not-exist-in-bash?lang=zh_CN

huntsbot.com – 程序员副业首选,一站式外包任务、远程工作、创意产品分享订阅平台。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值