簡體   English   中英

如何檢查目錄是否存在於 Bash shell 腳本中?

[英]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"
  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將給出如下錯誤:

    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 testman [
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

同樣的事情適用於cdmvrm等...如果您在不存在的文件上嘗試它們,它們將退出並顯示錯誤並打印一條消息說它不存在,然后您的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

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";

根據喬納森的評論:

如果要創建目錄但它還不存在,那么最簡單的技術是使用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

以一種三元形式,

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

並通過test

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

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。 所以這里是完整的腳本。

https://pastebin.com/QF2Exmpn

作為 '[ -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

  1. 使用測試命令:
if test -d /tmp; then
  echo "Directory exists"
else
  echo "Directory does not exist"
fi

  1. 使用[ -d ]測試運算符:
if [ -d /tmp ]; then
  echo "Directory exists"
else
  echo "Directory does not exist"
fi
  1. 使用[[ -d ]]測試運算符(這與前一個類似,但更強大):
if [[ -d /tmp ]]; then
  echo "Directory exists"
else
  echo "Directory does not exist"
fi
  1. 使用-e測試運算符(這檢查文件是否存在,它適用於文件和目錄):
if [ -e /tmp ]; then
  echo "Directory exists"
else
  echo "Directory does not exist"
fi
  1. 使用ls命令並將 output 重定向到/dev/null
if ls -d /tmp > /dev/null 2>&1; then
  echo "Directory exists"
else
  echo "Directory does not exist"
fi
  1. 使用find命令:
if find /tmp -mindepth 1 -print -quit 2>/dev/null; then
  echo "Directory exists"
else
  echo "Directory does not exist"
fi
  1. 使用stat命令:
if stat /tmp > /dev/null 2>&1; then
  echo "Directory exists"
else
  echo "Directory does not exist"
fi
  1. 使用dirname命令:
if [ "$(dirname /tmp)" != "/tmp" ]; then
  echo "Directory exists"
else
  echo "Directory does not exist"
fi
  1. 使用readlink命令:
if readlink -e /tmp > /dev/null 2>&1; then
  echo "Directory exists"
else
  echo "Directory does not exist"
fi
  1. 使用realpath命令:
if realpath /tmp > /dev/null 2>&1; then
  echo "Directory exists"
else
  echo "Directory does not exist"
fi
  1. 使用cd命令:
if cd /tmp; then
  echo "Directory exists"
  cd - >/dev/null
else
  echo "Directory does not exist"
fi
  1. 使用grep命令:
if ls -d /tmp 2>/dev/null | grep -q '/tmp'; then
  echo "Directory exists"
else
  echo "Directory does not exist"
fi
  1. 使用 Python 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM