结合两个否定的文件检查条件(-f和-s)似乎返回错误的结果

时间:2019-07-03 13:12:56

标签: linux bash

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

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

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

存在

以上返回“ 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 
  

存在

它不是文件时返回“ Exists”,因此应该转到else子句,返回“不存在”

2 个答案:

答案 0 :(得分:4)

拥有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

答案 1 :(得分:4)

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

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

如果您应用布尔代数分解出!,那么您将得到:

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