Сценарий оболочки для переименования нескольких файлов из имени их родительских папок

2073
Simon

У меня есть такая структура файла:

  • 00000010
    • 000000001.file1
    • 000000001.file2
  • 00000020
    • 00000003.file1
    • 00000003.file2
    • 00000003.file3
  • ...

Таким образом, есть папки с 8-значными именами, содержащими один или несколько файлов, имена которых начинаются с 8-значных чисел. Но эти имена файлов - скажем так - не синхронизированы. Итак, теперь я пытаюсь рекурсивно переименовать их в bash для архивирования:

  • 00000010
    • 000000010.file1
    • 000000010.file2
  • 00000020
    • 00000020.file1
    • 00000020.file2
    • 00000020.file3
  • ...

Мой сценарий выглядит так:

#! /bin/bash  find * -maxdepth 1 -name "*" -type d | while read -r dir do rename 's/$dir\/[0-9]/$dir/' * done 

Но это не работает и дает такие ошибки, как

Глобальный символ "$ dir" требует явного имени пакета в (eval 1) строке 1.

Как я мог написать это, чтобы переименовать файлы в соответствии с именами их папок?

Спасибо за помощь!

3
Пожалуйста, не [кросс-пост] (http://stackoverflow.com/questions/4861208/shell-script-to-rename-multiple-files-from-their-parent-folders-name). Dennis Williamson 13 лет назад 1

2 ответа на вопрос

2
Simon

Как из другого ответа я узнал, что я должен использовать

rename "s/$dir\/[0-9]/$dir\/$dir/" $dir/* 

На всякий случай, если у кого-то есть такая же проблема ...

0
Daniel Andersson

I do not really like the answer where $dir is interpolated into the pattern. It could lead to unexpected results if the directory would e.g. contain a character that gets interpreted as a special regexp token.

I would rather match the files directly in the pattern, negating the need to loop over the directories and just use a regular glob.

rename 's#([^/]+)/[^/]+(\.file[0-9]+)$#$1/$1$2#' base_directory/*/* 

where the glob hits the individual files within the directories (it could even be specified to base_directory/*/*.file*, or similar, but it should not matter here).

Note that this is the full command, without need for the find construction.

  • I use # as separator instead of the "regular" / to avoid having to escape that in the patterns.
  • I capture the (greedy) group of "not a directory separator", followed by a directory separator, followed by a file name and line end. This makes the first capture group be the parent directory for each file.
  • The first portion of the file name is discarded, except for the ending to keep the ordinal suffix.

I chose to use a more general approach than to assume that the files were all 8 characters long, but the real difference is that I neither need the find construct nor to cram the $dir variable into the (possibly unsafe) regexp environment.

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