如何检查Bash Shell脚本中是否存在目录?


Answers:


5144

要检查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 在另一个答案中对此进行了解释。

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


29
如果您想使用GNU工具安全使用它,--则强烈建议使用(选项结束标记)。否则,如果您的变量包含看起来像选项的内容,则脚本将与空格一样失败。
Marc Mutz-mmutz,2009年

2
对于bash,ksh等的现代版本。[...]是内置的
fpmurphy 2011年

79
有一点要记住:[ ! -d "$DIRECTORY" ]为真或者如果$DIRECTORY不存在,或者如果确实存在,但不是一个目录。考虑类似的东西if [ ! -d "$DIRECTORY" ] ; then mkdir "$DIRECTORY" ; fi;如果"$DIRECTORY"是文件,这将失败。(当然,您还是应该检查是否mkdir成功;有很多原因可能会导致失败。)
Keith Thompson

5
值得一提的是,一旦执行了检查,情况可能已经由于其他过程而发生了变化。在许多情况下,最好只创建或使用目录并对故障做出反应。
Alfe 2013年

12
与其同时测试目录(-d)和symlink(-L),不如将斜杠附加到变量上,就更容易了if [ -d "${THING:+$THING/}" ]。目录不介意多余的斜线。文件将评估为false。空将保持为空,因此为假。一个符号链接将被解析到它的目的地。当然,这取决于您的目标。如果您想去那里,那很好。如果要删除它,那么此答案中的代码会更好。
ghoti

530

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

有一天,其中一个孩子将运行您的脚本,将脚本$DIRECTORY设置为,"My M0viez"并且脚本会崩溃。你不要那样 所以用这个。

if [ -d "$DIRECTORY" ]; then
    # Will enter here if $DIRECTORY exists, even if it contains spaces
fi

9
使用双引号的另一个原因是,由于某种原因未设置$ DIRECTORY。
乔恩·埃里克森

2
“总是在bash脚本中将变量用双引号引起来。” 对于bash,使用[[...]]在技术上不是必需的;请参阅tldp.org/LDP/abs/html/testconstructs.html#DBLBRACKETS(注意:不分词):“ [[和]]之间没有文件名扩展或分词,但有参数扩展和命令替换。”
迈克尔

2
Unix / Linux上的目录不应包含任何空格,并且随后的脚本也不应对此进行调整。Windows支持它已经够糟糕了,这会对Windows脚本产生所有后果,但是请热衷于此,无需引入不必要的要求。
tvCa 2014年

18
@tvCa我发现用户通常更喜欢在目录名称中获得更大的灵活性,而不是被迫使开发人员更容易。(实际上,当处理长文件名时,我发现没有空格的文件会很痛苦,因为即使我自己过去由于不考虑脚本和程序中带空格的路径,我也因此遭受了换行的困扰。)
JAB

2
哈。空格只是通常没有字形的字符。无论如何,您可以使用反斜杠将其转义。
uchuugaka

228

注意-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条件表达式以及[内建命令[[复合commmand的更多信息。


12
或者,假设只需要在目录上工作(并且可以忽略链接)=> if [ -d tmpdir -a ! -L tmpdir ]; then echo "is directory"; rmdir tmpdir; fi...,或者对于同时在链接和目录上工作的一个命令:rm -r tmpdir
michael

218

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

if [[ -d "${DIRECTORY}" && ! -L "${DIRECTORY}" ]] ; then
    echo "It's a bona-fide directory"
fi

因为if [[ -d "$TARFILE" ]]我越来越[[:找不到
TheVillageIdiot 2011年

15
@TheVillageIdiot和@Hedgehog,您使用的是bash shell吗?不普遍支持双括号。关于这一点,这是一个特别的答案:stackoverflow.com/questions/669452/…–
yukondude

6
并且在Busybox中,使用默认编译选项[[ ]]支持ash ,但实际上并没有提供与的任何其他功能[ ]。如果需要考虑可移植性,请坚持[ ]并使用必要的解决方法。
dubiousjim

6
...如果在外壳程序脚本中使用bash构造,则脚本的第一行应为:#!/ bin / bash(而不是#!/ bin / sh,ksh等)
michael

在bash中使用双方括号时,无需引用变量。
Hubert Grzeskowiak

157

缩写形式:

[ -d "$DIR" ] && echo "Yes"

6
这是这样工作的 if $dir is a dir, then echo "yes"吗?
稍作

5
cmd && other是通用的简写if cmd; then other; fi-适用于大多数支持布尔逻辑的编程语言,称为短路评估
人间

1
下的行为是不同的set -e(这是Shell编程的最佳实践)。
支石墓

1
@dolmen [ -d "$DIR" ]是经过检查的(后跟&& echo Yes),因此我认为set -e对脚本行为没有影响(即,如果测试失败,则脚本可以正常继续)。
tzot

132

要检查目录是否存在,可以使用以下简单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

除了与文件切换无关,这又比2008年接受的答案好吗?
Dan Dascalescu

更好,因为[!-d目录/目录路径]
user1855805,

108
  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”:文件存在


4
如果最初不存在,则第二个目录将创建目录。那不是幂等的。
Shihe Zhang,

👆👆👆。第二个似乎很危险。由于它创建了目录,因此不再存在该目录已不再是事实。
克里斯

92

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

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

例如:

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

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

[-这是test内建函数的同义词,但是最后一个参数必须为文字],才能与开头匹配[

有关可能的选择或更多帮助,请检查:

  • help [
  • help test
  • man test 要么 man [

55

或完全没有用的东西:

[ -d . ] || echo "No"

6
它永远不会打印“否”。当前目录始终存在,除非被其他线程或其他方式删除。
Jahid 2015年

完美的示例:)鉴于与接受的答案相比,某些答案的“独特性”如何
Sergey Sargsyan

4
为什么这么多次反对?它没有回答问题。
codeforester

因为这是最好的答案EVA
Karl Morrison

52

这是一个非常实用的习惯用法:

(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会给我一个标准的一行消息,提示已出现标准错误。它还将提供比我所能提供的更多的信息。通过cd在subshel​​l内部执行( ... ),该命令不会影响调用者的当前目录。如果目录存在,则此子外壳程序和该函数仅是no-op。

接下来是我们传递给的论点cd${1:?pathname expected}。这是参数替换的一种更详尽的形式,下面将对其进行详细说明。

Tl; dr:如果传递给此函数的字符串为空,则再次退出子Shell,( ... )并从函数返回给定的错误消息。


ksh93手册页引用:

${parameter:?word}

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

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

此处的措辞是shell文档所特有的,它word可以指代任何合理的字符串,包括空格。

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

哲学注释:

外壳不是面向对象的语言,因此该消息pathname不是directory。在这个级别上,我宁愿保持简单-函数的参数只是字符串。


这不仅可以检查是否存在:还可以检查用户级别的可访问性。所以问题只代表存在。所以正确的答案test -d就像@Grundlefleck解释的那样。
F. Hauri 2013年

7
@ F.Hauri-他什么都没要求了,没错。但是,我发现我通常需要了解的不只是这些。
Henk Langeveld

我从来没有想到没有测试可以得出结论,除非它是作为root运行的。 test -d /unreadable/exists即使参数存在也将失败。
Henk Langeveld '16

36
if [ -d "$Directory" -a -w "$Directory" ]
then
    #Statements
fi

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


1
-a在效果上与-e相同。它已被“弃用”,不建议使用。
CousinCocaine 2014年

27
DIRECTORY=/tmp

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

在线尝试


remeber space[- > [``-d。我由于缺少空间而报错
Raj

4
同样,该答案已经在2008年给出,并提供了更多有用的解释。这里唯一的新事物是在线游乐场。
Dan Dascalescu

24

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

if [ -d "$DIRECTORY" ]; then
    # If true this block of code will execute
fi

再次,这个答案已经在2008年给出。重复它有什么意义?
Dan Dascalescu

21

使用更多功能 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

嗨,尼尔。你的想法可能是有用的检查视象的图案目录的存在:find -maxdepth 1 -type d -name 'pattern'。您介意我在您的答案中附加这个技巧吗?干杯;)
olibre

20

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

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

只要您使用,就不必担心空格和特殊字符"${}"

请注意,[[]]它不像那样具有可移植性[],但是由于大多数人都使用Bash的现代版本(毕竟,大多数人甚至不使用命令行:-p),所以收益大于麻烦。


17

您是否考虑过只是在做自己想做的事情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

同样的事情与工作cdmvrm,等...如果你试戴不存在的文件,他们将用一个错误退出,并打印一条消息说它不存在,你的then块将被跳过。如果您在确实存在的文件上尝试使用它们,该命令将执行并退出,状态为0,从而允许您的then块执行。


2
对我来说,推动是最优雅的方式。我打算将其发布为答案:)
melMass



15
[[ -d "$DIR" && ! -L "$DIR" ]] && echo "It's a directory and not a symbolic link"

注意:引用变量是一个好习惯。

说明:

  • -d:检查它是否是目录
  • -L:检查它是否是符号链接

可以按顺序进行解释(通过编辑答案,而不是在注释中)。
Peter Mortensen


11

这个答案包装成一个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";

10

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

if [ -e ${FILE_PATH_AND_NAME} ]
then
    echo "The file or directory exists."
fi

1
并且没有正确回答OP的问题-它是目录吗?
马克·斯图尔特

8

根据乔纳森的评论:

如果要创建目录并且目录尚不存在,那么最简单的方法是使用mkdir -p创建目录以及路径中所有丢失的目录的方法,并且如果目录已经存在也不会失败,因此您可以执行所有操作同时使用:

mkdir -p /some/directory/you/want/to/exist || exit 1

7
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

7

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

file $directory_name

检查不存在的文件: file blah

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

检查现有目录: file bluh

输出: bluh: directory


1
不错的主意,但是在两种情况下文件命令总是返回0退出代码,这太糟糕了。此外,当文件/目录无法找到:(。
danger89

6

ls命令与-l(长列表)选项一起返回有关文件和目录的属性信息。
特别是ls -l输出的第一个字符通常是a 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

+1,但是当根本不存在ISDIR时,您会收到一条错误消息以及诊断消息。
ysap


5

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

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

说明:如果目录或符号链接不存在,“ ls”命令将给出错误“ ls:/ x:没有这样的文件或目录”,并且还将可以通过“ $?”检索的返回码设置为non。 -null(通常为“ 1”)。确保调用“ ls”后直接检查返回码。


3
另外,您也可以使用以下较短的版本:if ! ls $DIR 2>/dev/null; then echo "$DIR does not exist!"; fi
derFunk 2014年

5

(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:找不到:[没有这样的文件或目录]


“以上”指的是什么?此答案或先前答案中的三个命令行?(请回复您的答案,而不是在评论中进行答复。在此先感谢。)
Peter Mortensen

4

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

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

此解决方案很好,因为它允许使用通配符,这是搜索文件/目录时的有用功能。唯一的问题是,如果搜索到的目录不存在,“ find”命令将不会在标准输出中显示任何内容(这不是我的喜好解决方案),并且退出状态为零。也许有人可以对此进行改进。


13
如果程序在整个硬盘驱动器中查找目录而不是礼貌地查找当前工作目录或使用我给它的绝对路径,我会感到不高兴。您所建议的内容可能对一个名为的工具locate
有用,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.