在Bash shell脚本中,可以使用什么命令来检查目录是否存在?
在Bash shell脚本中,可以使用什么命令来检查目录是否存在?
Answers:
要检查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" ] ; then mkdir "$DIRECTORY" ; fi
;如果"$DIRECTORY"
是文件,这将失败。(当然,您还是应该检查是否mkdir
成功;有很多原因可能会导致失败。)
-d
)和symlink(-L
),不如将斜杠附加到变量上,就更容易了if [ -d "${THING:+$THING/}" ]
。目录不介意多余的斜线。文件将评估为false。空将保持为空,因此为假。一个符号链接将被解析到它的目的地。当然,这取决于您的目标。如果您想去那里,那很好。如果要删除它,那么此答案中的代码会更好。
在Bash脚本中引用变量时,切记始终将变量用双引号引起来。这些天,孩子们长大了,他们的目录名称中可以有空格和许多其他有趣的字符。(空格!回到我的时代,我们没有多余的空格!;))
有一天,其中一个孩子将运行您的脚本,将脚本$DIRECTORY
设置为,"My M0viez"
并且脚本会崩溃。你不要那样 所以用这个。
if [ -d "$DIRECTORY" ]; then
# Will enter here if $DIRECTORY exists, even if it contains spaces
fi
注意-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的更多信息。
if [ -d tmpdir -a ! -L tmpdir ]; then echo "is directory"; rmdir tmpdir; fi
...,或者对于同时在链接和目录上工作的一个命令:rm -r tmpdir
我发现使编写逻辑测试更自然的双括号版本test
:
if [[ -d "${DIRECTORY}" && ! -L "${DIRECTORY}" ]] ; then
echo "It's a bona-fide directory"
fi
if [[ -d "$TARFILE" ]]
我越来越[[:找不到
[[ ]]
支持ash ,但实际上并没有提供与的任何其他功能[ ]
。如果需要考虑可移植性,请坚持[ ]
并使用必要的解决方法。
缩写形式:
[ -d "$DIR" ] && echo "Yes"
if $dir is a dir, then echo "yes"
吗?
set -e
(这是Shell编程的最佳实践)。
[ -d "$DIR" ]
是经过检查的(后跟&& echo Yes
),因此我认为set -e
对脚本行为没有影响(即,如果测试失败,则脚本可以正常继续)。
要检查目录是否存在,可以使用以下简单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
一个简单的脚本来测试目录或文件是否存在:
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:无法创建目录“ tempdir”:文件存在
或完全没有用的东西:
[ -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
在subshell内部执行( ... )
,该命令不会影响调用者的当前目录。如果目录存在,则此子外壳程序和该函数仅是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解释的那样。
test -d /unreadable/exists
即使参数存在也将失败。
if [ -d "$Directory" -a -w "$Directory" ]
then
#Statements
fi
上面的代码检查目录是否存在以及是否可写。
在Bash提示符下键入以下代码:
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
find -maxdepth 1 -type d -name 'pattern'
。您介意我在您的答案中附加这个技巧吗?干杯;)
您是否考虑过只是在做自己想做的事情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
块执行。
要检查多个目录,请使用此代码:
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
:检查它是否是目录-L
:检查它是否是符号链接[ -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
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";
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
使用该file
程序。考虑到所有目录在Linux中也是文件,发出以下命令就足够了:
file $directory_name
检查不存在的文件: file blah
输出: cannot open 'blah' (No such file or directory)
检查现有目录: file bluh
输出: bluh: directory
该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
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:没有这样的文件或目录”,并且还将可以通过“ $?”检索的返回码设置为non。 -null(通常为“ 1”)。确保调用“ ls”后直接检查返回码。
if ! ls $DIR 2>/dev/null; then echo "$DIR does not exist!"; 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 exists || not exists
-ksh:找不到:[没有这样的文件或目录]
有很多好的解决方案,但是如果您不在正确的目录中,最终每个脚本都会失败。所以这样的代码:
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
--
则强烈建议使用(选项结束标记)。否则,如果您的变量包含看起来像选项的内容,则脚本将与空格一样失败。