检查shell脚本中是否存在目录

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

回答

要检查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解释.

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

  • 要记住一件事:`[!-d"$ DIRECTORY"]`如果`$ DIRECTORY`不存在,或者*确实*存在但不是目录,则为真.考虑像`if [!-d"$ DIRECTORY"]; 然后mkdir"$ DIRECTORY"; fi`; 如果`"$ DIRECTORY"`是一个文件,这将失败.(当然你应该检查`mkdir`是否成功;有很多原因可能会失败.)
  • 如果你想用GNU工具安全地使用它,强烈建议使用` - `(选项结束标记).否则,如果您的变量包含看起来像选项的内容,则脚本将像空格一样失败.
  • 不是测试目录(`-d`)和符号链接(`-L`),而是更容易向变量追加斜杠,比如`if [-d"$ {THING:+ $ THING /} "]`.目录不会介意额外的斜杠.文件将评估为false.空将保持为空,所以是假的.符号链接将被解析到其目的地.当然,这取决于你的目标.如果你想*去那里,这很好.如果你想*删除它*,那么这个答案中的代码更好.
  • 值得一提的是,一旦执行了检查,由于其他流程,情况可能已经发生变化.在许多情况下,最好只创建或使用目录并对失败做出反应.
  • 对于现代版本的bash,ksh等[...]是内置的
  • 我应该使用`[]`还是`[[]]`?

请记住,在bash脚本中引用变量时,始终将变量用双引号括起来.这些天孩子们长大了,他们的目录名称中可以有空格和许多其他有趣的字符.(太空!回到我的日子,我们没有任何奇特的空间!;))

有一天,其中一个孩子将运行你的脚本$DIRECTORY设置为"My M0viez",你的脚本将爆炸.你不希望这样.所以使用它.

if [ -d "$DIRECTORY" ]; then
# Will enter here if $DIRECTORY exists, even if it contains spaces
fi
  • @tvCa我发现用户通常更喜欢在目录名中更灵活,而不是被迫让开发人员更容易.(事实上​​,在处理长文件名时,我发现没有空格的文件就像包装文字包装一样痛苦,尽管我自己过去曾因为没有考虑脚本和程序中带空格的路径而受到影响.)
  • 使用双引号的另一个原因是,由于某种原因未设置$ DIRECTORY.
  • "总是用双引号括起变量......在bash脚本中." 对于bash,在使用[[...]]时技术上不必要; 请参阅http://tldp.org/LDP/abs/html/testconstructs.html#DBLBRACKETS(注意:没有单词拆分):"[[和]]之间没有文件名扩展或分词,但有参数扩展和命令替换."
  • Unix/Linux上的目录不应该有任何空格,随后脚本也不应该适应它.Windows支持它已经足够糟糕了,它会对Windows脚本产生一些影响,但是,对于喜欢的东西,请不要引入不必要的要求.
  • 哈.空格只是通常没有字形的字符.无论如何,你可以用反斜杠逃脱它们.
  • Spaces in filenames are evil, I'm currently on a mission, with Wowbagger the Infinitely Prolonged, to insult all those who use them 🙂

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

  • 或者,假设只需要处理目录(并且可以忽略链接)=>`if [-d tmpdir -a!-L tmpdir]; 然后回显"是目录"; rmdir tmpdir; fi` ...或者,对于一个适用于链接和目录的命令:`rm -r tmpdir`

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

if [[ -d "${DIRECTORY}" && ! -L "${DIRECTORY}" ]] ; then
echo "It's a bona-fide directory"
fi
  • @TheVillageIdiot和@Hedgehog,你在使用bash shell吗?双支架不是普遍支持的.以下是关于这一点的回答:http://stackoverflow.com/questions/669452/is-preferable-over-in-bash-scripts/669486#669486
  • 在Busybox ash中,支持默认编译选项`[[]]`,但实际上并没有为`[]`提供任何不同的功能.如果可移植性是一个问题,坚持使用`[]`并使用必要的解决方法.
  • ...如果在shell脚本中使用bash结构,脚本的第一行应该是:#!/ bin/bash(而不是#!/ bin/sh,ksh等)
  • 在 bash 中使用双方括号时,不需要引用变量。

缩短形式:

[ -d "$DIR" ] && echo "Yes"
  • 这样做是这样的:`如果$ dir是一个目录,那么回声"是"`?一点解释会有所帮助:)
  • `cmd && other`是`if cmd的常用简写; 其他; fi` - 这适用于支持布尔逻辑的大多数编程语言,被称为[短路评估](https://en.wikipedia.org/wiki/Short-circuit_evaluation).
  • `set -e` 下的行为不一样(这是一个 [shell 编程最佳实践](https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/))。

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

  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将给出如下错误:

  • 如果最初不存在,则第二个目录将创建目录。那不是幂等的。
  • . The 2nd one seems dangerous. Since it creates the directory, it's not even true anymore that the dir is not present.

if [ -d "$DIRECTORY" ]; then
# Here if $DIRECTORY exists
fi

你可以使用test -d(见man test).

例如:

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

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

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

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

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

[ -d . ] || echo "No"
  • 永远不会打印"否".当前目录始终存在,除非被其他线程或其他方式删除.
  • 为什么这么多次被投票?它没有回答这个问题.

这是一个非常务实的习语:

(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将给我一个标准的一行消息给stderr.它还将提供比我能提供的更多信息.通过cd在子shell中执行内部( ... )命令,该命令不会影响调用者的当前目录.如果目录存在,则此子shell和函数只是一个无操作.

接下来是我们传递给的论点cd:${1:?pathname expected}.这是更精细的参数替换形式,下面将更详细地解释.

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


引用ksh93手册页:

${parameter:?word}

这里的措辞是shell文档所特有的,word可以引用任何合理的字符串,包括空格.

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

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

  • @ F.Hauri - 他没有要求更多,这是真的.但是,我发现我通常需要了解更多.

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

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


在bash promt上键入此代码

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

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

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

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),所以好处大于麻烦.


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

IE,如果要在输入之前检查目录是否存在,请尝试执行以下操作:

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块执行.

  • pushd对我来说是最优雅的做法.我准备发布它作为答案:)

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

if [ -d "$DIRECTORY1" ] && [ -d "$DIRECTORY2" ] then
# Things to do
fi

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

[ -d "$DIRECTORY" ] || mkdir $DIRECTORY
  • 您可以使用`mkdir -p"$ DIRECTORY"`来获得相同的效果.

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

[ -d ~/Desktop/TEMPORAL/ ] && echo "DIRECTORY EXISTS" || echo "DIRECTORY DOES NOT EXIST"

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

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

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

根据乔纳森的评论:

如果你想创建目录并且它还不存在,那么最简单的方法是使用mkdir -p它创建目录 - 以及路径上任何缺少的目录 - 如果目录已经存在则不会失败,所以你可以全部完成同时:

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

以一种三元形式,

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

并与test

test -d "$directory" && echo "exist" || echo "not exist"

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

在线尝试

  • [AGAIN](https://stackoverflow.com/questions/59838/how-to-check-if-a-directory-exists-in-a-bash-shell-script#comment107113517_23077923), this answer was already given in 2008, with more useful explanations. The only new thing here is the online playground.

if [ -d "$DIRECTORY" ]; then
# Will enter here if $DIRECTORY exists
fi

这不完全正确......如果要转到该目录,还需要拥有该目录的执行权限.也许你还需要拥有写权.

Therfore:

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

ls命令与-l(long listing)选项一起返回有关文件和目录的属性信息.
特别是ls -l输出的第一个字符通常是a d或a -(破折号).如果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

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

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”命令将不会向标准输出打印任何内容(对于我来说这不是一个优雅的解决方案)并且仍然会以零退出。也许有人可以改进这一点。

  • 如果程序查看我的整个硬盘驱动器来查找目录而不是礼貌地查看我当前的工作目录或使用我提供的绝对路径,我会被冒犯。您所建议的可能适用于名为“locate”的工具,但不适用于其他任何工具...

find可以使用下面的,

find . -type d -name dirname -prune -print

file程序怎么样。考虑到所有目录也是linux中的文件,发出以下命令就足够了:

file $directory_name

检查不存在的文件: file blah

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

检查现有目录: file bluh

输出: bluh: directory


file="foo"
if [[ -e "$file" ]]; then echo "File Exists"; fi;

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

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

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

  • 或者你可以使用这个较短的版本:`if!ls $ DIR 2>/dev/null; 然后回声"$ DIR不存在!"; fi`

(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存在|| 不存在-ksh:not:not found [没有这样的文件或目录]


以上是检查shell脚本中是否存在目录的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>