Лучший способ переименования файлов на основе нескольких шаблонов

много файлов, которые я загружаю, имеют дерьмо/спам в именах файлов, например.

[ www.crap.com ] file.name.ext

www.crap.com - file.name.ext

У меня есть два способа справиться с ними, но они оба кажутся довольно неуклюжими:

с расширением параметра:

if [[ ${base_name} != ${base_name//\[+([^\]])\]} ]]
then
    mv -v "${dir_name}/${base_name}" "${dir_name}/${base_name//\[+([^\]])\]}" &&
        base_name="${base_name//\[+([^\]])\]}"
fi

if [[ ${base_name} != ${base_name//www.*.com - /} ]]
then
    mv -v "${dir_name}/${base_name}" "${dir_name}/${base_name//www.*.com - /}" &&
        base_name="${base_name//www.*.com - /}"
fi

# more of these type of statements; one for each type of frequently-encountered pattern

а затем с помощью echo/sed:

tmp=`echo "${base_name}" | sed -e 's/\[[^][]*\]//g' | sed -e 's/\s-\s//g'`
mv "${base_name}" "{tmp}"

Мне кажется, что расширение параметра хуже из двух, но мне оно нравится, потому что я могу сохранить одну и ту же переменную, назначенную файлу для дальнейшей обработки после переименования (приведенный выше код используется в script который вызывается для каждого файла после завершения загрузки файла).

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

Спасибо

Ответ 1

Два ответа: использование переименовать или используя чистый bash

Как есть некоторые люди, которым не нравится perl, я написал свою версию bash только

Переименование файлов с помощью команды rename.

Введение

Да, это типичное задание для команды rename, которая была специально разработана для:

man rename | sed -ne '/example/,/^[^ ]/p'
   For example, to rename all files matching "*.bak" to strip the
   extension, you might say

           rename 's/\.bak$//' *.bak

   To translate uppercase names to lower, you'd use

           rename 'y/A-Z/a-z/' *

Более ориентированные образцы

Просто отбросьте все пробелы и квадратные скобки:

rename 's/[ \[\]]*//g;' *.ext

Переименуйте все .jpg нумерацией из 1:

rename 's/^.*$/sprintf "IMG_%05d.JPG",++$./e' *.jpg

Демо:

touch {a..e}.jpg
ls -ltr
total 0
-rw-r--r-- 1 user user 0 sep  6 16:35 e.jpg
-rw-r--r-- 1 user user 0 sep  6 16:35 d.jpg
-rw-r--r-- 1 user user 0 sep  6 16:35 c.jpg
-rw-r--r-- 1 user user 0 sep  6 16:35 b.jpg
-rw-r--r-- 1 user user 0 sep  6 16:35 a.jpg
rename 's/^.*$/sprintf "IMG_%05d.JPG",++$./e' *.jpg
ls -ltr
total 0
-rw-r--r-- 1 user user 0 sep  6 16:35 IMG_00005.JPG
-rw-r--r-- 1 user user 0 sep  6 16:35 IMG_00004.JPG
-rw-r--r-- 1 user user 0 sep  6 16:35 IMG_00003.JPG
-rw-r--r-- 1 user user 0 sep  6 16:35 IMG_00002.JPG
-rw-r--r-- 1 user user 0 sep  6 16:35 IMG_00001.JPG

Полный синтаксис для сопоставления SO-запроса безопасным способом

Существует мощный и безопасный способ использования утилиты rename:

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

rename 'my $o=$_;
        s/[ \[\]]+/-/g;
        s/-+/-/g;
        s/^-//g;
        s/-\(\..*\|\)$/$1/g;
        s/(.*[^\d])(|-(\d+))(\.[a-z0-9]{2,6})$/
                my $i=$3;
                $i=0 unless $i;
                sprintf("%s-%d%s", $1, $i+1, $4)
            /eg while
               $o ne $_  &&
               -f $_;
    ' *

Правило тестирования:

touch '[ www.crap.com ] file.name.ext' 'www.crap.com - file.name.ext'
ls -1
[ www.crap.com ] file.name.ext
www.crap.com - file.name.ext
rename 'my $o=$_; ...
    ...
    ...' *
ls -1
www.crap.com-file.name-1.ext
www.crap.com-file.name.ext

touch '[ www.crap.com ] file.name.ext' 'www.crap.com - file.name.ext'
ls -1
www.crap.com-file.name-1.ext
[ www.crap.com ] file.name.ext
www.crap.com - file.name.ext
www.crap.com-file.name.ext
rename 'my $o=$_; ...
    ...
    ...' *
ls -1
www.crap.com-file.name-1.ext
www.crap.com-file.name-2.ext
www.crap.com-file.name-3.ext
www.crap.com-file.name.ext

... и так далее...

... и он безопасен, пока вы не используете флаг -f для rename: файл не будет перезаписан, и вы получите сообщение об ошибке, если что-то пойдет не так.

Переименование файлов с помощью и так называемые базисы:

Я предпочитаю делать это с помощью специальной утилиты, но это можно сделать даже с помощью чистого bash (он же без какой-либо вилки)

Нет никакого другого двоичного кода, кроме bash (no sed, awk, tr или другого):

#!/bin/bash

for file;do
    newname=${file//[ \]\[]/.}
    while [ "$newname" != "${newname#.}" ] ;do
        newname=${newname#.}
      done
    while [ "$newname" != "${newname//[.-][.-]/.}" ] ;do
        newname=${newname//[.-][.-]/-};done
    if [ "$file" != "$newname" ] ;then
        if [ -f $newname ] ;then
            ext=${newname##*.}
            basename=${newname%.$ext}
            partname=${basename%%-[0-9]}
            count=${basename#${partname}-}
            [ "$partname" = "$count" ] && count=0
            while printf -v newname "%s-%d.%s" $partname $[++count] $ext &&
                  [ -f "$newname" ] ;do
              :;done
          fi
        mv  "$file" $newname
      fi
  done

Для запуска с файлами в качестве аргумента для образца:

/path/to/my/script.sh \[*
  • Замена пробелов и квадратных скобок точкой
  • Замена последовательностей .-, -., -- или .. только одним -.
  • Проверьте, не отличается ли имя файла, нечего делать.
  • Проверить, существует ли файл с новым именем...
  • разделять имя файла, счетчик и расширение, для создания индексированного newname
  • если файл существует с новым именем
  • Окончательно переименуйте файл.

Ответ 2

Воспользуйтесь следующей классической схемой:

 job_select /path/to/directory| job_strategy | job_process

где job_select отвечает за выбор объектов вашего задания, job_strategy готовит план обработки для этих объектов, а job_process в конечном итоге выполняет план.

Предполагается, что имена файлов не содержат вертикальную полосу | и символ новой строки.

Функция job_select

 # job_select PATH
 #  Produce the list of files to process
 job_select()
 {
   find "$1" -name 'www.*.com - *' -o -name '[*] - *'
 }

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

Избегайте общей ошибки, связанной с содержимым скрытых каталогов на выходе функции job_select. Например, каталоги CVS, .svn, .svk и .git используются соответствующими средствами управления средствами управления версиями, и почти всегда неправильно включать их содержимое в вывод функции job_select. Посредством случайной пакетной обработки этих файлов можно легко сделать поврежденную рабочую копию непригодной.

Функция job_strategy

# job_strategy
#  Prepare a plan for renaming files
job_strategy()
{
  sed -e '
    h
    [email protected]/www\..*\.com - *@/@
    [email protected]/\[^]]* - *@/@
    x
    G
    s/\n/|/
  '
}

Эти команды считывают вывод job_select и составляют план для нашего задания на переименование. План представлен текстовыми строками, имеющими два поля, разделенных символом |, причем первым полем является старое имя файла, а второе - новый вычисленный файл файла, он выглядит как

[ www.crap.com ] file.name.1.ext|file.name.1.ext
www.crap.com - file.name.2.ext|file.name.2.ext

Конкретная программа, используемая для составления плана, по существу не имеет значения, но обычно используется sed, как в примере; awk или perl для этого. Пройдем через sed - script, который используется здесь:

h       Replace the contents of the hold space with the contents of the pattern space.
…       Edit the contents of the pattern space.
x       Swap the contents of the pattern and hold spaces.
G       Append a newline character followed by the contents of the hold space to the pattern space.
s/\n/|/ Replace the newline character in the pattern space by a vertical bar.

Для подготовки плана может быть проще использовать несколько фильтров. Другим распространенным случаем является использование команды stat для добавления времени создания к именам файлов.

Функция job_process

# job_process
#  Rename files according to a plan
job_process()
{
   local oldname
   local newname
   while IFS='|' read oldname newname; do
     mv "$oldname" "$newname"
   done
}

Разделитель IFS поля ввода настроен так, чтобы функция считывала вывод job_strategy. Объявление oldname и newname, поскольку локально полезно в больших программах, но может быть опущено в очень простых скриптах. Функция job_process может быть скорректирована, чтобы избежать перезаписи существующих файлов и сообщить о проблемных элементах.

О структурах данных в программах оболочки Обратите внимание на использование труб для передачи данных с одного этапа на другой: ученики часто полагаются на переменные для представления такой информации, но это оказывается неуклюжий выбор. Вместо этого предпочтительно представлять данные в виде табличных файлов или в виде потоков табличных данных, перемещающихся от одного процесса к другому, в этой форме данные могут быть легко обработаны мощными инструментами, такими как sed, awk, join, paste и sort - только для цитирования наиболее распространенных.

Ответ 3

Если вы используете команду Ubunntu/Debian os, переименуйте команду переименовать несколько файлов во время.

Ответ 4

Если вы хотите использовать что-то, не зависящее от perl, вы можете использовать следующий код (позвоните ему sanitizeNames.sh). Он показывает только несколько случаев, но легко расширяется с помощью подстановки строк, tr (и sed тоже).

    #!/bin/bash

    ls $1 |while read f; do
      newfname=$(echo "$f" \
                  |tr -d '\[ ' \    # Removing opened square bracket
                  |tr ' \]' '-' \   # Translating closing square bracket to dash
                  |tr -s '-' \      # Squeezing multiple dashes
                  |tr -s '.' \      # Squeezing multiple dots
                )
      newfname=${newfname//-./.}

      if [ -f "$newfname" ]; then
        # Some string magic...
        extension=${newfname##*\.}
        basename=${newfname%\.*}
        basename=${basename%\-[1-9]*}
        lastNum=$[ $(ls $basename*|wc -l) ] 
        mv "$f" "$basename-$lastNum.$extension"
      else
        mv "$f" "$newfname"
      fi
    done

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

    $ touch '[ www.crap.com ] file.name.ext' 'www.crap.com - file.name.ext' '[ www.crap.com ] - file.name.ext' '[www.crap.com ].file.anothername.ext2' '[www.crap.com ].file.name.ext'
    $ ls -1 *crap*
    [ www.crap.com ] - file.name.ext
    [ www.crap.com ] file.name.ext
    [www.crap.com ].file.anothername.ext2
    [www.crap.com ].file.name.ext
    www.crap.com - file.name.ext
    $ ./sanitizeNames.sh *crap*
    $ ls -1 *crap*
    www.crap.com-file.anothername.ext2
    www.crap.com-file.name-1.ext
    www.crap.com-file.name-2.ext
    www.crap.com-file.name-3.ext
    www.crap.com-file.name.ext

Ответ 5

Вы можете использовать rnm

rnm -rs '/\[crap\]|\[spam\]//g' *.ext

Вышеупомянутое удалит [crap] или [spam] из имени файла.

Вы можете передать несколько шаблонов регулярных выражений, завершая их с помощью ; или перегружая параметр -rs.

rnm -rs '/[\[\]]//g;/\s*\[crap\]//g' -rs '/crap2//' *.ext

Общий формат этой строки замены /search_part/replace_part/modifier

  • search_part: regex для поиска.
  • replace_part: строка для замены
  • модификатор: я (регистр нечувствителен), g (глобальная замена)

прописные/строчные буквы:

Заменить строку формы /search_part/\c/modifier сделает выбранную часть имени файла (с помощью регулярного выражения search_part) в нижнем регистре, а \C (capital\C) в замещающей части сделает его прописным.

rnm -rs '/[abcd]/\C/g' *.ext
## this will capitalize all a,b,c,d in the filenames


Если у вас много шаблонов регулярных выражений, которые нужно решать, затем поместите эти шаблоны в файл и передайте файл с опцией -rs/f.
rnm -rs/f /path/to/regex/pattern/file *.ext

Здесь вы можете найти другие примеры .

Примечание:

  • rnm использует регулярное выражение PCRE2 (исправленное PCRE).
  • Вы можете отменить операцию нежелательного переименования, запустив rnm -u

P.S: Я являюсь автором этого инструмента.