Переместить много папок с пробелами в названии.

Вопрос или проблема

У меня много веб-страниц сохранено в папке “Загрузки”, и я хочу переместить все html-файлы вместе с их папкой (для каждого “NAME.html” существует папка “NAME_files/”).

Большая проблема, с которой я сталкиваюсь, это пробел в имени.
Я подумал над этим, и после нескольких попыток сделал следующее:

export OLDIFS="$IFS"
export IFS=$'\n'

затем:

for FILE in $(find . -type d -iname "*_files" ) ; do DIR=$(basename ${FILE/_files/}); WEB="${DIR}.html" ;  mv "${DIR}" 000 ;   mv "${WEB}" 000 ; done 

Я думаю, что поставил кавычки везде, но это не работает.
Или лучше сказать, приведенная выше команда перемещает html-файлы, но я получаю “Такого файла или директории не существует” для папок.

Например, у меня есть такие файлы:
before the command
Когда я выполняю свою команду, только html-файл попадает в папку 000, но не папка!
after the command

Да, я знаю, имя, “[FreeFileSync] SyncSettings-Contabilità ⚠️.html” — это очень плохое имя… 😅
Я также пробовал с менее экзотическими именами с теми же результатами.

Пожалуйста, помогите мне, где моя ошибка?

Вы поставили кавычки везде, кроме самой важной части, что вы не можете сделать, потому что именно там вы поместили оператор find.

Поскольку вы говорите, что все директории находятся в вашей папке “Загрузки”, просто ссылайтесь на них напрямую

for dir in *_files/
do
    file="${dir%_files/}.html"
    if [ -f "$file" ]
    then
        mv -- "$file" "$dir" 000/
    fi
done

Как и ожидалось, вы можете получить приближение к команде mv, преобразованной в оператор отладки, добавив перед mv команду echo:

echo mv -- "$file" "$dir" 000/

Это позволит вам увидеть, что произойдет, без выполнения каких-либо действий

for FILE in $(find . -type d -iname "*_files" )

это довольно просто: не делайте этого!

если вы используете find, используйте -exec команды find; или по крайней мере используйте print0 команды (GNU) find и xargs -0.

Но реалистично, просто

#!/bin/bash
(shopt -s dotglob nullglob nocaseglob globstar
for FILE in **/*_files ; do
  [[ -d "${FILE}" ]] || continue
  DIR="$(basename -- "${FILE/_files/}")"
# …
done
)

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

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

В zsh групповка немного более универсальна, и скрипт сокращается до

#!/usr/bin/zsh
# почему вы называете элементы списка директорий FILE…
for FILE in **/*_files(/N) ; do
  DIR="${{FILE%_files}:t}" # Сокращение для x="${FILE%_files}"; DIR="${x:t}"
  mv -- "${FILE}" "${DIR}.html" 000
done

Я опускаю (#i) перед группировкой, потому что в то время как ваша оригинальная команда find действительно выполняет регистронезависимое соответствие, но остальная часть вашего кода не пытается работать с _FiLEs (и также опущена setopt -s extended_glob, которая нужна для этого).

Если вы делаете это с директорией, названной foo_files, вы увидите, что сообщение об ошибке связано с файлом, названным foo, а не foo.html или foo_files. .html перемещается, так что $WEB должно быть правильным.

Но DIR=$(basename ${FILE/_files/}) явно убирает часть _files из имени перед присвоением DIR. Вы получаете имя директории непосредственно из find, так что оно находится в FILE.

Во всяком случае, я не уверен, что здесь нужен basename, так как он просто удалит промежуточную часть пути, если у вас есть подходящая директория глубже в дереве (например, subdir/foo_files). Вы могли бы просто использовать *_files/ для получения совпадений на непосредственном уровне дерева, хотя это регистрозависимо, если вы не используете shopt -s nocaseglob. (Или используйте *_[fF][iI][lL][eE][sS]/ вместо этого…)

Обратите внимание, что если вы действительно полагаетесь на разделение слов в выводе find, вы должны также отключить глоббинги с set -f, так как иначе имена, похожие на глоббинги, могут вызвать проблемы. (Это потребует одного имени, являющегося глоббингом, который соответствует другому имени, поэтому это будет редко, но тем сложнее будет понять, если это произойдет.) Или просто используйте find -exec или for f in **/*_files/shopt -s globstar) вместо этого.

Ответ или решение

Перемещение множества папок с пробелами в названии может быть проблемой в Unix-подобных системах из-за особенностей работы с пробелами в командной строке. Это связано с тем, что пробелы считаются разделителями, и, если их не обрабатывать должным образом, можно столкнуться с ошибками. Рассмотрим, как решить эту задачу в рамках сценария с перемещением файлов веб-страниц и соответствующих папок.

Теория

Когда в названии файла или папки присутствуют пробелы, их необходимо "экранировать" или заключать в кавычки для правильной интерпретации командной строкой. Существует несколько стратегий для работы с такими именами файлов с использованием скриптов Shell:

  1. Кавычки: Всегда заключайте в кавычки переменные, содержащие имена файлов. Например, используйте "$file" вместо $file.
  2. Специальные символы: Используйте специальные параметры, такие как --, чтобы указать конец параметров, особенно если имена файлов могут начинаться с -.
  3. Команды с нулевым разделителем: Используйте find ... -print0 и xargs -0, чтобы безопасно обрабатывать файлы с пробелами.

Пример

Давайте рассмотрим практическую реализацию. У вас есть файлы HTML и соответствующие папки с суффиксом _files, которые необходимо переместить. Один из подходов — использовать встроенные возможности Bash для работы с файлами и папками:

#!/bin/bash

# Включаем необходимые опции оболочки
(shopt -s dotglob nullglob nocaseglob globstar

# Цикл по всем директориям с суффиксом _files
for dir in **/*_files/
do
    # Получаем имя файла
    file="${dir%_files/}.html"

    # Проверяем, существует ли файл, и если да, перемещаем его вместе с директорией
    if [ -f "$file" ]; then
        mv -- "$file" "$dir" 000/
    fi
done
)

Применение

Этот скрипт в первую очередь устанавливает необходимые параметры оболочки для обработки файлов, игнорируя чувствительность к регистру и позволяя рекурсивный поиск. Затем он ищет все папки с суффиксом _files, вычисляет соответствующее имя файла HTML и проверяет его наличие. Если файл существует, он перемещается вместе с папкой в директорию 000.

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

Оцените материал
Добавить комментарий

Капча загружается...