Как заменить пробелы во всех именах файлов подчеркиванием в Linux с помощью сценария оболочки?

17

Я попытался следующий сценарий оболочки, который должен заменить пробелы из всех имен файлов XML

for xml_file in $(find $1 -name "* .xml" -type f);
do
 echo "removing spaces from XML file:" $xml_file
 mv "$xml_file" "${xml_file// /_}";
done

Предположим, у меня есть XML-файл с именем xy z.xml, тогда он дает:

removing spaces from XML file: /home/krishna/test/xy
mv: cannot stat `/home/krishna/test/xy': No such file or directory
removing spaces from XML file: .xml
mv: cannot stat `z.xml': No such file or directory
Кришна
источник

Ответы:

28

Используйте это с bash:

find $1 -name "* *.xml" -type f -print0 | \
  while read -d $'\0' f; do mv -v "$f" "${f// /_}"; done

findбудет искать файлы с пробелом в имени. Имена файлов будут напечатаны с помощью nullbyte ( -print0) в качестве разделителя, чтобы также обрабатывать специальные имена файлов. Затем readвстроенный модуль считывает имена файлов, разделенные нулевым байтом, и, наконец, mvзаменяет пробелы подчеркиванием.

РЕДАКТИРОВАТЬ: Если вы хотите удалить пробелы в каталогах тоже, это немного сложнее. Каталоги переименовываются и больше не доступны для поиска по именам find. Попробуй это:

find -name "* *" -print0 | sort -rz | \
  while read -d $'\0' f; do mv -v "$f" "$(dirname "$f")/$(basename "${f// /_}")"; done

sort -rzИзменяет порядок файла, так что самые глубокие файлы в папке являются первыми для перемещения и сама папка будет последним. Таким образом, папки никогда не переименовываются, пока все файлы и папки не переименованы внутри. Команда mvв цикле тоже немного изменена. В имени цели мы удаляем только пробелы в базовом имени файла, иначе он не будет доступен.

хаос
источник
Я пытаюсь заменить пробелы подчеркиванием во всех каталогах, но выдает ошибку, потому что после изменения имени этот каталог недоступен.
Кришна
@krishna Я добавил изменения в свой ответ.
хаос
1
@chaos вау, просто запустил эти два на двух системах, и это сработало как чудо, несколько файлов и папок не проходили, но это всего лишь несколько
что-то что-то
В macOS нам нужно указать директорию в команде find перед опцией -name find . -name "* *" -print0 | sort -rz | \ while read -d $'\0' f; do mv -v "$f" "$(dirname "$f")/$(basename "${f// /_}")"; done
Laszlo Pinter
17
  1. С помощью rename

    find . -type f -name "* *.xml" -exec rename "s/\s/_/g" {} \;

    или с $1

    find "$1" -type f -name "* *.xml" -exec rename "s/\s/_/g" {} \;
  2. С помощью mv

    find . -type f -name "* *.xml" -exec bash -c 'mv "$0" "${0// /_}"' {} \;

    или с $1

    find "$1" -type f -name "* *.xml" -exec bash -c 'mv "$0" "${0// /_}"' {} \;
AB
источник
Я не знаю почему, но ваша команда не работает для меня. Это не показывает какую-либо ошибку и вывод.
Кришна
@krishna исправлено, извините
AB
1
Переименование сработало для меня. Дружеский удар кулаками!
Брайан Пирси,
1

Это метод, который я нашел, столкнувшись с той же проблемой:

for f in *; do mv "$f" `echo $f | tr ' ' '_'`; done

Я писал файл сценария bash для автоматического обновления моих ssl-сертификатов.

NekoMisaki
источник
1

Используйте rename:

rename 's/\s/_/g' ./*.xml

Нет необходимости для find:)

Ян Верховен
источник
1
добавьте конечный g к регулярному выражению, и он отлично работает. 's / \ s / _ / g'
19
Хороший совет, спасибо :)
Ян Верховен