Скрипт Ksh без родительской ошибки

Это плохой код. getopt практически непригоден¹. Вместо него используйте встроенную оболочку getopts (у нее два преимущества: она может работать и доступна на всех POSIX платформах).

Что делает args=$(getopt optstring $*); set -- $args:

  • Разделите каждый аргумент командной строки пробелами и замените его списком слов, разделенных пробелами.
  • Берет каждое из получившихся слов и интерпретирует его как шаблон подстановочного знака. Если шаблон соответствует хотя бы одному файлу, замените шаблон списком подходящих файлов.
  • Передайте полученный список слов команде getopt.
  • Сохраните вывод команды getopt в переменной args. Это строка, состоящая из аргументов командной строки, объединенных пробелами в качестве разделителя, и упорядоченная так, чтобы были опции и их аргументы, затем --, затем операнды без опций.
  • Разделите эту строку пробелами, интерпретируйте каждое слово как шаблон подстановки и замените шаблон списком подходящих файлов, если таковые имеются.
  • Используйте полученный список в качестве позиционных аргументов.

В оболочках типа Bourne/POSIX, $foo - это оператор "split+glob". Чтобы получить значение переменной, нужны двойные кавычки: "$foo". Но в zsh $foo работает по-другому: он расширяется до значения foo, за исключением случаев, когда foo пуст. Таким образом, в zsh вы получаете один позиционный параметр.

Первого использования оператора split+glob можно избежать, написав getopt optstring "$@": это передаст позиционные параметры точно в getopt. Но при разборе вывода getopt расщепление неизбежно (хотя вы можете отключить globbing), поскольку getopt использует пробелы для разделения аргументов. Проблема с getopt в том, что вывод неоднозначен: нет способа отличить пробел, который был в аргументе, от пробела, который getopt добавил в качестве разделителя.

Правильный способ сделать это - getopts. Он надежен и переносим.

while getopts optstring OPTLET; do
  # We got the option -$OPTLET
  case $OPTLET in
    …
  esac
done
shift $((OPTIND-1))
# Now the positional parameters are just the non-option operands

¹ По крайней мере, в версии BSD. Версия GNU добавляет возможности, которые делают ее удобной для использования.

0
16.03.2018, 22:21
1 ответ

Хотя мне кажется странным, что вы сравниваете переменную с чем-то, что вы только что установили, основная проблема заключается в том, что вы используете числовой оператор сравнения (-ne)для того, что ожидается. быть именем файла (текста ). Вместо этого используйте:

if [ "$filename" != "$1" ]

... где я также процитировал ваши переменные .

Бонус указывает на комментарий steeldriver , который побудил меня изучить это немного глубже.

Основываясь на моем тестировании, я считаю, что ksh видитneчисловой оператор сравнения и выполняет цикл переменного и арифметического расширения двух операндов $filenameи $1. Таким образом, $filenameпревращается в test.txt, который ksh распознает как возможный compound variable. Поскольку testне установлен, вы получаете сообщение об ошибке test.txt: no parent.

3
28.01.2020, 02:23

Теги

Похожие вопросы