如何在Bash shell脚本中检查一个目录是否存在?
在Bash shell脚本中,什么命令可以检查一个目录是否存在?
要检查一个目录是否存在。
if [ -d "$DIRECTORY" ]; then
echo "$DIRECTORY does exist."
fi
要检查一个目录是否不存在。
if [ ! -d "$DIRECTORY" ]; then
echo "$DIRECTORY does not 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 在另一个答案中解释了这样做的原因。
如果变量中含有空格或其他不寻常的字符,很可能会导致脚本失败。
--
(选项结束标记)。否则,如果您的变量包含一些看起来像选项的东西,脚本将像空格一样失败。
- Marc Mutz - mmutz 2009-07-21
$DIRECTORY
不存在,或者确实存在但不是一个目录,那么[ ! -d "$DIRECTORY" ]
将为真。考虑像if [ ! -d "$DIRECTORY" ] ; then mkdir "$DIRECTORY" ; fi
这样的情况;如果"$DIRECTORY"
是一个文件,这将失败。(当然,你应该检查mkdir
是否成功;有许多原因会导致失败)。
- Keith Thompson 2011-08-09
-d
)和符号链接(-L
),不如在变量上加一个斜线,如if [ -d "${THING:+$THING/}" ]
,这样更简单。一个目录不会介意额外的斜线。一个文件将评估为false。空将保持空,所以是假的。而一个符号链接将被解析到它的目的地。当然,这取决于你的目标。如果你想去那里,这很好。如果你想删除它,那么这个答案中的代码会更好。
- ghoti 2017-01-17
在Bash脚本中引用变量时,一定要用双引号将其包裹起来。
if [ -d "$DIRECTORY" ]; then
# Will enter here if $DIRECTORY exists, even if it contains spaces
fi
现在的年轻人在他们的目录名称中加入了空格和许多其他有趣的字符。(在我的时代,我们没有花哨的字符)有一天,这些年轻人中的一个会在运行你的脚本时把$DIRECTORY
设置为"My M0viez"
,你的脚本就会爆炸。你不希望这样。所以要使用双引号。
请注意,-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
if [ -d tmpdir -a ! -L tmpdir ]; then echo "is directory"; rmdir tmpdir; fi
... 或者,对于一个既能在链接上工作又能在dirs上工作的命令。rm -r tmpdir
- michael 2014-09-12
我发现双括号版的test
使编写逻辑测试更加自然。
if [[ -d "${DIRECTORY}" && ! -L "${DIRECTORY}" ]] ; then
echo "It's a bona-fide directory"
fi
if [[ -d "$TARFILE" ]]
,我得到的是[[:未找到]]。
- TheVillageIdiot 2011-06-19
[[ ]]
是被支持的,但事实上并没有提供任何与[ ]
不同的功能。如果移植性是一个问题,请坚持使用[ ]
并使用必要的变通方法。
- dubiousjim 2012-05-31
更为简短的形式。
# if $DIR is a directory, then print yes
[ -d "$DIR" ] && echo "Yes"
if $dir is a dir, then echo "yes"
?解释一下会有帮助 :)
- Martijn 2016-08-05
[ -d "$DIR" ]
被检查了(接着是&& echo Yes
),所以我相信set -e
对脚本的行为没有任何影响(即如果测试失败,脚本会正常继续)。
- tzot 2018-09-04
set -e
下的行为是完全一样的。除了如果echo失败,脚本会退出。如果测试失败(即目录不存在,或者$DIR
存在但不是一个目录),仅[ -d "$DIR" ]
(没有&& cmd ...
)就会导致脚本在set -e
下退出。
- dan 2022-07-18
一个简单的脚本,用来测试一个目录或文件是否存在。
if [ -d /home/ram/dir ] # For file "if [ -f /home/rama/file ]" then echo "dir present" else echo "dir not present" fi
一个简单的脚本,用于检查目录是否存在。
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: cannot create directory ‘tempdir’: File exists
要检查一个目录是否存在,你可以使用一个简单的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
你可以使用test -d
(见man test
)。
-d file
True if file exists and is a directory.
例如:
test -d "/etc" && echo Exists || echo Does not exist
注意:test
命令与条件表达式[
相同(见:man [
),所以它在不同的shell脚本中是可移植的。
[
- This is a synonym for thetest
builtin, but the last argument must, be a literal]
, to match the opening[
.
关于可能的选择或进一步的帮助,请查看。
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
将给我一个标准的单行信息,以标准的错误已经。它还会给出比我能够提供的更多信息。通过在子壳( ... )
内执行cd
,该命令不会影响调用者的当前目录。如果目录存在,这个子壳和函数只是一个无用功。
接下来是我们传递给cd
的参数。${1:?pathname expected}
.这是一种更复杂的参数替换形式,下面会详细解释。
Tl;dr: 如果传入这个函数的字符串是空的,我们再次从子shell( ... )
中退出,并从函数中返回给定的错误信息。
引用ksh93
man的内容。
${parameter:?word}
If
parameter
is set and is non-null then substitute its value; otherwise, printword
and exit from the shell (if not interactive). Ifword
is omitted then a standard message is printed.
和
If the colon
:
is omitted from the above expressions, then the shell only checks whether parameter is set or not.
这里的措辞是shell文档所特有的,因为word
可以指任何合理的字符串,包括空白处。
在这个特殊的案例中,我知道标准错误信息1: parameter not set
是不够的,所以我放大了我们在这里期望的值的类型--目录的pathname
。
一个哲学上的说明。
shell不是一种面向对象的语言,所以信息说的是pathname
,而不是directory
。在这个层面上,我宁愿保持简单--函数的参数只是字符串。
test -d
,正如@Grundlefleck所解释的。
- F. Hauri - Give Up GitHub 2013-02-09
test -d /unreadable/exists
会失败,即使参数存在。
- Henk Langeveld 2016-04-02
if [ -d "$Directory" -a -w "$Directory" ]
then
#Statements
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
find -maxdepth 1 -type d -name 'pattern'
.你介意我在你的答案中加入这个技巧吗?谢谢;)
- oHo 2013-11-18
DIRECTORY=/tmp
if [ -d "$DIRECTORY" ]; then
echo "Exists"
fi
space
在[
之后 -> [``-d.我得到了错误,因为缺少空格
- Raj 2020-02-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),所以好处多于麻烦。
你是否考虑过只做你想做的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
块执行。
[[ -d "$DIR" && ! -L "$DIR" ]] && echo "It's a directory and not a symbolic link"
注意:引用变量是一种好的做法。
解释如下:
-d
:检查它是否是一个目录-L
:检查它是否是一个符号链接
[[...]]
,大部分情况下不需要给变量加引号(即使是带有路径和元字符的空格)。唯一的例外是=
的RHS,例如[[ $VAR = "$VAR" ]]
。(这是由于Bash将RHS解释为一个glob)。
- amphetamachine 2022-07-08
如果要检查一个以上的目录,请使用这个代码。
if [ -d "$DIRECTORY1" ] && [ -d "$DIRECTORY2" ] then
# Things to do
fi
检查目录是否存在,否则制作一个目录。
[ -d "$DIRECTORY" ] || mkdir $DIRECTORY
mkdir -p "$DIRECTORY"
来达到同样的效果。
- Logan Pickup 2016-07-24
mkdir
部分的$DIRECTORY
周围也需要双引号。否则,分词可能会导致不理想的结果。比如说。dir="a b"; mkdir $dir
将导致两个目录a
和b
被创建,而不是一个a b
目录。
- codeforester 2021-02-22
[ -d ~/Desktop/TEMPORAL/ ] && echo "DIRECTORY EXISTS" || echo "DIRECTORY DOES NOT EXIST"
使用-e
将检查文件,这也包括目录。
if [ -e ${FILE_PATH_AND_NAME} ]
then
echo "The file or directory exists."
fi
这个答案被包装成了一个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
i.e.d. "是什么?
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";
按照Jonathan的评论。
如果你想创建目录,但它还不存在,那么最简单的技术是使用mkdir -p
,它可以创建目录--以及路径上任何缺失的目录--并且如果目录已经存在也不会失败,所以你可以用mkdir -p
一次完成。
mkdir -p /some/directory/you/want/to/exist || exit 1
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
以一种ternary的形式。
[ -d "$directory" ] && echo "exist" || echo "not exist"
而用test
。
test -d "$directory" && echo "exist" || echo "not exist"
file="foo"
if [[ -e "$file" ]]; then echo "File Exists"; fi;
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
那里有很好的解决方案,但最终每个脚本都会失败,如果你不在正确的目录中。因此,像这样的代码。
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
的工具来说可能是不错的,但对其他东西来说就不怎么样了......
- sarnold 2012-02-01
可以使用下面的find
。
find . -type d -name dirname -prune -print
一句话的意思。
[[ -d $Directory ]] && echo true
(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 [No such file or directory]
使用file
程序。 考虑到在Linux中所有的目录也是文件,发出下面的命令就足够了。
file $directory_name
检查一个不存在的文件。file blah
输出: cannot open 'blah' (No such file or directory)
检查一个现有的目录。file bluh
输出: bluh: directory
如果你想检查一个目录是否存在,不管它是一个真正的目录还是一个符号链接,都可以使用这个。
ls $DIR
if [ $? != 0 ]; then
echo "Directory $DIR already exists!"
exit 1;
fi
echo "Directory $DIR does not exist..."
解释一下。ls "命令给出了一个错误 "ls:/x:如果目录或符号链接不存在,会给出错误 "ls: /x: No such file or directory",并将返回代码设置为非空(通常为 "1"),你可以通过"$? "检索到该代码。 请确保在调用 "ls "后直接检查返回代码。
if ! ls $DIR 2>/dev/null; then echo "$DIR does not exist!"; fi
- derFunk 2014-01-08
ls
返回非零并不意味着该目录存在。该代码应该是。ls $DIR RETURN_CODE=$? if [ "$RETURN_CODE" != "0" ]; then echo "Cannot access directory $DIR (does not exist or no permission or something else altogether)!" exit $RETURN_CODE; fi echo "Directory $DIR already exists..."
- zerzevul 2021-02-19
来自于脚本文件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
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。因此,这里是脚本的全部内容。
cd -
可以将其简化很多...或者cd "$OLDPWD"
(或者使用一个子shell,你的脚本目录不会改变,但这样你就不能设置变量了)。
- Gert van den Berg 2018-04-18
prv=$(pwd) && eval "cd $dbox" && result=1 && cd "$prv"
也许写成if (cd "$dbox"); then result=1; fi
更好 -- (...)
在离开括号时将撤销目录的改变。另外,我只把eval
作为最后的手段来使用,并在评论中表示歉意。
- amphetamachine 2022-07-08
作为'[ -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