Проверка на наличие нескольких каталогов

8

Я хочу проверить наличие нескольких каталогов, скажем dir1, dir2и dir3в рабочем каталоге.

У меня есть следующее

if [ -d "$PWD/dir1" ] && [ -d "$PWD/dir2" ] && [ -d "$PWD/dir3" ]; then
    echo True
else
    echo False
fi

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

Цель состоит в том, чтобы проверить наличие нескольких каталогов и отсутствие других.

Я использую Bash, но переносимый код предпочтительнее.

утонченность
источник
1
«Цель состоит в том, чтобы проверить наличие нескольких каталогов и отсутствие других». Что ж, ваш пример проверяет наличие всех перечисленных каталогов. Можете ли вы уточнить эту часть? Это все в списке или что-нибудь в списке? Вам нужна проверка того, что переданные значения на самом деле являются каталогами, а не файлами других типов?
Сергей Колодяжный
1
Вам не нужно $PWD, кстати. [ -d "$PWD/dir1"]эквивалентно [ -d "dir1" ].
Тердон

Ответы:

5

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

ls "$PWD/dir1" "$PWD/dir2" "$PWD/dir3" >/dev/null 2>&1 && echo All there

Я перенаправляю вывод и stderr для /dev/nullтого, чтобы он исчез, так как нам важен только код выхода ls, а не его вывод. Все, что написано, /dev/nullисчезает - оно не записывается на ваш терминал.

Джефф Шаллер
источник
Можете ли вы помочь мне понять эту команду? Я знаю, что такое файловые дескрипторы. Я знаю, что 1это стандартный вывод, 2это стандартный вывод, и я знаю, что такое перенаправление. Я не понимаю значения /dev/null, и я не знаю, как разобрать команду.
Elegance
@ Элегантность Я добавил небольшое объяснение. Более подробные ответы относительно / dev / null см. В разделах unix.stackexchange.com/questions/163352/… и unix.stackexchange.com/questions/438130/…
Джефф Шаллер
Все еще пытаюсь понять, как работает синтаксис. Я прочитал, что &>filenameперенаправляет как stdout и stderr filename. Так нельзя ли упростить команду (по крайней мере, для меня это проще) как ls "$PWD/dir1" "$PWD/dir2" "$PWD/dir2" &>/dev/null && echo All there?
Elegance
3
(1) Вы, вероятно, должны использовать -dопцию (а), поэтому она lsтребует только для статистики каталогов, а не их чтения, и (б), чтобы команда выполнялась успешно, даже если у пользователя нет доступа на чтение к каталогам. (2) Я не вижу никакой причины для использования, "$PWD/"кроме как для защиты от каталогов, имена которых начинаются с -(и, конечно, есть лучшие способы сделать это).
G-Man говорит: «Восстановите Монику»
1
выполнение этой команды может занять гораздо больше времени, чем тест из исходного вопроса. также он не проверяет каталоги.
Jasen
9

Я бы зациклился

result=True
for dir in \
        "$PWD/dir1" \
        "$PWD/dir2" \
        "$PWD/dir3" 
do
    if ! [ -d "$dir" ]; then
        result=False
        break
    fi
done
echo "$result"

breakВызывает петлю к короткому замыканию, так же , как ваша цепь&&

Гленн Джекман
источник
5

Цикл может быть более элегантным:

arr=("$PWD/dir1" "$PWD/dir2" "$PWD/dir2")
for d in "${arr[@]}"; do
    if [ -d "$d"]; then
        echo True
    else
        echo False
    fi
done

Это Баш. Более портативным является Ш. Там вы можете использовать позиционный массив:

set -- "$PWD/dir1" "$PWD/dir2" "$PWD/dir2"

Затем зациклить его использовать "$@".


источник
5

Почему бы просто:

if [ -d "dir1" -a -d "dir2" -a -d "dir3" ]; then
    echo True
else
    echo False
fi
Дэвид Конрад
источник
По сути, это то, с чего начался ФП,But I suspect there is a more elegant way of doing this
Джефф Шаллер
5
Также POSIX не рекомендует использовать -a: « -aи -oбинарные операторы первичных (...) помечены как устаревшие»: pubs.opengroup.org/onlinepubs/9699919799
Elegance
@JeffSchaller Это более кратко, поскольку все это делается за один вызов для проверки.
Дэвид Конрад
2
это совсем не то же самое, оригинал вызывает test(иначе [) три раза, это вызывает его один раз,
Jasen
1
pubs.opengroup.org/onlinepubs/9699919799/utilities/… является более точной ссылкой на расположение оператора POSIX.
G-Man говорит «Восстановить Монику»
4

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

# Returns success if all given arguments exists and are directories.
ck_dir_exists () {
    for dir do
        [ -d "$dir" ] || return 1
    done
}

# Returns success if none of the given arguments are existing directories.
ck_dir_notexists () {
    for dir do
        [ ! -d "$dir" ] || return 1
    done
}

Пример:

$ mkdir dir1 dir2
$ ck_dir_exists dir1 dir2; echo $?
0
$ ck_dir_exists dir1 dir2 dir3; echo $?
1
$ ck_dir_notexists dir1 dir2 dir3; echo $?
1
$ ck_dir_notexists dir3 dir4; echo $?
0
Кусалананда
источник
1

Цель состоит в том, чтобы проверить наличие нескольких каталогов и отсутствие других.   [Акцент добавлен]

Основываясь на ответе Гленна Джекмана , мы можем проверить отсутствие других имен:

результат = True
для режиссера в \
        "$ PWD / dir1" \
        "$ PWD / dir2" \
        "$ PWD / dir3" 
делать
    если ! [-d "$ dir"]; тогда
        результат = False
        перемена
    фи
сделанный
для режиссера в \
        "$ PWD / dir4" \
        "$ PWD / dir5" \
        "$ PWD / dir6" 
делать
    if [-e "$ dir"]; затем # Примечание: нет «!»
        результат = False
        перемена
    фи
готово 
эхо "$ result"
Я имел обыкновение [ -e "$dir" ]проверять, "$dir"существует ли ; то есть, если dir5существует, но является файлом, результатом является False. Если вы хотите только проверить, являются ли имена во второй группе каталогами, используйте [ -d "$dir" ], как в первом цикле.

Поскольку мы говорим о проверке наличия вещей в текущем рабочем каталоге, возможно, нет необходимости указывать $PWD/имена; просто делать

для режиссера в \
        "dir1" \
        "dir2" \
        "Dir3" 
делать
      ︙

G-Man говорит: «Восстанови Монику»
источник