8

Я писал несколько сценариев и написал что-то вроде

ARTIFACTS="/SOME/PATH"
[ -d $ARTIFCATS ] && rm -rf $ARTIFACTS/*

Случилось так, что по глупости я выполнил вторую строку, не выполняя первую. Оказалось, что [-d ""] возвращает true, и выражение стало

rm -rf /*

К счастью, это была только тестовая машина, и я не был sudo, но хотя я потерял некоторые данные

Мой вопрос, почему [-d ""] возвращает true?? документация ясно заявляет, что проверяет, существует ли путь и является ли папка

Я решил проблему с помощью

[ -e $ARTIFACTS ]
который, кажется, работает

ура

4 ответа4

9

1. Эти два теста возвращают true:

# [ -d ] && echo true || echo false
true
# [ -d $SOME_UNSET_VAR ] && echo true || echo false
true

в соответствии с POSIX (как объяснено @Tim).

2. Но это возвращает ложь (не верно, как указано в вопросе)

# [ -d "" ] && echo true || echo false
false

потому что test вызывается с двумя аргументами (хотя второй является пустой строкой).

3. Вот почему хорошей практикой является использование [[ … ]] вместо test ([ … ]), который наиболее (все?) текущие снаряды обеспечивают. Эта конструкция проверяет, достаточно ли вы указали аргументов (в противном случае выдает ошибку и прерывает работу).

# [[ -d ]] && echo true || echo false
bash: unexpected argument `]]' to conditional unary operator
bash: syntax error near `]]'

или просто ведет себя так, как и следовало ожидать:

# [[ -d $SOME_UNSET_VAR ]] && echo true || echo false
false

4. И, как отмечает @Gilles, еще важнее сделать двойные кавычки. Так что -d "$SOME_UNSET_VAR" расширяется до -d "" и возвращает ложь даже с test (равным случаю 2). Следовательно, это также совместимо с оболочкой Bourne sh:

# [ -d "$SOME_UNSET_VAR" ] && echo true || echo false
false

протестировано с bash 3.00.16(1) и 4.1.5(1)

6

На этот вопрос уже ответили на StackOverflow. В нем говорится, что согласно стандарту POSIX, test всегда должен возвращать успешный результат, если он вызывается с точно одним непустым аргументом (и без других аргументов).

Это также должно быть в случае с test -e (и фактически это происходит в моей системе), поэтому будьте осторожны.

Вместо этого используйте:

[ -d "$ARTIFACTS" ]

Затем будет вызван test с двумя аргументами, даже если переменная пуста, и в этом случае вернет false.

4

Я решил проблему с помощью [-e $ ARTIFACTS], который, кажется, работает

Вы не правы. Это работает, потому что $ARTIFACTS теперь настроен на что-то.

Когда переменная не установлена, то говоря

[ -d $SOMEVAR ]

или же

[ -e $SOMEVAR ]

оба оценили бы как true потому что это подразумевает высказывание

[ -d ]

а также

[ -e ]

соответственно. (Сказать [ foobar ] всегда будет верно.)

поговорка

set -u

пригодится в таких ситуациях. help set скажет вам:

  -u  Treat unset variables as an error when substituting.
4

Убедитесь, что вы установили переменную ARTIFACTS и проверяли ARTIFCATS. Возможно опечатка?

В любом случае, -d так же, как и -e, будут давать одинаковые результаты для неустановленных переменных.

Поэтому используйте двойные кавычки, и это поможет вам.

ARTIFACTS="/SOME/PATH"
[ -d "$ARTIFACTS" ] && rm -rf -- "$ARTIFACTS/"*

ПРИМЕЧАНИЕ. Если в вашем //SOME /PATH есть какая-либо папка с пробелом, упомянутый вами скрипт сломается с ошибкой "ожидается двоичный оператор".

Пример:

ARTIFACTS="/home backup/"

1) [ -d $ARTIFACTS ] && rm -rf $ARTIFACTS/*
bash: [: /home: binary operator expected

2) [ -d "$ARTIFACTS" ] && rm -rf "$ARTIFACTS"/*

все будет хорошо. Не забудьте также поставить кавычки в вызове rm (rm -rf $ARTIFACTS с радостью удалит /home затем будет жаловаться на backup/* не существует).

Кроме того, включение -L check позволит убедиться, что это каталог, а не просто символическая ссылка на каталог.

Итак, в основном,

[ -d "$ARTIFACTS" && ! -L "$ARTIFACTS" ] && rm -rf -- "$ARTIFACTS"/*

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .