shellcheck советует для не использования базового имени: почему?

Высвечиваясь с FreeDOS, одной перезагрузкой и никакими съемными устройствами
  1. Удостоверьтесь использование GRUB2 (проверка, если у Вас есть пакет grub-pc установленный на Ubuntu)
  2. Овладейте MEMDISK SYSLINUX. На Ubuntu установите пакет syslinux-common и Ваш memdisk будет находиться в /usr/lib/syslinux/memdisk
  3. Загрузите fdboot.img, сохраните его в Вашем корневом каталоге или некотором другом каталоге, который можно легко ввести с американской раскладкой клавиатуры
  4. Встройте свое программное обеспечение высвечивания в изображение FreeDOS:
    1. sudo -s
    2. mkdir -p /mnt/floppy
    3. mount -o loop -t msdos fdboot.img /mnt/floppy
    4. cp -via FLASH.EXE BIOS.IMG /mnt/floppy/ (FLASH.EXE и BIOS.IMG примеры),
    5. umount /mnt/floppy
  5. Загрузите свою систему и прервите ее в GRUB2 (нажмите ESC),
  6. Нажмите c для ввода командной строки GRUB2.
  7. Загрузка MEMDISK:
    1. Войти linux16 (hd. Теперь нажмите вкладку. Список жестких дисков покажут.
    2. Завершите выбор жесткого диска так, чтобы строка сказала linux16 (hd0,, например.
    3. Нажмите вкладку еще раз для получения списка разделов. Необходимо найти раздел где Ваш /usr/lib/syslinux смонтирован на в Вашей установке Linux.
    4. Теперь у Вас есть жесткий диск и спецификация раздела, можно завершить путь так, чтобы это было похоже на это: linux16 (hd0,msdos3)/usr/lib/syslinux/memdisk. Нажмите Enter.
  8. Загрузка FreeDOS:
    1. Используйте то же заполнение клавишей Tab для нахождения fdboot.img, но с командой initrd16 вместо linux16. Вы закончите со строкой как это: initrd16 (hd0,msdos3)/home/janus/fdboot.img. Нажмите Enter.
  9. Записать boot и нажмите Enter.
  10. Меню начальной загрузки FreeDOS появится.
  11. Выберите опцию "безопасного режима", поскольку Вам не нужны драйверы.
  12. В командной строке DOS напишите имя исполняемого файла высвечивания встроенного микропрограммного обеспечения, например: FLASH.EXE. Нажмите Enter.
  13. Ожидайте высвечивания для окончания.
  14. Микропрограммный проблесковый сигнал мог бы загрузить саму машину, или Вы могли бы вернуть подсказку. Если Вы возвращаете подсказку, press Control-Alt-Delete к перезагрузке.
  15. Поскольку Вы не изменили конфигурацию GRUB постоянно, она загрузится назад в Вашу ОС по умолчанию.

Если существует недостаточно пространства на изображении, используйте наименьшее изображение от chtaube.eu. Распакуйте изображение и отфильтруйте его хотя xxd. Теперь поиск 55aa. Это должно быть в 0x1fe. Можно смонтировать изображение с offset=$((0x200)) как дополнительный флаг монтирования. Остерегайтесь этого $(()) синтаксис является определенным для Bash, но будет также работать в Zsh.

С другой стороны, см. https://www.fladi.at/posts/large-freedos-boot-image/

25
10.10.2013, 01:16
3 ответа

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

Это далее осложнено фактом это, люди обычно используют basename как это: "$(basename "$file")". Это делает вещи еще более трудными, потому что $(command) полосы все запаздывающие новые строки от command. Считайте маловероятный случай этим $file концы с новой строкой. Затем basename добавит дополнительная новая строка, но "$(basename "$file")" разделит обе новых строки, оставляя Вас с неправильным именем файла.

Другая проблема с basename это если $file начинается с a - (подчеркните штриховой линией иначе минус), это будет интерпретироваться как опция. Этого легко зафиксировать: $(basename -- "$file")

Устойчивый способ использовать basename это:

# A file with three trailing newlines.
file=$'/tmp/evil\n\n\n'

# Add an 'x' so we can tell where $file's newlines end and basename's begin.
file_x="$(basename -- "$file"; printf x)"

# Strip off two trailing characters: the 'x' added by us and the newline added by basename. 
base="${file_x%??}"

Альтернатива должна использовать ${file##*/}, который легче, но имеет собственные ошибки. В частности, это неправильно в случаях где $file / или foo/.

26
27.01.2020, 19:40
  • 1
    Очень положительные стороны, +1. Довольный OP принял это вместо моего. –  terdon♦ 09.10.2013, 22:50
  • 2
    : что, если $file foo/? Что, если это /? –  Gilles 'SO- stop being evil' 10.10.2013, 01:17
  • 3
    @Gilles: Вы правы. Я начинаю думать что basename подход лучше, в конце концов, как hacky как есть. Лучшие альтернативы, которые я могу придумать, ${${${file}%%/#}##*/} и [[ $file =~ "([^/]*)/*$" ]] && printf "%s" $match[1], оба из которых zsh-конкретны и ни один из которых обрабатывают / правильно. –  Matt 10.10.2013, 05:27
  • 4
    @terdon Благодарит, что Вы не взяли его лично :-). Файлы с новыми строками не являются общими, но у Matt есть точка. Конечно, использование подстановки переменных также более эффективно. –  Matteo 10.10.2013, 09:27

Соответствующие строки в shellcheckисходный код:

checkNeedlessCommands (T_SimpleCommand id _ (w:_)) | w `isCommand` "dirname" =
    style id "Use parameter expansion instead, such as ${var%/*}."
checkNeedlessCommands (T_SimpleCommand id _ (w:_)) | w `isCommand` "basename" =
    style id "Use parameter expansion instead, such as ${var##*/}."
checkNeedlessCommands _ = return ()

Нет никакого объяснения, данного явно, но на основе названия функции (checkNeedlessCommands) похоже, что @jordanm совершенно правилен, и это предлагает, чтобы Вы постарались не разветвлять новый процесс.

17
27.01.2020, 19:40
  • 1
    Пусть источник будет с Вами :) –  Joseph R. 09.10.2013, 19:29

dirname, basename, readlink и т.д. (благодарит @Marco - это исправлено), может создать проблемы мобильности, когда безопасность становится важной (требование безопасности пути). Много систем (как Fedora Linux) помещают его в /bin тогда как другие (как MAC OSX) помещают его в /usr/bin. Затем существует Bash в Windows, например, cygwin, msys, и другие. Всегда лучше остаться чистый Bash, если это возможно. (на комментарий @Marco)

BTW, спасибо за указатель на shellcheck, я не видел это прежде.

3
27.01.2020, 19:40
  • 1
    1), Что Вы подразумеваете под “безопасностью”? Можно ли уточнить? 2) OP не упоминает dirname вообще. 3) Основные базовые утилиты должны быть в ПУТИ, везде, где они хранятся. Я еще не видел систему где basename не был в ПУТИ. 4) Принятие удара доступно, проблема portibility. Всегда лучше избегать удара и использовать оболочку POSIX, когда мобильность требуется. –  Marco 10.10.2013, 02:03
  • 2
    @Marco спасибо за указание на эти проблемы. Да Вы корректны, что утилиты находятся на пути. Но где каждый хочет предоставить дополнительную защиту сценарию Bash, это - хорошая практика для обеспечения полного пути. Так вызов '/bin/basename' будет работать на системы Redhat, но он произведет ошибку на Mac. Это лучше объяснено в Поваренной книге Bash, где приблизительно одна четверть 600 страниц посвящена этому предмету. Мы предприняли грубую попытку обратиться к проблемам безопасности там в нашем свободном исходном безопасном lib. Точка –  AsymLabs 10.10.2013, 09:31
  • 3
    @Marco 4 является действительным комментарием, но вопрос (OP) начинается и записан вокруг shellcheck, который разработан для проверки обоих sh/bash сценарии. Поэтому мы должны предположить, что это не строго Posix по умолчанию. –  AsymLabs 10.10.2013, 09:42
  • 4
    @Marco переменной среды пути может быть поставлена под угрозу легко. Например, я был очень удивлен найти несколько лет назад, что RVM Ruby, установленный локально, по умолчанию поместил, это - путь перед системным путем. –  AsymLabs 10.10.2013, 10:36
  • 5
    OP конкретно упоминает POSIX, и вопрос отмечен posix и нет bash. Мне не удается найти любой индикатор, что OP требует решения для удара. Ваш оператор “It is always better to stay pure Bash” является просто неправильным, я сожалею. –  Marco 10.10.2013, 11:09

Теги

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