[英]How do I check if a directory exists in a Bash shell script?
什么命令檢查目錄是否存在於 Bash 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在另一個答案中解釋了其原因。
如果變量包含空格或其他異常字符,則可能會導致腳本失敗。
在 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 條件表達式以及[
內置命令和[[
復合命令 。
我發現test
的雙括號版本使編寫邏輯測試更自然:
if [[ -d "${DIRECTORY}" && ! -L "${DIRECTORY}" ]] ; then
echo "It's a bona-fide directory"
fi
較短的形式:
# if $DIR is a directory, then print yes
[ -d "$DIR" ] && echo "Yes"
一個簡單的腳本來測試目錄或文件是否存在:
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': 文件存在
要檢查目錄是否存在,您可以使用如下簡單的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
如果文件存在並且是一個目錄,則為真。
例如:
test -d "/etc" && echo Exists || echo Does not exist
注意: test
命令與條件表達式[
(參見: man [
)相同,因此它可以跨 shell 腳本移植。
[
- 這是test
內置的同義詞,但最后一個參數必須是文字]
,以匹配開頭[
。
有關可能的選項或進一步的幫助,請檢查:
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
會給我一個標准的單行消息到標准錯誤。 它還將提供比我能夠提供的更多的信息。 通過在子shell ( ... )
中執行cd
,該命令不會影響調用者的當前目錄。 如果該目錄存在,則此子shell 和函數只是一個空操作。
接下來是我們傳遞給cd
的參數: ${1:?pathname expected}
。 這是一種更復雜的參數替換形式,下面將更詳細地解釋。
Tl;dr:如果傳遞給此函數的字符串為空,我們將再次退出子 shell ( ... )
並從函數返回並返回給定的錯誤消息。
引用ksh93
手冊頁:
${parameter:?word}
如果
parameter
已設置且非空,則替換其值; 否則,打印word
並從 shell 退出(如果不是交互式的)。 如果word
被省略,則打印一條標准消息。
和
如果上述表達式中省略了冒號
:
,則 shell 僅檢查是否設置了參數。
這里的措辭是 shell 文檔特有的,因為word
可以指代任何合理的字符串,包括空格。
在這種特殊情況下,我知道標准錯誤消息1: parameter not set
是不夠的,所以我放大了我們在這里期望的值的類型 - 目錄的pathname
。
哲學筆記:
shell 不是面向對象的語言,所以消息說pathname
,而不是directory
。 在這個級別上,我寧願保持簡單——函數的參數只是字符串。
if [ -d "$Directory" -a -w "$Directory" ]
then
#Statements
fi
上面的代碼檢查目錄是否存在以及是否可寫。
DIRECTORY=/tmp
if [ -d "$DIRECTORY" ]; then
echo "Exists"
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
在Bash shell腳本中,可以使用什么命令來檢查目錄是否存在?
實際上,您應該使用幾種工具來獲得防彈方法:
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
: 檢查是否是符號鏈接要檢查多個目錄,請使用以下代碼:
if [ -d "$DIRECTORY1" ] && [ -d "$DIRECTORY2" ] then
# Things to do
fi
檢查目錄是否存在,否則創建一個:
[ -d "$DIRECTORY" ] || mkdir $DIRECTORY
[ -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
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";
根據喬納森的評論:
如果要創建目錄但它還不存在,那么最簡單的技術是使用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
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
file="foo"
if [[ -e "$file" ]]; then echo "File Exists"; fi;
可以使用以下find
,
find . -type d -name dirname -prune -print
那里有很好的解決方案,但如果您不在正確的目錄中,最終每個腳本都會失敗。 所以這樣的代碼:
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
這個解決方案很好,因為它允許使用通配符,這是搜索文件/目錄時的一個有用功能。 唯一的問題是,如果搜索到的目錄不存在,“查找”命令將不會在標准輸出中打印任何內容(對我來說這不是一個優雅的解決方案)並且仍然會出現零退出。 也許有人可以改進這一點。
(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 [沒有這樣的文件或目錄]
使用file
程序。 考慮到 Linux 中的所有目錄也是文件,發出以下命令就足夠了:
file $directory_name
檢查不存在的文件: file blah
輸出: cannot open 'blah' (No such file or directory)
檢查現有目錄: file bluh
輸出: bluh: directory
一個班輪:
[[ -d $Directory ]] && echo true
如果要檢查目錄是否存在,無論它是真實目錄還是符號鏈接,請使用以下命令:
ls $DIR
if [ $? != 0 ]; then
echo "Directory $DIR already exists!"
exit 1;
fi
echo "Directory $DIR does not exist..."
說明:如果目錄或符號鏈接不存在,“ls”命令會給出錯誤“ls: /x: No such file or directory”,並將返回碼(您可以通過“$?”檢索)設置為非-null(通常為“1”)。 確保在調用“ls”后直接檢查返回碼。
從腳本文件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。 所以這里是完整的腳本。
作為 '[ -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
我在下面收集了一些鮮為人知的選項來檢查目錄是否存在,也包括了眾所周知的選項(其中一些可能已經在之前的答案中介紹過)。
所有示例都在Ubuntu 18.04
上進行了測試,因此它們可能並不總是適用於某些其他類型的操作系統(盡管它們中的大多數應該在大多數Linux
發行版或Mac OS
上都能順利運行)。 目錄路徑可以更改為任何目錄,在下面的示例中使用了/tmp
。
if test -d /tmp; then
echo "Directory exists"
else
echo "Directory does not exist"
fi
[ -d ]
測試運算符:if [ -d /tmp ]; then
echo "Directory exists"
else
echo "Directory does not exist"
fi
[[ -d ]]
測試運算符(這與前一個類似,但更強大):if [[ -d /tmp ]]; then
echo "Directory exists"
else
echo "Directory does not exist"
fi
-e
測試運算符(這檢查文件是否存在,它適用於文件和目錄):if [ -e /tmp ]; then
echo "Directory exists"
else
echo "Directory does not exist"
fi
ls
命令並將 output 重定向到/dev/null
:if ls -d /tmp > /dev/null 2>&1; then
echo "Directory exists"
else
echo "Directory does not exist"
fi
find
命令:if find /tmp -mindepth 1 -print -quit 2>/dev/null; then
echo "Directory exists"
else
echo "Directory does not exist"
fi
stat
命令:if stat /tmp > /dev/null 2>&1; then
echo "Directory exists"
else
echo "Directory does not exist"
fi
dirname
命令:if [ "$(dirname /tmp)" != "/tmp" ]; then
echo "Directory exists"
else
echo "Directory does not exist"
fi
readlink
命令:if readlink -e /tmp > /dev/null 2>&1; then
echo "Directory exists"
else
echo "Directory does not exist"
fi
realpath
命令:if realpath /tmp > /dev/null 2>&1; then
echo "Directory exists"
else
echo "Directory does not exist"
fi
cd
命令:if cd /tmp; then
echo "Directory exists"
cd - >/dev/null
else
echo "Directory does not exist"
fi
grep
命令:if ls -d /tmp 2>/dev/null | grep -q '/tmp'; then
echo "Directory exists"
else
echo "Directory does not exist"
fi
os
模塊:if python -c "import os; print(os.path.isdir('/tmp'))" | grep -q "True"; then
echo "Directory exists"
else
echo "Directory does not exist"
fi
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.