【问题标题】:Combining two negated file check conditions (-f and -s) seems to return incorrect result结合两个否定的文件检查条件(-f 和 -s)似乎返回不正确的结果
【发布时间】:2019-07-03 13:12:56
【问题描述】:

我想检查一个文件是否是一个文件并且存在以及它是否不为空,所以最终使用-f-s 的组合检查。如果文件不存在或为空,我想提前返回,所以我否定这两​​项检查。

为了测试我的文件名返回空字符串并且我将路径传递到目录的情况,我正在尝试这样做:

if [[ ! -f "/path/to/dir/" ]] && [[ ! -s "/path/to/dir/" ]]; 
then  echo "Does not exists"; else echo "Exists"; fi

存在

Above 返回 'Exist' 似乎不正确。

-f单独检查是正确的:

if [[ ! -f "/path/to/dir/" ]]; then  echo "Does not exists"; 
else echo "Exists"; fi

不存在

合并检查但不否定每个检查也是正确的:

if [[ -f "/path/to/dir/" ]] && [[ -s "/path/to/dir/" ]]; 
then  echo "Exists"; else echo "Does not exists"; fi

不存在

不确定在将否定条件与逻辑和 && 结合使用时,我是否做错了什么,或者 Bash 中是否有一些奇怪之处?

编辑 1: 正如建议的那样,尝试使用两个条件都在同一组括号中的符号:

if [[ ! -f "/opt/gmdemea/smartmap_V2/maps/" && ! -s "/opt/gmdemea/smartmap_V2/maps/" ]]; then  echo "Does not exists"; else echo "Exists"; fi

存在

但这不会改变行为。

编辑 2: 从手册页看来,在这种情况下-s 应该足够了,但是当传递现有目录路径时,它返回 true(Bash 版本:4.1.2(1)-release):

if [[ -s "/opt/gmdemea/smartmap_V2/maps/" ]]; then echo "Exists"; else echo "Does not exists"; fi 

存在

它在不是文件时返回“存在”,所以应该去 else 子句返回“不存在”

【问题讨论】:

  • 请阅读De Morgan's law
  • 对于目录,您可能应该使用if [[ ! -d "/path/to/dir/" ]]

标签: linux bash


【解决方案1】:

拥有x AND y,然后对其进行唠叨你会得到:NOT (x AND y)。这等于(NOT a) OR (NOT b)。它等于(NOT x) AND (NOT y)

我想检查一个文件是否是一个文件并且存在,如果它不为空

如果你想检查一个文件是否是一个普通文件并且它是否不为空,那么你可以这样做:

[[ -f path ]] && [[ -s path ]]

否定是(每行相等)(注意De Morgan's law):

! ( [[ -f path ]] && [[ -s path ]] )
[[ ! -f path || ! -s path ]]

你也可以写成(每行相等):

! [[ -f path && -s path ]]
[[ ! ( -f path && -s path ) ]]
[[ ! -f path ]] || [[ ! -s path ]]
# or using `[` test and `-a` and `-o`:
! [ -f path -a -s path ]
[ ! -f path -o ! -s path ]
[ ! \( -f path -a -s path \) ]

就这样:

if [[ ! -f "/path/to/dir/" || ! -s "/path/to/dir/" ]]; then
     echo "The /path/to/dir is not a regular file or size is nonzero"
else
     echo "The path /path/to/dir is a regular file and it's size is zero"
fi

【讨论】:

  • 我正在关注/path/to/dir/ 末尾的斜线,并认为值得发表评论,但今天早上很难表达。也许在底部添加一个注释作为旁白,以澄清如果斜线在那里,它一个目录?
  • @Kamil Cuk mybe 您正在使用不同的 Bash 版本(我在 4.1.2(1)-release 上)并且 -s 还不够。如果我像这样传递现有目录路径:if [[ -s "/opt/gmdemea/smartmap_V2/maps/" ]]; then echo "Exists"; else echo "Does not exists"; fi 它在不是文件时返回“Exists”,因此应该转到 else 子句并返回“不存在”。
  • @PiotrPanczyk 你是对的。我认为它将 dir 视为大小为零的文件...:/
  • @EdMorton 我认为因为理论上[[ a ]] || [[ b ]] 将运行两个进程,而[[ a || b ]] 将只运行一个。请注意,如果a 在这两种情况下都为假,则不会处理b。更少的进程通常会导致更快的脚本。而且打字更少。我承认,我没有充分考虑该声明(但我认为我无论如何都会坚持下去,并且仍会在我的脚本中使用 && ||[[
  • @KamilCuk 我理解'-s'和你一样,并且在代码中单独使用它给我带来了麻烦。这就是为什么开始对此进行调查。
【解决方案2】:

@KamilCuk 已经解释了逻辑缺陷,但总的来说 - 始终避免在代码中使用否定词,例如! 在这种情况下,因为它们使代码比使用正数更难阅读(和正确)。而不是:

if [[ ! -f "/path/to/dir/" ]] && [[ ! -s "/path/to/dir" ]]
then
    echo "Does not exists"
else
    echo "Exists"
fi

如果你应用布尔代数来分解!s,那么你会得到:

if ! ( [[ -f "/path/to/dir/" ]] || [[ -s "/path/to/dir" ]] )
then
    echo "Does not exists"
else
    echo "Exists"
fi

然后您可以翻转 if/else 以摆脱最终的!

if [[ -f "/path/to/dir/" ]] || [[ -s "/path/to/dir" ]]
then
    echo "Exists"
else
    echo "Does not exists"
fi

您一眼就能看出不是您正在尝试的测试。相反,你想要:

if [[ -f "/path/to/dir/" ]] && [[ -s "/path/to/dir" ]]
then
    echo "Exists"
else
    echo "Does not exists"
fi

【讨论】:

  • @EdMorton 这是一个很好的建议,我知道这不是最佳做法,但希望避免翻转 if/else 并在原始问题中提到,没有否定的这种条件的版本可以正常工作。检查了! 的因素,它无济于事,仍然返回不正确。这个条件的所有三个版本在逻辑上都是等价的,关键是为什么它在 Bash 中不起作用,是否存在错误?
  • 不,没有错误。你在你的代码中做错了什么。我从your comment 可以看出你仍在使用!a && !b 而不是!a || !b
  • @EdMorton 也许我错过了一些条件,除了不遵循最佳实践并且不像翻转 if/else 和不使用'!'从逻辑的角度来看,我没有看到问题?
  • @EdMorton 您正确使用!a || !b 是正确的,在这里设法使自己感到困惑。
猜你喜欢
  • 1970-01-01
  • 2022-09-27
  • 2016-02-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-10
  • 1970-01-01
  • 2016-10-26
相关资源
最近更新 更多