检查目录中是否存在某个文件

检查目录中是否存在某个文件

您好,我正在尝试执行 if 操作,它获取目录路径作为参数,并检查 file.txt 是否在目录中。如果是,则返回 1,否则返回 0。

     if [ -e $1/file.txt ]; then
         exit 1
     else exit 0
     fi

我也尝试过 ls 方法

     ls $1/file.txt && exit 1 || exit 0

还有其他方法吗?或者我错过了什么?

答案1

file.txt要检查作为第一个参数传递给脚本或函数的目录中是否存在文件,请使用

[ -e "$1/file.txt" ]

不要忘记用双引号引用变量替换

如果文件存在则成功,如果文件不存在则失败。失败包括文件存在但无法访问的情况,例如因为您没有遍历目录的权限。

请注意,在 shell 脚本中,当涉及进程退出状态时,0 表示成功,1(或更多,最多 125)表示失败。看我可以在 bash 函数/脚本中使用哪些返回/退出值?进程终止时的默认退出代码?更多细节。因此,如果您想检查文件是否存在,则脚本或函数必须在文件存在时返回 0,否则返回 1。您的代码片段执行相反的操作:它检查文件是否不存在。

 if [ -e "$1/file.txt" ]; then
    exit 0
 else
    exit 1
 fi

只是一种更复杂的写法

[ -e "$1/file.txt" ]
exit

exit没有状态参数时使用先前执行的命令的状态)。如果这是在脚本的末尾,那么这exit是多余的。

!如果您确实想检查该文件是否不存在,那么您可以使用shell 运算符反转命令:

! [ -e "$1/file.txt" ]

! test/[运算符:

[ ! -e "$1/file.txt" ]

答案2

[ -e "$1/file.txt" ]

在支持它的shell/[实现中,如果可以对stat()路径为$1/file.txt.

它相当于:

if ls -Ld -- "$1/file.txt" > /dev/null 2>&1

相当于:

if ls -d -- "$1/file.txt" > /dev/null 2>&1

即是否lstat()可以对文件执行 a 操作,它将是:

if [ -e "$1/file.txt" ] || [ -L "$1/file.txt" ]

覆盖“损坏的”符号链接情况(-e在符号链接解析后测试是否存在时将返回 false)。

现在,stat(),lstat()失败并不一定意味着该文件不存在,stat()/lstat()可能会因 ENOENT(无条目)ENOTDIR(路径组件不是目录)以外的其他错误条件而失败。例如,您可能没有对任何目录组件的搜索访问权限。

通过该ls方法,您可以删除2>&1forls来告诉您错误。有了[,你不会知道,除非你使用zsh你可以使用的地方$ERRNO

如果你没有搜索访问该目录,您可能仍然拥有访问权限,因此您仍然可以读取目录内容以查看是否存在同名的文件。

对于zsh,可以通过 匿名函数 来完成()(($#)) $1/file.txt(N),如果它接收到至少一个参数 ( ),我们将与该glob()(($#))匹配的文件列表传递给该参数,该匿名函数将返回 true,即为该 glob打开。$1/file.txt(N)(N)NULLGLOB

一个单独的问题是其中is 的$1/file.txt情况,在这种情况下,在某些系统上 that 变为which 与 不同。$1///file.txt/file.txt

因此zsh,使用 来检查目录file.txt中是否存在条目$1

exists() {
  local file="${1%/}/file.txt"

  zmodload zsh/system
  local ERRNO=0
  [ -e "$file" ] || [ -L "$file" ] && return 0
  case $errnos[ERRNO] in
    (ENOENT|ENOTDIR) return 1;; # does not exist for sure
    (*) ()(($#)) $file && return 0;;
  esac
  return 2 # meaning: don't know
}

对于其他 shell,您可以尝试:

enoent_error=$(
  LC_ALL=C ls -d /surely-does-not-exist 2>&1)
)
enoent_error=${enoent_error##*:}

enotdir_error=$(
  LC_ALL=C ls -d /bin/sh/foo)
)
enotdir_error=${enotdir_error##*:}

exists() (
  file=${1%/}/file.txt
  if error=$(LC_ALL=C ls -d -- "$file" 2>&1 > /dev/null); then
    return 0 # exists for sure
  else
    case $error in
      (*:"$enoent_error"|*:"$enotdir_error")
        return 1;; # does not exist for sure
    esac
  fi
  return 2 # don't know
}

假设lsC 语言环境中的错误消息遵循以下*: fixed error message模式,fixed error message其中每个错误条件都不同,但对于给定错误始终相同,并且不包含:(仅在我的系统上ETOOMANYREFS参考太多:无法拼接) 在相应的标准 libc 错误消息中有一条:,但这不是lstat(), 无论如何返回的 errno无法拼接在其他错误消息中找不到)。


又名[最初test不支持-e。首先ksh引入-a(然后兼作一元和二元运算符),对于无障碍我相信(这在某种程度上更正确),后来被重命名为-e(尽管大多数实现仍然支持-a),这就是-ePOSIX 为标准test/[实用程序指定的。/bin/sh在 Solaris 10 及更早版本上仍然是非 POSIX Bourne shell,并且其[内置仍然不支持[ -eNor [ -a,因此如果您要使用该 shell,则需要求助于ls或调用/bin/test(尽管您更愿意使用 POSIX shell)就像/usr/xpg4/bin/sh那里一样)。

相关内容