Вопрос или проблема
Я хотел бы использовать стандартные параметры, т.е. мой минимально воспроизводимый пример:
#!/usr/bin/zsh
a=${1:a}
printf 'a: "%s"\n' "${a}"
b=${2:./build}
printf 'b: "%s"\n' "${b}"
Я ожидал увидеть, при запуске ./demo.zsh
без аргументов:
a: "a"
b: "./build"
Вместо этого я получаю
a: ""
./demo.zsh:4: bad floating point constant
- почему
${1:a}
кажется предполагает, что$1
установлен и ненулевой, но развернутый$a
является пустой строкой? - откуда возникает ошибка при парсинге с плавающей точкой? Если я заменяю
./build
наbuild
, появляется сообщение об ошибке:b
является неизвестным модификатором.
Если я запускаю ./demo.zsh asdf bar
, я получаю
a: "/tmp/fasf"
./demo.zsh:4: bad floating point constant
что, честно говоря, еще более сбивает с толку; откуда взялось /tmp/
(это текущий каталог).
Это основывается на комментарии от Stéphane.
В оболочке Zsh ${1:a}
это то же самое, что и $1:a
, что означает применение модификатора :a
к $1
. Модификатор :a
документирован в zshexpn(1)
:
a Превращает имя файла в абсолютный путь: добавляет текущий
каталог, если необходимо; удаляет сегменты пути `.`; и
удаляет сегменты пути `..` и сегменты, которые непосредственно
предшествуют им.
Следовательно, ${1:a}
будет пустой строкой, если $1
пуст или не установлен. Это будет путь, начинающийся с /tmp/fasf
, если $1
это какая-то непустая строка, и ваш текущий каталог был /tmp/fasf
.
:.
не является допустимым модификатором в том же смысле, что и :a
, но расширение ${1:n}
будет допустимым для целого числа n
и вернет конец строки в $1
, начиная с позиции n
. Это наследие от оболочек ksh88
и ksh93
. Это означает, что так как .
не является допустимым модификатором, оболочка пытается интерпретировать его как арифметическое выражение для целей вычисления подстроки. Вот почему вы получаете ошибку для ${2:./build}
, строка ./build
не может быть использована в качестве смещения.
В конечном итоге, вы хотели использовать одно из стандартных ${1-a}
или ${1:-a}
расширений для предоставления значения по умолчанию в случае, если $1
не установлен или пуст.
${1:a}
Этот синтаксис неправильный для предоставления значений по умолчанию. Он пытается использовать a как модификатор, что не соответствует вашему намерению.
Сообщения об ошибках bad floating point constant
и unknown modifier
возникают из-за того, что zsh пытается интерпретировать a
и ./build
как модификаторы или специальный синтаксис, которыми они не являются.
Я воспроизвел скрипт с Bash
, и он должен действительно работать так же в Zsh
.
#!/bin/bash
a=${1:-a}
printf 'a: "%s"\n' "${a}"
b=${2:-./build}
printf 'b: "%s"\n' "${b}"
Вывод 1:
$:. ./test sss fff
a: "sss"
b: "fff"
Вывод 2:
$:. ./test
a: "a"
b: "./build"
Синтаксис ${1:a}
не является правильным способом предоставления значения по умолчанию для позиционного параметра.
Следует использовать ${1:-default}
, чтобы предоставить значение по умолчанию, если параметр не установлен или пуст.
${1:-a}
Это означает, что если $1
не установлен или пуст, используйте a в качестве значения по умолчанию.
${2:-./build}
Это означает, что если $2
не установлен или пуст, используйте ./build
в качестве значения по умолчанию.
.
Ответ или решение
Вопрос, предложенный вам для анализа, связан с неправильным использованием синтаксиса подстановки в оболочке Zsh и связанными ошибками. Zsh предлагает множество функций для управления переменными и их подстановкой, и понимание этих функций помогает избежать ошибок и непредвиденного поведения скриптов. Давайте разберем ситуацию подробно.
Теория (Theory)
Рассмотрим начальный пример кода:
#!/usr/bin/zsh
a=${1:a}
printf 'a: "%s"\n' "${a}"
b=${2:./build}
printf 'b: "%s"\n' "${b}"
Этот скрипт имеет цель задать стандартные параметры, если не переданы соответствующие аргументы. Оператор ${1:a}
предполагает наличия файла и должен превратить относительный путь в абсолютный. Однако использование этого выражения является неправильным для замены значения по умолчанию параметра.
В Zsh модификатор :a
используется для обработки имен файлов. Документация утверждает, что он превращает имя файла в абсолютный путь, добавляя текущий каталог, если это необходимо, и убирает сегменты пути .
и ..
. Этот модификатор никак не связан с подстановкой значений по умолчанию.
Использование конструкции ${2:./build}
также некорректно, так как символ :
в данном контексте предполагает, что слева и справа от него должны присутствовать специальные модификаторы, чего здесь нет. Ошибка «bad floating point constant» указывает, что Zsh пытается интерпретировать символы после двоеточия как арифметическое выражение, ожидая числовое значение, а не строковое.
Для достижения ожидаемого результата следует использовать форму подстановки ${parameter:-default_value}
, которая гарантированно возвращает заданное значение default_value
, если parameter
не определен или равен null.
Пример (Example)
Следующий исправленный пример демонстрирует правильный подход:
#!/usr/bin/zsh
a=${1:-a}
printf 'a: "%s"\n' "${a}"
b=${2:-./build}
printf 'b: "%s"\n' "${b}"
Используя ${1:-a}
и ${2:-./build}
, скрипт корректно возвращает a
, когда $1
не установлен, и возвращает ./build
, когда $2
не установлен. Здесь конструкция ${parameter:-word}
обеспечивает подстановку word
только в случае, если parameter
не задан или равен пустой строке.
Применение (Application)
Применим вышеописанную теорию для разбора ошибок и их устранения в Zsh. При написании скриптов на Zsh важно учитывать:
- Различие в синтаксисе модификаторов и подстановки значений по умолчанию.
- Тщательная работа с параметрами командной строки и обеспечение их значений по умолчанию.
- Диагностика и устранение ошибок при помощи изучения справочной документации Zsh, такой как
zshexpn
.
Используя правильные конструкции, вы можете обеспечить надежную работу скриптов, которые обрабатывают аргументы командной строки с заданием значений по умолчанию. Применяя методики внимательного чтения документации и осознанного выбора синтаксиса, вы избежите множества типичных ошибок, которые могут затруднять отладку и сопровождение скриптов.
Таким образом, следуя подходу TEA, вы сможете минимизировать ошибки, использовать возможности языка Zsh на полную мощность, а также улучшить качество и долговечность ваших скриптов. В результате этого подхода ваш скрипт будет работать как в иных оболочках, так и в Zsh, при условии, что корректная версия оболочки заранее определена в заголовке скрипта (#!/usr/bin/zsh
). Это критично для обеспечения интероперабельности в разных средах.
Заключение
В завершение важно подчеркнуть, что написание и сопровождение скриптов требует глубокого понимания синтаксиса и особенностей поведения системы. Хоть Zsh и обладает схожестью с другими оболочками, специфические расширения и конструкты могут вызывать недопонимания и ошибки, как продемонстрировано в данном случае. За счет правильного выбора конструкций параметров с заменой по умолчанию вы создаете основу для более надежных и понятных скриптов, что особенно важно в сложных ИТ-проектах.