Я хочу объединить несколько условий в операторе if if и отменить комбинацию. У меня есть следующий рабочий код для простой комбинации условий:
if [ -f file1 ] && [ -f file2 ] && [ -f file3 ] ; then
# do stuff with the files
fi
Это отлично работает. Если я хочу отрицать это, я могу использовать следующий рабочий код:
if ! ( [ -f file1 ] && [ -f file2 ] && [ -f file3 ] ) ; then
echo "Error: You done goofed."
exit 1
fi
# do stuff with the files
Это также работает как ожидалось. Однако мне приходит в голову, что я не знаю, что на самом деле там делают скобки. Я хочу использовать их только для группировки, но на самом ли деле это порождение? (Как я могу сказать?) Если так, есть ли способ сгруппировать условия, не вызывая подоболочки?
bash
shell-script
Wildcard
источник
источник
if ! [ -f file1 ] || ! [ -f file 2 ] || ! [ -f file3 ] ; then
но я хотел бы получить более общий ответ.if [[ ! -f file1 ]] && [[ ! -f file2 ]]; then
if [ ! 1 -eq 2 ] && [ ! 2 -eq 3 ]; then echo yep; fi
и это работает. Я просто всегда пишу тесты с двойными скобками по привычке. Кроме того, чтобы убедиться, что это не такbash
, я дополнительно проверил,if /bin/test ! 1 -eq 2 && /bin/test ! 2 -eq 3 ; then echo yep; fi
и это работает так же.[ ! -e file/. ] && [ -r file ]
каталоги. отрицать это, как вам нравится. конечно, это то, что-d
делает.Ответы:
Вам нужно использовать
{ list;}
вместо(list)
:Оба они являются командами группирования , но
{ list;}
выполняют команды в текущей среде оболочки.Обратите внимание, что для разделения списка от обратного слова требуется
;
in , вы также можете использовать другой разделитель. Пробел (или другой разделитель) после также требуется.{ list;}
}
{
источник
awk
чаще, чем вbash
), это необходимость в пробелах после открытой фигурной скобки. Вы упоминаете «вы можете использовать и другой разделитель»; какие-нибудь примеры?zsh
, вы можете использовать пробелы&
это также разделитель, который вы можете использовать{ echo 1;:&}
, также можно использовать несколько символов новой строки.they must be separated from list by whitespace or another shell metacharacter.
Баша они:metacharacter: | & ; ( ) < > space tab
. Для этой конкретной задачи я считаю, что любой из них& ; ) space tab
будет работать. .... .... Из zsh (как комментарий)each sublist is terminated by
&',
&!', or a newline.
Вы можете полностью использовать
test
функциональность, чтобы достичь того, что вы хотите. Со страницы руководстваtest
:Таким образом, ваше состояние может выглядеть так:
Для отрицания используйте экранированные скобки:
источник
Чтобы переносить отрицание сложного условного выражения в оболочке, вы должны либо применить закон Де Моргана, и полностью отложить отрицание внутри
[
вызовов ...... или вы должны использовать
then :; else
...if ! command
недоступно и не доступно[[
.Если вам не нужна полная переносимость, не пишите сценарий оболочки . Вы на самом деле более вероятно найдете
/usr/bin/perl
в случайно выбранном Unix, чем выbash
.источник
!
это POSIX, который в настоящее время достаточно портативен. Даже системы, которые все еще поставляются с оболочкой Bourne, также имеют POSIX sh где-то еще в файловой системе, которую вы можете использовать для интерпретации вашего стандартного синтаксиса./bin/sh
. Сценарии Autoconf делают то, что вы предлагаете, но я думаю, что мы все знаем, как мало это одобрения.другие заметили группировку
{
составных команд;}
, но если вы выполняете идентичные тесты на наборе, вы можете использовать другой вид:... как показано в другом месте
{ :;}
, нет проблем с вложением сложных команд ...Обратите внимание, что выше (как правило) тестирует для обычных файлов. Если вы ищете только для существующих , читаемых файлов , которые не являются каталогами:
Если вам все равно, являются ли они каталогами или нет:
... работает для любого читаемого , доступного файла, но, вероятно, зависнет для писателей fifos w / out.
источник
Это не полный ответ на ваш главный вопрос, но я заметил, что вы упоминаете комплексное тестирование (читаемый файл) в комментарии; например,
Вы можете немного закрепить это, определив функцию оболочки; например,
Добавить обработку ошибок (например,
[ $# = 1 ]
) по вкусу. Первоеif
утверждение, приведенное выше, теперь может быть сжато дои вы можете сократить это еще больше, сократив имя функции. Аналогично, вы можете определить
not_readable_file()
(илиnrf
для краткости) и включить отрицание в функцию.источник
readable_files() { [ $# -eq 0 ] && return 1 ; for file in "$@" ; do [ -f "$file" ] && [ -r "$file" ] || return 1 ; done ; }
(Отказ от ответственности: я проверил этот код, и он работает, но он не был однострочным. Я добавил точки с запятой для публикации здесь, но не проверял их размещение.)if readable_files file1 file2 file3
, не будет знать , выполняла ли функция AND или OR - хотя (a) я думаю, что это довольно интуитивно понятно , (b) если вы не распространяете сценарий, это достаточно хорошо, если вы понимаете его и (c) поскольку я предложил сократить имя функции до неясности, я не в состоянии говорить о читабельности. … (Продолжение)for file in "$@" ; do
наfor file do
- по умолчаниюin "$@"
, и (несколько нелогично) эта функция;
не только не нужна, но и не рекомендуется.Вы также можете отменить тесты фигурных скобок, чтобы повторно использовать исходный код:
источник
||
вместо&&
||
будет выполнять предикат, если какой-либо из файлов отсутствует, а не тогда и только тогда, когда все файлы отсутствуют. НЕ (А И В И С) - это то же самое, что (НЕ А) И (НЕ В) И (НЕ С); увидеть оригинальный вопрос.||
вместо&&
. Смотрите мой первый комментарий ниже самого моего вопроса.not (a and b)
же, как(not a) or (not b)
. См en.wikipedia.org/wiki/De_Morgan%27s_lawsДа, команды внутри
(...)
выполняются в подоболочке.Чтобы проверить, есть ли у вас подоболочка, вы можете сравнить PID вашей текущей оболочки с PID интерактивной оболочки.
Пример вывода, демонстрирующий, что скобки порождают подоболочку, а фигурные скобки не:
источник
()
порождает недоразвитие .. возможно, вы имели в виду{}
....echo $$ && ( echo $$ )
чтобы сравнить PID, и они были одинаковыми, но как раз перед тем, как я отправил комментарий о том, что вы ошиблись, я попробовал еще одну вещь.echo $BASHPID && ( echo $BASHPID )
дает разные PIDecho $BASHPID && { echo $BASHPID; }
дать тот же PID, который вы предложили бы в этом случае. Спасибо за образование$BASHPID
, это еще одна вещь, которую мне не хватало.