Страницы

Поиск по вопросам

воскресенье, 2 февраля 2020 г.

Почему плохо перебирать файлы/папки через ls? (Iterating over ls output is fragile. Use globs.)

#bash #shell #инспекция_кода #zsh


Есть код, который должен работать в bash и zsh. Фрагмент кода перечисляет все директории,
сортируя их по времени последнего изменения. Эту задачу он решает вполне успешно. Перечисляемые
директории генерятся тем же кодом и содержат только символы a-zA-Z0-9-_, никаких пробелов.

mcve.sh:

#!/usr/bin/env bash
for i in $(ls -dt1 ./*/);
do
    echo "${i}";
done


Использую shellcheck:

shellcheck mcve.sh


Получаю следующий результат:

In mcve.sh line 2:
    for i in $(ls -dt1 ./*/);
             ^-- SC2045: Iterating over ls output is fragile. Use globs.


В чём "хрупкость" этого метода? Как я могу его улучшить?

Очевидный вариант "использовать глобы" не подходит, т.к. нужна сортировка по времени.
    


Ответы

Ответ 1



Проблема в том, что ls предназначена в первую очередь для отображения списка файлов в понятном пользователю формате. Это включает всякие метки и прочие обозначения, которые ls прибавляет к наименованиям файлов. ls -1 не добавляет меток, но это не избавляет от «расцвечивания». Кроме того, работа ls может варьироваться от настроек окружения и операционной системы, что переводит её из разряда «универсальное решение» в разряд «может работать». Так же не стоит забывать, что совсем нередко пользователи при помощи алиаса задают дефолтные настройки для ls. Для того, чтобы получить некий список файлов и передать его в качестве параметров какой-то другой команде, обычно используют find. Например, чтобы получить список поддиректорию в текущей директории, отсортированный по mtime, можно сделать как-нибудь так: find . -maxdepth 1 -type d -printf “%C@ %p\n" | sort | awk '{print $2}'

Ответ 2



под «хрупкостью», вероятно, подразумевалась обработка спец-символов, которые могут встретиться в именах файлов/каталогов. например, пробел: $ mkdir "1 2" 3 $ for i in $(ls); do echo "${i}"; done 1 2 3 в то время как использование glob даст корректный результат: $ for i in *; do echo "${i}"; done 1 2 3 данной проблемы можно избежать, если заключить вложенную команду в кавычки: $ for i in "$(ls)"; do echo "${i}"; done 1 2 3

Комментариев нет:

Отправить комментарий