Питання Перевірте наявність каталогу в скрипті оболонки


Яка команда може бути використана для перевірки наявності каталогу в межах сценарію оболонки?


2999
2017-09-12 20:06


походження




Відповіді:


Щоб перевірити наявність каталогу в сценарії оболонки, ви можете використовувати наступне:

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

Однак, як Джон Еріксон вказує на те, що наступні команди можуть не працювати, як передбачено, якщо ви не врахували, що символічна посилання на каталог також передасть цю перевірку. Наприклад, виконуючи це:

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 в іншому відповідь.

Якщо змінні містять пробіли або інші незвичні символи, це може спричинити неспроможність сценарію.


4144
2017-09-12 20:07



Якщо ви хочете грати безпечно за допомогою інструментів GNU, скористайтеся -- настійно рекомендується (маркер кінцевих параметрів). В іншому випадку, якщо ваша змінна містить те, що виглядає як параметр, скрипт буде збігатися так само, як і пробіли. - Marc Mutz - mmutz
Для сучасних версій bash, ksh та ін [...] є вбудованим - fpmurphy1
Одне що слід пам'ятати: [ ! -d "$DIRECTORY" ] буде правдою, якщо $DIRECTORY не існує, або якщо робить існує, але не є каталогом. Розглянемо щось подібне if [ ! -d "$DIRECTORY" ] ; then mkdir "$DIRECTORY" ; fi; це не вийде, якщо "$DIRECTORY" це файл (Звичайно, слід перевірити, чи є mkdir все-таки вдалося досягти успіху; існує цілий ряд причин, з яких він може зазнати невдачі.) - Keith Thompson
Можливо, слід зазначити, що як тільки перевірка буде виконана, ситуація може змінитися вже через інші процеси. У багатьох випадках краще просто створити або використовувати каталог і реагувати на невдачу. - Alfe
Замість тестування для обох каталогів (-d) та символічне посилання (-L), простіше просто додати косу риску до змінної, як-от if [ -d "${THING:+$THING/}" ]. Каталог не запередить додаткову косу риску. Файл буде оцінюватися як false. Пустий залишиться порожнім, тому невірно. І символьне посилання буде вирішено до місця призначення. Звичайно, це залежить від вашої мети. Якщо ти хочеш йти там, це добре. Якщо ти хочеш видалити його, то код у цьому відповіді краще. - ghoti


Не забудьте завжди загорнути змінні у подвійні лапки, коли вони посилаються на них скрипт bash Діти в ці дні ростуть з ідеєю, що вони можуть мати пробіли та багато інших смішних персонажів у своїх іменах каталогів. (Простір! За моїми днями у нас не було ніяких фантастичних простору!;))

Одного разу один з цих дітей запустить ваш сценарій з $DIRECTORY встановлений в "My M0viez" і ваш сценарій підірве. Ви цього не хочете. Так що використовуйте це.

if [ -d "$DIRECTORY" ]; then
    # Will enter here if $DIRECTORY exists, even if it contains spaces
fi

454
2017-09-15 22:00



Ще одна причина використання подвійних лапок - у випадку, якщо з якоїсь причини не встановлено $ DIRECTORY. - Jon Ericson♦
"завжди обертати змінні у подвійних лапках ... у скрипті bash". Для bash, не технічно необхідно при використанні [[...]]; побачити tldp.org/LDP/abs/html/testconstructs.html#DBLBRACKETS (Примітка: немає розбиття слів): "Відсутнє розширення файлу або розщеплення слів між [[і]], але є розширення параметра та заміна команди". - michael
Каталоги на Unix / Linux не повинні мати пробілів, і згодом скрипти не повинні адаптуватися до нього. Це досить погано, Windows підтримує це, з усіма наслідками для сценаріїв Windows, але, будь ласка, для любові до чогось не потрібно вводити непотрібні вимоги. - tvCa
@tvCa Я вважаю, що користувачі зазвичай вважають за краще допускати більшу гнучкість у своїх назвах каталогів, а не змушують розробників полегшувати ситуацію. (Фактично, коли мова йде про довгі імена файлів, я вважаю, що без пробілів це біль, оскільки це вбиває словотворення, хоча я і сам постраждав в минулому, не рахуючи шляхів із пробілами в сценаріях та програмах). - JAB
Ха. Простір - це просто символи, які зазвичай не мають гліфів. У будь-якому випадку, ви можете уникнути їх зворотною рисою. - uchuugaka


Зверніть увагу на -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 Баш умовних виразів і [ вбудована команда і [[ складова команда.


204
2017-09-12 20:26



або, припускаючи, що потрібно лише працювати над каталогами (і посилання можна ігнорувати) => if [ -d tmpdir -a ! -L tmpdir ]; then echo "is directory"; rmdir tmpdir; fi ... або для однієї команди, яка працює як на посиланнях, так і на дисках: rm -r tmpdir - michael


Я знаходжу подвійна дужка версія test робить написання логічних тестів більш природними:

if [[ -d "${DIRECTORY}" && ! -L "${DIRECTORY}" ]] ; then
    echo "It's a bona-fide directory"
fi

198
2017-09-12 21:33



за if [[ -d "$TARFILE" ]] Я отримую [[: не знайдено - TheVillageIdiot
точно [[: не знайдено - Hedgehog
@TheVillageIdiot і @Hedgehog, ви використовуєте баш-оболонку? Подвійний кронштейн не підтримується універсально. Ось відповідь на це питання: stackoverflow.com/questions/669452/... - yukondude
І в Busybox зола з параметрами компіляції за замовчуванням [[ ]] підтримується, але фактично не надає ніякої іншої функції [ ]. Якщо переносимість є проблемою, дотримуйтесь [ ] і використовуйте необхідні обхідні шляхи. - dubiousjim
... якщо використовує bash-конструктори в скрипті оболонки, перший рядок сценарію має бути: #! / bin / bash (а не #! / bin / sh, ksh та ін) - michael


Стисла форма:

[ -d "$DIR" ] && echo "Yes"

125
2017-09-12 21:08



Чи працює так: if $dir is a dir, then echo "yes"? Трохи пояснення допоможе :) - Martijn
cmd && other є загальним скороченням для if cmd; then other; fi - це працює з більшістю мов програмування, які підтримують булеву логіку, і відоме як оцінка короткого замикання. - tripleee
Поведінка не така ж set -e (який є а краща практика оболонки програмування) - dolmen


Щоб перевірити наявність каталогу, ви можете скористатись простим, якщо структура виглядає так:

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 

119
2018-04-08 02:50





if [ -d "$DIRECTORY" ]; then  
    # Here if $DIRECTORY exists  
fi

94
2018-04-15 08:07





Ви можете використовувати test -d (побачити man test)

-d file       Дійсно, якщо файл існує і є каталогом.

Наприклад:

test -d "/etc" && echo Exists || echo Does not exist

Примітка test команда така ж, як умовний вираз [ (побачити: man [), так що він портативний через скрипти командного рядка.

[ - Це синонім для test вбудований, але останній аргумент повинен бути буквальним ], щоб відповідати відкриттю [.

Для можливих варіантів або подальшої допомоги перевірте:

  • help [
  • help test
  • man test або man [

74
2017-09-12 21:25





Або для чогось абсолютно марного:

[ -d . ] || echo "No"

55
2017-08-17 14:02



Ніколи не буде друкувати "Ні". Поточний каталог завжди існує, якщо його не видалити іншим потоком чи іншими способами. - Jahid
Ідеальний зразок :), враховуючи, що як "унікальні" - це деякі відповіді у порівнянні з прийнятою відповіддю - Sergey Sargsyan
Чому це так багато разів виправдано? Він не відповідає на питання. - codeforester


Ось дуже прагматична ідіома:

(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. На цьому рівні, я вважаю за краще тримати це простіше - аргументи функції - це просто рядки.


46
2017-08-09 21:43



Це робить більше, ніж тільки перевіряє існування: це перевірка доступності на вашому рівні користувача. Тому питання стоїть існування тільки Отже, правильна відповідь test -d як пояснив @Grundlefleck. - F. Hauri
@ Ф. Хаурі - він більше не питав, це правда. Однак я виявив, що мені, як правило, потрібно знати більше, ніж це. - Henk Langeveld
І мені ніколи не здавалося, що жоден тест не може бути вирішальним, якщо він не працює як корінь. test -d /unreadable/exists не вийде, навіть якщо аргумент існує. - Henk Langeveld