检查一个目录是否存在于一个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所指出的(感谢Jon),如果您不考虑链接到目录的符号链接也会通过此检查,那么后续命令可能无法正常工作。 例如运行这个:
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
特别要注意用于包裹variables的双引号,其原因可以由8jean 在另一个答案中解释。
如果variables包含空格或其他不寻常的字符,可能会导致脚本失败。
请记住,在bash脚本中引用variables时总是用双引号包装variables。 现在的孩子长大了,他们的目录名中可以有空格和许多其他有趣的字符。 (空间!在我的日子里,我们没有任何花哨的空间!))
有一天,其中一个孩子会用$DIRECTORY
设置为"My M0viez"
来运行你的脚本,你的脚本将会炸毁。 你不要那个。 所以使用这个。
if [ -d "$DIRECTORY" ]; then # Will enter here if $DIRECTORY exists, even if it contains spaces fi
我发现test
的双括号版本使编写逻辑testing更加自然:
if [[ -d "${DIRECTORY}" && ! -L "${DIRECTORY}" ]] ; then echo "It's a bona-fide directory" fi
注意-dtesting可以产生一些令人惊讶的结果:
$ ln -s tmp/ t $ if [ -dt ]; then rmdir t; fi rmdir: directory "t": Path component not a directory
文件在“什么时候是不是目录的目录?” 答案是:“当它是一个符号链接到一个目录。” 一个更彻底的testing:
if [ -dt ]; then if [ -L t ]; then rm t else rmdir t fi fi
您可以在Bash条件expression式的Bash手册和[
内build命令和[[
复合 命令]中find更多信息。
更短的forms:
[ -d "$DIR" ] && echo "Yes"
要检查一个目录是否存在,你可以使用简单的结构如下:
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
注意 :请小心,在开启和closures支撑两侧留出空的空间。
使用相同的语法,您可以使用:
-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。
例如:
test -d "/etc" && echo Exists || echo Does not exist
注: test
命令与条件expression式[
(请参阅: man [
)相同,因此它可以在各个shell脚本之间移植。
[
– 这是内buildtest
的同义词,但最后一个参数必须是文字]
,以匹配开放[
。
有关可能的选项或进一步帮助,请检查:
-
help [
-
help test
-
man test
或man [
if [ -d "$DIRECTORY" ]; then # Here if $DIRECTORY exists fi
或者对于完全无用的东西:
[ -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。 它也会提供比我所能提供的更多的信息。 通过在子shell ( ... )
执行cd
,该命令不会影响调用者的当前目录。 如果该目录存在,这个子shell和函数只是一个空操作。
接下来是我们传递给cd
: ${1:?pathname expected}
。 这是更详细的参数replaceforms,下面将对此进行更详细的说明。
Tl; dr:如果传递给这个函数的string是空的,我们再次从子shell ( ... )
退出并从给出的错误信息返回函数。
从ksh93
手册页引用:
${parameter:?word}
如果
parameter
设置为非null,则replace其值; 否则,打印word
并从shell中退出(如果不是交互的话)。 如果word
被省略,则打印标准消息。
和
如果冒号
:
从上面的expression式中省略,那么shell只会检查参数是否被设置。
这里的措辞是shell文档特有的,因为word
可以指任何合理的string,包括空格。
在这种特殊情况下,我知道标准错误消息1: parameter not set
是不够的,所以我放大我们期望的值的types – 目录的pathname
。
一个philosphical注意:shell不是一个面向对象的语言,所以消息说pathname
,而不是directory
。 在这个层面上,我宁愿保持简单 – 函数的参数只是string。
if [ -d "$Directory" -a -w "$Directory" ] then #Statements fi
上面的代码检查目录是否存在,是否可写。
在bash promt上键入这个代码
if [ -d "$DIRECTORY" ]; then # if true this block of code will execute 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),所带来的好处比麻烦。
使用find
更多function
-
检查子目录内是否存在文件夹:
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
要检查多个目录,请使用以下代码:
if [ -d "$DIRECTORY1" ] && [ -d "$DIRECTORY2" ] then # Things to do fi
[ -d ~/Desktop/TEMPORAL/ ] && echo "DIRECTORY EXISTS" || echo "DIRECTORY DOES NOT EXIST"
[[ -d "$DIR" && ! -L "$DIR" ]] && echo "It's a directory and not a symbolic link"
注意:引用variables是一个好习惯。
检查目录是否存在,否则创build一个
[ -d "$DIRECTORY" ] || mkdir $DIRECTORY
使用-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
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";
按照Jonathan的评论:
如果你想创build目录并且目录还不存在,那么最简单的方法就是使用mkdir -p
来创build目录 – 以及path上的任何缺less的目录 – 如果目录已经存在,则不会失败,所以你可以一次完成:
mkdir -p /some/directory/you/want/to/exist || exit 1
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
(长列表)选项一起返回有关文件和目录的属性信息。
特别是ls -l
输出的第一个字符通常是d
或-
(破折号)。 如果是d
列出的是确定的目录。
下面的命令在一行中会告诉你给定的ISDIR
variables是否包含一个目录的path:
[[ $(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
那里有很好的解决scheme,但是如果你不在正确的目录下,每个脚本最终都会失败。 所以这样的代码:
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
只有在执行的时候,你才能成功执行你正在一个目录中,你有一个子目录,你碰巧检查。
我理解了这样的初始问题:validation目录是否存在,而不pipe用户在文件系统中的位置。 所以使用命令“查找”可能会有诀窍:
dir=" " echo "Input directory name to search for:" read dir find $HOME -name $dir -type d
这个解决scheme是好的,因为它允许使用通配符,这是search文件/目录时的一个有用的function。 唯一的问题是,如果search到的目录不存在,那么'find'命令将不会输出stdout(我的口味不是一个优雅的解决scheme),并且会有一个零退出。 也许有人可以改善这一点。
file="foo" if [[ -e "$file" ]]; then echo "File Exists"; fi;
如果你想检查一个目录是否存在,不pipe它是一个真实的目录还是一个符号链接,使用这个:
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”后直接检查返回码。
(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
ls -ld SAMPLE_DIR| grep ^d | wc -l
ls -ld SAMPLE_DIR| grep ^d | wc -l
-eq 1]] && echo exists || 不存在-ksh:不:没有find[没有这样的文件或目录]
下面find可以用,
find . -type d -name dirname -prune -print
从脚本文件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:
没有其他解决scheme为我的Dropbox文件夹工作,这是奇怪的,因为我可以推入Dropbox的符号path。
#!/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。 所以这里是脚本,它是完整的。