Предположений было довольно много, но большинство указанных и неуказанных в опросе, но всплывшие в обсуждении недостатки не являются фатальными.
Основной и очень грубой ошибкой является использование для получения списка файлов команды ls, также все сказанное далее в полной мере относится и к find. Обе эти команды созданы для интерактивного взаимодействия с оператором и не предназначены для использования в скриптах.
Почему? В обсуждении было приведено несколько хороших ссылок на подробные материалы, правда на английском, но даже с переводчиком смысл будет понятен. Мы же остановимся коротко на основных проблемах.
🔹 Первая и самая очевидная - пробелы, имя файла с пробелами превратится в набор строк, каждая из которых будет обрабатываться скриптом отдельно. И если в данном примере это относительно безопасно, то в реальных сценариях это может привести к абсолютно непредсказуемым последствиям.
Например, в нашей практике мы сталкивались со скриптом, который таким образом подсчитывал количество файлов в папке, потом сортировал их по дате создания и удалял самые старые, чтобы осталось всего N-файлов. Файл с пробелами в имени сразу грубо ломает эту логику и может привести к удалению нужных данных.
Обернуть ls *.mp4 в кавычки тоже не даст результата, так как в этом случае в качестве единой строки будет использоваться весь вывод команды.
🔹Вторая проблема – возможное наличие в имени файла управляющих и подстановочных символов. На практике встречается гораздо реже, но так как Linux вполне допускает подобные имена, то вы вполне можете с ними столкнуться, например, они могут появиться в результате ошибок в работе скриптов.
Допустим у вас есть набор файлов: 1Сезон-1Серия.mp4, 1Сезон-2Серия.mp4 и т.д. и туда случайным образом затесался файл где имя состоит из единицы и звездочки за ним. Символ звездочки будет расценен как подстановочный и ls подставит туда все попадающие под маску файлы. В результате все ваши серии попадут в вывод два раза. Как мы уже говорили, если в данном случае это безопасно, то в других сценариях может привести к различным негативным эффектам.
🔹Третья основная проблема – символы национальных алфавитов. Сейчас эта проблема отошла на второй план, но актуальной быть от этого не перестала. А причина все таже – ls и find рассчитаны на то, чтобы выводить информацию на экран.
А далее все зависит от установленной локали, если локаль не содержит символа, соответствующего его коду, то на его месте появится «крякозябкрик» или знак вопроса в ромбе, иди еще что-нибудь, а также такой символ может быть просто пропущен.
👆 Теперь о том, как сделать правильно. В оболочках POSIX, которым относится bash и его производные, есть функция позволяющая использовать в именах файлов символы подстановки, поэтому вывод никаких дополнительных команд анализировать не нужно, а переменную следует обязательно обернуть в кавычки:
for file in ./*.mp4; do
mv -f “$file” /new_path/video
done
В этом случае корректно будут отработаны и пробелы, и спецсимволы, и символы национальных алфавитов.
Также можно подстраховаться и добавить проверку на существование файла:
for file in ./*.mp4; do
[ -e "$file" ] || continue
mv -f “$file” /new_path/video
done
Если указанный файл не существует, то цикл пропустит текущую итерацию и перейдет к следующей.
👉 P.S. Почему мы заострили внимание именно на этой проблеме, а не на проверке наличия папки и наличия закрывающего слеша?
Потому что ls/find архитектурный баг скрипта, а остальное – частный случай с неправильной конфигурацией окружения.
Если Вася проследит, чтобы папка на момент запуска скрипта существовала – проблем у него не возникнет, никогда и никаких.
А вот использование ls/find для поиска файлов - это 100% проблема, заложенная архитектурно.
Если же Вася отразит в документации, мол перед запуском скрипта обязательно проверьте наличие целевой папки, то это уже будет не баг, а фича.
