4107

在 Bash shell 脚本中,可以使用什么命令来检查目录是否存在?

4

35 回答 35

5558

要检查 shell 脚本中是否存在目录,可以使用以下命令:

if [ -d "$DIRECTORY" ]; then
  # Control will enter here if $DIRECTORY exists.
fi

或者检查目录是否不存在:

if [ ! -d "$DIRECTORY" ]; then
  # Control will enter here if $DIRECTORY doesn't exist.
fi

但是,正如Jon Ericson指出的那样,如果您不考虑到目录的符号链接也将通过此检查,则后续命令可能无法按预期工作。例如运行这个:

ln -s "$ACTUAL_DIR" "$SYMLINK"
if [ -d "$SYMLINK" ]; then 
  rmdir "$SYMLINK" 
fi

会产生错误信息:

rmdir: failed to remove `symlink': Not a directory

因此,如果后续命令需要目录,则可能必须区别对待符号链接:

if [ -d "$LINK_OR_DIR" ]; then 
  if [ -L "$LINK_OR_DIR" ]; then
    # It is a symlink!
    # Symbolic link specific commands go here.
    rm "$LINK_OR_DIR"
  else
    # It's a directory!
    # Directory command goes here.
    rmdir "$LINK_OR_DIR"
  fi
fi

请特别注意用于包装变量的双引号。8jean在另一个答案中解释了其原因。

如果变量包含空格或其他异常字符,则可能会导致脚本失败。

于 2008-09-12T20:07:06.113 回答
580

在 Bash 脚本中引用变量时,请记住始终将变量用双引号括起来。这些天来,孩子们长大后认为他们的目录名称中可以有空格和许多其他有趣的字符。(空间!回到我的时代,我们没有花哨的空间!;))

有一天,其中一个孩子会运行你的脚本,$DIRECTORY设置为"My M0viez",你的脚本会爆炸。你不想要那个。所以用这个。

if [ -d "$DIRECTORY" ]; then
    # Will enter here if $DIRECTORY exists, even if it contains spaces
fi
于 2008-09-15T22:00:49.730 回答
252

请注意-d测试可能会产生一些令人惊讶的结果:

$ ln -s tmp/ t
$ if [ -d t ]; then rmdir t; fi
rmdir: directory "t": Path component not a directory

文件下:“什么时候目录不是目录?” 答案是:“当它是目录的符号链接时。” 一个稍微彻底的测试:

if [ -d t ]; then 
   if [ -L t ]; then 
      rm t
   else 
      rmdir t
   fi
fi

您可以在 Bash 手册中找到有关Bash 条件表达式以及[内置命令[[复合命令的更多信息。

于 2008-09-12T20:26:04.803 回答
234

我发现双括号版本test使编写逻辑测试更自然:

if [[ -d "${DIRECTORY}" && ! -L "${DIRECTORY}" ]] ; then
    echo "It's a bona-fide directory"
fi
于 2008-09-12T21:33:08.963 回答
206

较短的形式:

# if $DIR is a directory, then print yes
[ -d "$DIR" ] && echo "Yes"
于 2008-09-12T21:08:48.977 回答
144

要检查目录是否存在,您可以使用如下简单if结构:

if [ -d directory/path to a directory ] ; then
# Things to do

else #if needed #also: elif [new condition]
# Things to do
fi

你也可以在否定的情况下这样做:

if [ ! -d directory/path to a directory ] ; then
# Things to do when not an existing directory

注意:小心。在左大括号和右大括号的两侧留空。

使用相同的语法,您可以使用:

-e: any kind of archive

-f: file

-h: symbolic link

-r: readable file

-w: writable file

-x: executable file

-s: file size greater than zero
于 2015-04-08T02:50:09.670 回答
144
  1. 一个简单的脚本来测试目录或文件是否存在:

     if [ -d /home/ram/dir ]   # For file "if [ -f /home/rama/file ]"
     then
         echo "dir present"
     else
         echo "dir not present"
     fi
    
  2. 一个简单的脚本来检查目录是否存在:

     mkdir tempdir   # If you want to check file use touch instead of mkdir
     ret=$?
     if [ "$ret" == "0" ]
     then
         echo "dir present"
     else
         echo "dir not present"
     fi
    

    上面的脚本将检查目录是否存在

    $? 如果最后一个命令成功,则返回“0”,否则返回非零值。假设tempdir已经存在。然后mkdir tempdir会给出如下错误:

    mkdir: 无法创建目录 'tempdir': 文件存在

于 2018-05-15T05:36:08.160 回答
107

您可以使用test -d(请参阅man test)。

-d file 如果文件存在并且是目录,则为真。

例如:

test -d "/etc" && echo Exists || echo Does not exist

注意:该test命令与条件表达式相同[(请参阅:)man [,因此它可以跨 shell 脚本移植。

[- 这是test内置的同义词,但最后一个参数必须是文字],以匹配开头[

有关可能的选项或进一步的帮助,请检查:

  • help [
  • help test
  • man test或者man [
于 2015-09-12T21:25:05.697 回答
60

或者对于完全没用的东西:

[ -d . ] || echo "No"
于 2009-08-17T14:02:43.420 回答
59

这是一个非常实用的成语:

(cd $dir) || return # Is this a directory,
                    # and do we have access?

我通常将它包装在一个函数中:

can_use_as_dir() {
    (cd ${1:?pathname expected}) || return
}

或者:

assert_dir_access() {
    (cd ${1:?pathname expected}) || exit
}

这种方法的好处是我不必考虑好的错误消息。

cd会给我一个标准的单行消息到标准错误。它还将提供比我能够提供的更多的信息。通过在cdsubshel​​l 内部执行( ... ),该命令不会影响调用者的当前目录。如果该目录存在,则此子shell 和函数只是一个空操作。

接下来是我们传递给cd:的参数${1:?pathname expected}。这是一种更复杂的参数替换形式,下面将更详细地解释。

Tl;dr:如果传递给这个函数的字符串是空的,我们再次退出子shell( ... )并从函数返回给定的错误消息。


ksh93手册页引用:

${parameter:?word}

如果 parameter 已设置且不为空,则替换其值;否则,打印word并从 shell 退出(如果不是交互式的)。如果word省略,则打印标准消息。

如果上述表达式中省略了冒号:,则 shell 仅检查是否设置了参数。

这里的措辞是 shell 文档特有的,因为它word可以指任何合理的字符串,包括空格。

在这种特殊情况下,我知道标准错误消息1: parameter not set是不够的,所以我放大了我们在这里期望的值的类型——pathname目录的类型。

哲学笔记:

shell 不是面向对象的语言,所以消息说pathname,不是directory。在这个级别上,我宁愿保持简单——函数的参数只是字符串。

于 2012-08-09T21:43:52.137 回答
41
if [ -d "$Directory" -a -w "$Directory" ]
then
    #Statements
fi

上面的代码检查目录是否存在以及是否可写。

于 2010-04-21T06:06:05.000 回答
32

更多功能使用find

  • 检查子目录中是否存在该文件夹:

      found=`find -type d -name "myDirectory"`
      if [ -n "$found" ]
      then
          # The variable 'found' contains the full path where "myDirectory" is.
          # It may contain several lines if there are several folders named "myDirectory".
      fi
    
  • 根据当前目录中的模式检查一个或多个文件夹的存在:

      found=`find -maxdepth 1 -type d -name "my*"`
      if [ -n "$found" ]
      then
          # The variable 'found' contains the full path where folders "my*" have been found.
      fi
    
  • 两种组合。在以下示例中,它检查当前目录中是否存在文件夹:

      found=`find -maxdepth 1 -type d -name "myDirectory"`
      if [ -n "$found" ]
      then
          # The variable 'found' is not empty => "myDirectory"` exists.
      fi
    
于 2008-09-12T20:17:12.577 回答
31
DIRECTORY=/tmp

if [ -d "$DIRECTORY" ]; then
    echo "Exists"
fi

在线尝试

于 2019-10-09T06:08:03.883 回答
27

在 Bash 提示符下键入此代码:

if [ -d "$DIRECTORY" ]; then
    # If true this block of code will execute
fi
于 2014-11-05T03:39:01.307 回答
23

实际上,您应该使用几种工具来获得防弹方法:

DIR_PATH=`readlink -f "${the_stuff_you_test}"` # Get rid of symlinks and get abs path
if [[ -d "${DIR_PATH}" ]] ; Then # Now you're testing
    echo "It's a dir";
fi

只要您使用"${}".

请注意,[[]]它不如[].

于 2010-02-17T17:46:07.773 回答
23

你有没有考虑过只做你想做的事,if而不是在你跳跃之前先看?

即,如果您想在输入目录之前检查目录是否存在,请尝试这样做:

if pushd /path/you/want/to/enter; then
    # Commands you want to run in this directory
    popd
fi

如果您提供的路径pushd存在,您将输入它并以 退出0,这意味着then语句的部分将执行。如果它不存在,则不会发生任何事情(除了一些输出说目录不存在,这对于调试来说可能是一个有用的副作用)。

这似乎比这更好,这需要重复自己:

if [ -d /path/you/want/to/enter ]; then
    pushd /path/you/want/to/enter
    # Commands you want to run in this directory
    popd
fi

同样的事情适用于cd, mv, rm, 等...如果您在不存在的文件上尝试它们,它们将退出并显示错误并打印一条消息说它不存在,并且您的then块将被跳过。如果您在确实存在的文件上尝试它们,该命令将执行并以 状态退出0,从而允许您的then块执行。

于 2017-12-07T16:24:23.760 回答
20
[[ -d "$DIR" && ! -L "$DIR" ]] && echo "It's a directory and not a symbolic link"

注意:引用变量是一种很好的做法。

解释:

  • -d: 检查是否是目录
  • -L: 检查是否是符号链接
于 2015-04-19T00:54:07.030 回答
17

要检查多个目录,请使用以下代码:

if [ -d "$DIRECTORY1" ] && [ -d "$DIRECTORY2" ] then
    # Things to do
fi
于 2015-12-29T09:45:14.513 回答
16

检查目录是否存在,否则创建一个:

[ -d "$DIRECTORY" ] || mkdir $DIRECTORY
于 2016-03-23T07:25:55.557 回答
15
[ -d ~/Desktop/TEMPORAL/ ] && echo "DIRECTORY EXISTS" || echo "DIRECTORY DOES NOT EXIST"
于 2013-04-18T22:12:37.013 回答
12

这个答案包含在一个 shell 脚本中

例子

$ is_dir ~                           
YES

$ is_dir /tmp                        
YES

$ is_dir ~/bin                       
YES

$ mkdir '/tmp/test me'

$ is_dir '/tmp/test me'
YES

$ is_dir /asdf/asdf                  
NO

# Example of calling it in another script
DIR=~/mydata
if [ $(is_dir $DIR) == "NO" ]
then
  echo "Folder doesnt exist: $DIR";
  exit;
fi

is_dir

function show_help()
{
  IT=$(CAT <<EOF

  usage: DIR
  output: YES or NO, depending on whether or not the directory exists.

  )
  echo "$IT"
  exit
}

if [ "$1" == "help" ]
then
  show_help
fi
if [ -z "$1" ]
then
  show_help
fi

DIR=$1
if [ -d $DIR ]; then 
   echo "YES";
   exit;
fi
echo "NO";
于 2016-04-15T18:13:53.633 回答
11

使用-e检查将检查文件,这包括目录。

if [ -e ${FILE_PATH_AND_NAME} ]
then
    echo "The file or directory exists."
fi
于 2013-07-25T13:12:09.573 回答
9
if [ -d "$DIRECTORY" ]; then
    # Will enter here if $DIRECTORY exists
fi

这并不完全正确……

如果要进入该目录,还需要对该目录具有执行权限。也许您还需要具有写入权限。

所以:

if [ -d "$DIRECTORY" ] && [ -x "$DIRECTORY" ] ; then
    # ... to go to that directory (even if DIRECTORY is a link)
    cd $DIRECTORY
    pwd
fi

if [ -d "$DIRECTORY" ] && [ -w "$DIRECTORY" ] ; then
    # ... to go to that directory and write something there (even if DIRECTORY is a link)
    cd $DIRECTORY
    touch foobar
fi
于 2010-03-18T10:52:57.553 回答
9

根据乔纳森的评论:

如果你想创建目录但它还不存在,那么最简单的技术是使用mkdir -p它来创建目录——以及路径上任何缺失的目录——并且如果目录已经存在也不会失败,所以你可以做这一切同时:

mkdir -p /some/directory/you/want/to/exist || exit 1
于 2015-09-12T21:21:06.503 回答
8

以一种三元形式,

[ -d "$directory" ] && echo "exist" || echo "not exist"

并与test

test -d "$directory" && echo "exist" || echo "not exist"
于 2017-04-15T13:36:55.640 回答
7

ls命令与-l(长列表)选项一起返回有关文件和目录的属性信息。
特别是ls -l输出的第一个字符通常是一个d或一个-(破折号)。如果d列出的是一个目录,那肯定是一个目录。

仅一行中的以下命令将告诉您给定ISDIR变量是否包含目录路径:

[[ $(ls -ld "$ISDIR" | cut -c1) == 'd' ]] &&
    echo "YES, $ISDIR is a directory." || 
    echo "Sorry, $ISDIR is not a directory"

实际使用:

    [claudio@nowhere ~]$ ISDIR="$HOME/Music" 
    [claudio@nowhere ~]$ ls -ld "$ISDIR"
    drwxr-xr-x. 2 claudio claudio 4096 Aug 23 00:02 /home/claudio/Music
    [claudio@nowhere ~]$ [[ $(ls -ld "$ISDIR" | cut -c1) == 'd' ]] && 
        echo "YES, $ISDIR is a directory." ||
        echo "Sorry, $ISDIR is not a directory"
    YES, /home/claudio/Music is a directory.

    [claudio@nowhere ~]$ touch "empty file.txt"
    [claudio@nowhere ~]$ ISDIR="$HOME/empty file.txt" 
    [claudio@nowhere ~]$ [[ $(ls -ld "$ISDIR" | cut -c1) == 'd' ]] && 
        echo "YES, $ISDIR is a directory." || 
        echo "Sorry, $ISDIR is not a directoy"
    Sorry, /home/claudio/empty file.txt is not a directory
于 2011-09-15T19:47:49.540 回答
6

那里有很好的解决方案,但如果您不在正确的目录中,最终每个脚本都会失败。所以这样的代码:

if [ -d "$LINK_OR_DIR" ]; then
if [ -L "$LINK_OR_DIR" ]; then
    # It is a symlink!
    # Symbolic link specific commands go here
    rm "$LINK_OR_DIR"
else
    # It's a directory!
    # Directory command goes here
    rmdir "$LINK_OR_DIR"
fi
fi

只有在执行时您所在的目录具有您碰巧检查的子目录,才会成功执行。

我理解这样的初始问题:无论用户在文件系统中的位置如何,都要验证目录是否存在。所以使用命令'find'可能会成功:

dir=" "
echo "Input directory name to search for:"
read dir
find $HOME -name $dir -type d

这个解决方案很好,因为它允许使用通配符,这是搜索文件/目录时的一个有用功能。唯一的问题是,如果搜索到的目录不存在,“查找”命令将不会在标准输出中打印任何内容(对我来说这不是一个优雅的解决方案),并且仍然会出现零退出。也许有人可以改进这一点。

于 2011-12-12T20:40:01.247 回答
6
file="foo" 
if [[ -e "$file" ]]; then echo "File Exists"; fi;
于 2013-02-22T02:39:07.313 回答
6

find可以使用下面的,

find . -type d -name dirname -prune -print
于 2014-08-13T13:41:35.353 回答
6

(1)

[ -d Piyush_Drv1 ] && echo ""Exists"" || echo "Not Exists"

(2)

[ `find . -type d -name Piyush_Drv1 -print | wc -l` -eq 1 ] && echo Exists || echo "Not Exists"

(3)

[[ -d run_dir  && ! -L run_dir ]] && echo Exists || echo "Not Exists"

如果使用上述方法之一发现问题:

ls命令;目录不存在的情况 - 显示错误消息

[[ `ls -ld SAMPLE_DIR| grep ^d | wc -l` -eq 1 ]] && echo exists || not exists

-ksh: not: not found [没有这样的文件或目录]

于 2015-05-13T07:21:10.920 回答
5

使用该file程序。考虑到 Linux 中的所有目录也是文件,发出以下命令就足够了:

file $directory_name

检查不存在的文件:file blah

输出: cannot open 'blah' (No such file or directory)

检查现有目录:file bluh

输出: bluh: directory

于 2018-06-25T06:59:09.197 回答
4

如果要检查目录是否存在,无论它是真实目录还是符号链接,请使用以下命令:

ls $DIR
if [ $? != 0 ]; then
        echo "Directory $DIR already exists!"
        exit 1;
fi
echo "Directory $DIR does not exist..."

说明:如果目录或符号链接不存在,“ls”命令会给出错误“ls: /x: No such file or directory”,并将返回码(您可以通过“$?”检索)设置为非-null(通常为“1”)。确保在调用“ls”后直接检查返回码。

于 2014-01-07T17:59:56.567 回答
3

从脚本文件myScript.sh

if [ -d /home/ec2-user/apache-tomcat-8.5.5/webapps/Gene\ Directory ]; then
   echo "Directory exists!"
   echo "Great"
fi

或者

if [ -d '/home/ec2-user/apache-tomcat-8.5.5/webapps/Gene Directory' ]; then
   echo "Directory exists!"
   echo "Great"
fi
于 2017-06-29T22:14:25.753 回答
3

Git Bash + Dropbox + Windows:

其他解决方案都不适用于我的 Dropbox 文件夹,这很奇怪,因为我可以将 Git 推送到 Dropbox 符号路径。

#!/bin/bash

dbox="~/Dropbox/"
result=0
prv=$(pwd) && eval "cd $dbox" && result=1 && cd "$prv"
echo $result

read -p "Press Enter To Continue:"

您可能还想知道如何从 Bash 成功导航到 Dropbox。所以这里是完整的脚本。

https://pastebin.com/QF2Exmpn

于 2017-09-13T19:49:19.297 回答
2

作为 '[ -d ]' 和 '[ -h ]' 选项的替代方案,您可以使用stat获取文件类型并对其进行解析。

#! /bin/bash
MY_DIR=$1
NODE_TYPE=$(stat -c '%F' ${MY_DIR} 2>/dev/null)
case "${NODE_TYPE}" in
        "directory") echo $MY_DIR;;
    "symbolic link") echo $(readlink $MY_DIR);;
                 "") echo "$MY_DIR does not exist";;
                  *) echo "$NODE_TYPE is unsupported";;
esac
exit 0

测试数据:

$ mkdir tmp
$ ln -s tmp derp
$ touch a.txt
$ ./dir.sh tmp
tmp
$ ./dir.sh derp
tmp
$ ./dir.sh a.txt
regular file is unsupported
$ ./dir.sh god
god does not exist
于 2019-07-26T15:45:48.733 回答