hi, Tue, Nov 21, 2017 at 01:34:30, spell wrote about "Re: [freebsd] test и пустые строки":
> > Я бы перефразировал: всплыло некорректное использование команды test. > > О, это всё объясняет :) Спасибо. > Только ни разу не очевидно, что null string в случае "[ $str ]" допустим, > а в случае "[ -n $str ]" - нет. И тем более что оно молча fallback-ает в > treating an option as a regular string. А какой собственно у неё выход? Вот запускается test. Неважно, в каком виде - как test или как [ (во втором случае оно просто финальный ] не считает параметром). У неё на входе argc с количеством параметров и argv с их строками. И теперь надо неким святым духом опознать, что и как было задано на входе, что автор скрипта подразумевал как параметр, а что как операция? Когда видим какую-нибудь -n, это опция самой test, опция вызванного скрипта, которую этот test проверяет, прочтённая из файла строка, имя файла или что-то иное? Отличить их так нельзя, в отличие от "полноценного" языка программирования, где чётко видно, где одно, а где другое. И при этом неважно, у нас какого стиля язык. Например, для C++ if (a != b && s1 != "!=" && s2 == "&&") { puts("ой всё"); } или для LISP (неважно, какой диалект) (if (and (= a b ) (not (streq (s1 "!=")) (streq s2 "&&"))) (puts "ой всё")) синтаксис даёт их различать так, что спутать невозможно. А для test такого нет. Уж такой интерфейс достался, извините. Поэтому, для test есть формы гарантированно надёжного использования проверок, которые не страдают от того, что где-то какое-нибудь "=" оказалось операцией самого test, а где-то - аргументом для этой операции. Если у него два аргумента и первый равен "-n", это проверка на непустоту. Если три аргумента и средний равен "=", это проверка на текстовое равенство. Если три аргумента и средний равен "lt", это проверка на числовое "меньше". И ещё несколько аналогичных операций. Собственно, это всё, что гарантируется стандартом без побочных эффектов (см. ниже - можете полный набор сами прочитать). А теперь о случаях типа один аргумент, который проверяет на непустоту. Тут одновременно и наследие (в смысле legacy), и простой сокращённый случай - но это уже фактически та простота, которая не то хуже воровства, не то "просто" требует очень внимательного отношения к себе. Как и вообще многое в шелле и вокруг. Test тут далеко не единственный пример. Возьмём grep. Мы можем десятки раз писать что-то типа "grep vasya /var/log/auth.log", но если шаблон приходит снаружи, мы обязаны написать: grep -e "$pattern" "$file" причём важны и -e - указать, что тут шаблон, и кавычки - чтобы шелл сохранил это одним аргументом, независимо от количества параметров в нём. В случае test имеем несколько наслоений интерфейса - да, таки это legacy. Первый, самый ранний, это тот самый одноаргументный вариант и прочее связанное с ним. Когда осознали возможность конфликта с опциями, добавили гарантированный вариант. Но из-за принципиальной проблемы на уровне передачи аргументов оказалось, что есть относительно немного надёжных форм. В частности, если не применяется XSI расширение со скобками, то гарантия даётся на корректный парсинг только одной проверки; если нужно две и больше - это делается на уровне вызывающего шелла, а не самой test. Например, вы не можете написать if [ "$a" = 1 -a "$b" = 2 ]; then надо писать вместо этого if [ "$a" = 1 ] && [ "$b" = 2 ]; then Зато при этом не надо ставить префиксы аргументам. А вот если допустить проверку с объединителями стиля XSI (-a, -o, скобки), можно писать несколько условий. Но тут начинается новая проблема: а что, если одним из параметров придёт -a, -o, числовая операция типа -eq, или скобка? Вот тут уже для строковых операций можно исключить это проверками вида: if [ "x$a" = x1 -a "x$b" = x2 ]; then а для числовых аналогично подставить ноль (по крайней мере для целых неотрицательных... иначе, боюсь, тут вообще остаётся только делать одну проверку за раз. Стандарт можете почитать сами тут: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html а дальше посмотреть на то, как более дружественные шеллы (bash, zsh...) борются с последствиями этого. Как они расширяют сам test, как эмпирически пытаются разбирать сложные случаи, как вместо этого можно пользоваться конструкциями типа $((...)), и так далее. (Если бы мне дали это всё исправить, я бы сделал вариант с только префиксной записью всех вариантов (например, `= arg1 arg2' вместо `arg1 = arg2'), начальную опцию для него, и загнал бы это кувалдой в стандарт. Примеры такого подхода есть - printf в стандарте вместо проблемного echo. Проблемы неоднозначного парсинга были бы решены с гарантией и с возможностью расширения на любые операции. Но сейчас имеем то, что имеем.) -netch- _______________________________________________ freebsd mailing list freebsd@uafug.org.ua http://mailman.uafug.org.ua/mailman/listinfo/freebsd