Ошибка сегментации при вызове рекурсивной функции bash

Пейджер чаще всего выполняется вещами за пределами вашей оболочки, такими как команда man или различные подкоманды git, поэтому псевдоним оболочки не имеет возможности что-либо делать в большинстве случаев и, следовательно, не имеет большого смысла. Существует стандартная переменная среды $PAGER — используйте ее!

В качестве альтернативы, в системе Debian для общесистемной конфигурации попробуйте:

update-alternatives --config pager
2
10.03.2019, 06:32
1 ответ

Существует множество причин ошибки сегментации. Наиболее распространенной низкоуровневой причиной является то, что процесс попытался получить доступ к адресу памяти, который не определен, т.е. некорректное разыменование указателя. Часто это ошибка в программе.

Здесь вы запускаете программу-оболочку. Оболочка - это язык программирования высокого уровня, без указателей, поэтому ваш сценарий не может вызвать недопустимое разыменование указателя как таковое.

Многие программы имеют ограниченное пространство для своего стека вызовов и погибают от ошибки сегментации, если размер стека превышен. В большинстве случаев предельный размер стека достаточно велик для любых разумных данных, но бесконечная рекурсия может привести к разрушению стека.

В bash бесконечная рекурсия в вызове функции действительно приводит к ошибке сегментации. (То же самое относится к dash и mksh; ksh и zsh умнее и применяют максимальную глубину вложенности вызовов функций на уровне оболочки, так что они не приводят к ошибкам сегментации.)


В вашем сценарии есть несколько ошибок. Одна из них заключается в том, что в случае обычного файла вы всегда вызываете recurse в конце, тогда как вы явно хотели сделать это только для zip-файлов.

Не используйте && или ||, когда вы имеете в виду if. Понятнее писать то, что вы имеете в виду; краткость через неясность - не лучшая идея, и она вас здесь подкосила.

if [[ ${extension} = "zip" ]]; then
  unzip -uq $currentItem -d "${extractionDirectory}"
  recurse ${extractionDirectory}
fi

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

Используйте расширение параметров вместо вызова basename и dirname. Так проще работать с особыми случаями (например, имя файла начинается с -) и это быстрее.

Еще одна ошибка, которую я случайно обнаружил: шаблон +(sh|xslt|dtd|log|txt) явно должен быть @(sh|xslt|dtd|log|txt) (соответствовать этим расширениям, а не shsh, dtdtxtshdtd и т.д.).

Вот обычный файл case, с исправленными выше ошибками и переписанными с case для ясности:

case "$extension" in
  sh|xslt|dtd|log|txt) break;;
  zip)
    extractionDirectory=$"{currentItem%.zip}"
    unzip -uq "$currentItem" -d "${extractionDirectory}"
    recurse "${extractionDirectory}"
esac

Обратите внимание, что я не проверял логику и не тестировал код. Это кажется сложным способом написания

find -type f -name '*.zip' -exec sh -c 'unzip -uq "$0" -d "${0%.zip}"' {} \;
4
29.04.2021, 00:12

Теги

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