Проверьте, существует ли каталог в сценарии оболочки

Какую команду можно использовать для проверки, существует ли каталог в сценарии оболочки?

37 ответов

Решение

Чтобы проверить, существует ли каталог в сценарии оболочки, вы можете использовать следующее:

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

Короче форма:

[ -d "$DIR" ] && echo "Yes"
  1. Простой скрипт для проверки наличия или отсутствия dir или файла:

    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 [), поэтому он переносим через сценарии оболочки.

[ - это синоним 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 даст стандартное однострочное сообщение для stderr. Это также даст больше информации, чем я смогу предоставить. Выполняя cd внутри подоболочки ( ... )команда не влияет на текущий каталог вызывающего абонента. Если каталог существует, эта подоболочка и функция просто не активны.

Следующий аргумент, который мы передаем cd: ${1:?pathname expected}, Это более сложная форма замены параметров, которая более подробно описана ниже.

Tl; dr: если строка, переданная в эту функцию, пуста, мы снова выходим из подоболочки ( ... ) и вернитесь из функции с данным сообщением об ошибке.


Цитируя из ksh93 справочная страница:

${parameter:?word}

Если parameter устанавливается и не является нулевым, тогда подставьте его значение; в противном случае распечатайте word и выход из оболочки (если не интерактивный). Если word опускается, то печатается стандартное сообщение.

а также

Если толстая кишка : исключено из вышеприведенных выражений, тогда оболочка только проверяет, установлен ли параметр или нет.

Формулировка здесь свойственна документации оболочки, так как word может ссылаться на любую разумную строку, включая пробелы.

В данном конкретном случае я знаю, что стандартное сообщение об ошибке 1: parameter not set недостаточно, поэтому я увеличу тип ожидаемого значения - pathname каталога.

Философское примечание: оболочка не является объектно-ориентированным языком, поэтому в сообщении говорится pathnameне directory, На этом уровне я бы предпочел, чтобы все было просто - аргументы функции - это просто строки.

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
    
DIRECTORY=/tmp

if [ -d "$DIRECTORY" ]; then
    echo "Exists"
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), выгода больше, чем проблема.

Рассматривали ли вы просто делать то, что вы хотите сделать в if вместо того, чтобы смотреть, прежде чем прыгать?

IE, если вы хотите проверить существование каталога перед тем, как вводить его, попробуйте просто сделать это:

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"

Примечание: цитирование переменных - это хорошая практика.

Чтобы проверить более одного каталога, используйте этот код:

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 check проверит наличие файлов и включает в себя каталоги.

if [ -e ${FILE_PATH_AND_NAME} ]
then
    echo "The file or directory exists."
fi

Этот ответ обернут как сценарий оболочки

Примеры

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

Один лайнер:

      [[ -d $Directory ]] && echo true

Согласно комментарию Jonathan Leffler:

Если вы хотите создать каталог, а он еще не существует, тогда самым простым способом является использование mkdir -p который создает каталог - и любые отсутствующие каталоги вверх по пути - и не дает сбоя, если каталог уже существует, так что вы можете сделать все это сразу с помощью:

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

В виде троичной формы,

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

И с тестом

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

Ниже найти можно использовать,

find . -type d -name dirname -prune -print
Другие вопросы по тегам