Renomeação em massa, versão * nix

11

Eu estava procurando uma maneira de renomear um grande número de arquivos com nomes semelhantes, muito parecido com este (uma questão relacionada ao Windows) , exceto que eu estou usando * nix (Ubuntu e FreeBSD, separadamente). Apenas para resumir, ao usar o shell (Bash, CSH, etc.) como renomear em massa um número de arquivos como, por exemplo, os seguintes arquivos:

Beethoven - Fur Elise.mp3
Beethoven - Sonata ao luar.mp3
Beethoven - Ode à Alegria.mp3
Beethoven - Raiva Sobre a Penny Perdida.mp3

será renomeado como este?

Fur Elise.mp3
Sonata do luar.mp3
Ode à Alegria.mp3
Raiva Sobre a Penny Perdida.mp3

A razão pela qual eu quero fazer isso é que essa coleção de arquivos irá para um diretório chamado "Beethoven" (ou seja, o prefixo dos nomes dos arquivos), e ter essa informação no próprio nome do arquivo será redundante.

    
por Paolo B. 19.08.2009 / 08:57

9 respostas

12

O utilitário de renomeação fará o que você quiser.

Use apenas rename 's/Beethoven\ -\ //g' *.mp3

    
por 19.08.2009 / 09:35
10

Como muitas coisas com o Linux / Unix, há mais de uma maneira de fazer isso!

Alguns podem usar mmv (massa mv).

O comando rename, ou prename que vem com alguns pacotes Perl (Ubuntu e Debian mais recentes) também pode fazer isso.

prename 's/Beethoven\ -\ //g' Beethoven*.mp3

Note que a ferramenta de renomeação no Fedora 10 não é o mesmo programa e funciona de maneira diferente. É parte de um pacote diferente, util-linux-ng e pode ser encontrado aqui .

Eu costumo ir ao shell fora do hábito (afinal de contas, tais ferramentas nem sempre existiam).

mkdir -p Beethoven
for x in Beethoven\ -\ *
do
mv "$x" Beethoven/"${x/Beethoven - /}"
done

Isto irá criar o diretório Beethoven, então mova o arquivo para o diretório / nome do arquivo, onde o nome do arquivo tem o "Beethoven -" substituído por nada.

Como teste, antes:

$ ls
Beethoven - Fur Elise.mp3                 Beethoven - Ode to Joy.mp3
Beethoven - Moonlight Sonata.mp3          Beethoven - Rage Over the Lost Penny.mp3

Depois:

$ ls Beethoven/
Fur Elise.mp3                 Ode to Joy.mp3
Moonlight Sonata.mp3          Rage Over the Lost Penny.mp3
    
por 19.08.2009 / 09:10
4

Experimente esta solução, implementada usando uma combinação de grep e rename. Isto está assumindo que você tem um monte de diretórios que você precisa renomear. Se houver apenas alguns, eu usaria a abordagem manual, com o padrão "Artist -" codificado para cada um.

# Rename any mp3 files in the directory hierarchy of type "a - b.mp3" to "b.mp3"
find . -name "*.mp3" -exec rename -n -v 's|^(.*/).*-\s*(.*)\s*$|$1$2|g' {} \;

Explicação de encontrar :
O comando find localiza todos os arquivos com extensão .mp3 na hierarquia de arquivos atual e chama o argumento passado para -exec para cada um. Note que dentro de -exec , {} refere-se ao argumento passado por find (caminho do arquivo + nome). O \; garante que ; seja passado para renomear e, em vez de indicar o fim do comando localizar .

O comando dado acima tem o interruptor -n (sem ação); por isso, só lhe dirá o que aconteceria se você o executasse. Eu recomendo que você execute este comando sem a opção -n somente depois de executá-lo uma vez e estar satisfeito com os resultados propostos.

Agora para o regexp.

  • ^ corresponde ao início da cadeia.
  • $ corresponde ao final da string.
  • . corresponde a qualquer caractere.
  • * significa zero ou mais da construção precedente. por exemplo, .* significa zero ou mais caracteres.
  • \s significa qualquer caractere de espaço.
  • \S significa qualquer caractere não espacial.
  • Qualquer coisa dentro de () é capturada e é refletida como $1 , $2 , dependendo de sua posição.

O regexp:

  • Procura uma estrutura de diretórios opcional no início, captura isso em $ 1: (.*/)
  • Ignora tudo até o " - ": .*-
  • Captura o restante da string, exceto espaços iniciais e finais, em $ 2: (.*)
  • Reescreve o arquivo como $ 1 $ 2, que deve ser "/ caminho / para / arquivo /" "nome_do_arquivo.mp3"

Aqui está o meu teste:

/tmp/test$ ls -R
.:
a  b  c  z-unknown.mp3

./a:
a3.mp3                 a - longer title3.mp3  c.mp3   disc2
a - longer title2.mp3  a - long title.mp3     disc 1  the band - the title.mp3

./a/disc 1:
a - title1.mp3  a - title2.mp3

./a/disc2:
a - title1.mp3  a - title2.mp3

./b:
cd - ab - title3.mp3  cd - title1.mp3  cd - title2.mp3  c.mp3

./c:
c-pony2.mp4  c - pony3.mp3  c - pony4.mp3  c-pony.mp3

/tmp/test$ find . -name "*.mp3" -exec rename -v 's|^(.*/).*-\s*(.*)\s*$|$1$2|g' {} \;
./c/c-pony.mp3 renamed as ./c/pony.mp3
./c/c - pony4.mp3 renamed as ./c/pony4.mp3
./c/c - pony3.mp3 renamed as ./c/pony3.mp3
./z-unknown.mp3 renamed as ./unknown.mp3
./a/the band - the title.mp3 renamed as ./a/the title.mp3
./a/a - longer title2.mp3 renamed as ./a/longer title2.mp3
./a/a - longer title3.mp3 renamed as ./a/longer title3.mp3
./a/disc 1/a - title1.mp3 renamed as ./a/disc 1/title1.mp3
./a/disc 1/a - title2.mp3 renamed as ./a/disc 1/title2.mp3
./a/a - long title.mp3 renamed as ./a/long title.mp3
./a/disc2/a - title1.mp3 renamed as ./a/disc2/title1.mp3
./a/disc2/a - title2.mp3 renamed as ./a/disc2/title2.mp3
./b/cd - title1.mp3 renamed as ./b/title1.mp3
./b/cd - title2.mp3 renamed as ./b/title2.mp3
./b/cd - ab - title3.mp3 renamed as ./b/title3.mp3

/tmp/test$ ls -R
.:
a  b  c  unknown.mp3

./a:
a3.mp3  c.mp3  disc 1  disc2  longer title2.mp3  longer title3.mp3  long title.mp3  the title.mp3

./a/disc 1:
title1.mp3  title2.mp3

./a/disc2:
title1.mp3  title2.mp3

./b:
c.mp3  title1.mp3  title2.mp3  title3.mp3

./c:
c-pony2.mp4  pony3.mp3  pony4.mp3  pony.mp3

O Regexp é um negócio complicado, e cometi muitos erros ao escrevê-los, por isso gostaria de receber qualquer informação sobre a falta de mérito deste. Eu sei que encontrei alguns testes.

    
por 19.08.2009 / 11:18
1

Eu criei um programa Java de linha de comando que torna a renomeação de arquivos (e diretórios) muito fácil, especialmente para scripts. É grátis e de código aberto, para que você possa modificá-lo para o conteúdo do seu coração:

RenameWand link

Alguns exemplos de uso relevantes:

Mova os arquivos do formulário "<a> - <b>" para o respectivo diretório "<a>" :

java -jar RenameWand.jar  "<a> - <b>"  "<a>/<b>"

Classifique os arquivos pela hora da última modificação e renomeie-os com um número de três dígitos:

java -jar RenameWand.jar  "<a>"  "<3|#FT> <a>"

Reorganize partes do nome do arquivo e altere o caso:

java -jar RenameWand.jar  "<album> - <artist> - <song>.<ext>" 
                          "<artist.upper> <album.title> - <song>.<ext.lower>"
    
por 21.08.2009 / 22:44
1

zmv A ferramenta de renomeação do zsh é muito boa.

# zmv "programmable rename"
# Replace spaces in filenames with a underline
zmv '* *' '$f:gs/ /_'
# Change the suffix from *.sh to *.pl
zmv -W '*.sh' '*.pl'
# lowercase/uppercase all files/directories
$ zmv '(*)' '${(L)1}' # lowercase
$ zmv '(*)' '${(U)1}' # uppercase

Mais notas aqui ...

    
por 12.01.2011 / 01:10
0

Para os pinguins, isso é feito facilmente em um shell script ou script AWK. Para nós, meros mortais, você pode querer experimentar o Midnight Commander. Está na maioria das distribuições linux, a partir de um prompt de shell tipo mc -a. Você pode renomear arquivos usando expressões regulares. Eu usei o artigo no GeekStuff link para me ajudar.

    
por 19.08.2009 / 09:36
0

Aqui está um exemplo simples de linha de comando. Eu tinha a palavra "branco" no meio dos nomes de um monte de arquivos png. Eu queria tirá-lo e deixar apenas um único sublinhado. Isso fez o truque:

for i in *.png; do mv "$i" "${i/white/}"; done
    
por 01.06.2011 / 02:26
0

Use vidir e use os recursos do editor para aplicar o padrão de renomeação.

NAME

vidir - edit directory

SYNOPSIS

vidir [--verbose] [directory|file|-] ...

DESCRIPTION

vidir allows editing of the contents of a directory in a text editor. If no directory is specified, the current directory is edited.

When editing a directory, each item in the directory will appear on its own numbered line. These numbers are how vidir keeps track of what items are changed. Delete lines to remove files from the directory, or edit filenames to rename files. You can also switch pairs of numbers to swap filenames.

Note that if "-" is specified as the directory to edit, it reads a list of filenames from stdin and displays those for editing. Alternatively, a list of files can be specified on the command line.

EXAMPLES

vidir vidir *.jpeg Typical uses.

find | vidir - Edit subdirectory contents too. To delete subdirectories, delete all their contents and the subdirectory itself in the editor.

find -type f | vidir - Edit all files under the current directory and subdirectories.

AUTHOR

Joey Hess 2006-2010

Modifications by Magnus Woldrich 2011

COPYRIGHT

Copyright 2006-2011 the vidir "AUTHOR"s as listed above.

Licensed under the GNU GPL.

    
por 03.09.2009 / 14:39
0

Em um * nix sem perl rename available

Em alguns * nix não há renomeação disponível, então é necessário fazer o renomeie usando algum outro método. Alguns anos atrás eu sugeri zmv que, embora excelente, não está necessariamente disponível também.

Usando builtins e sed, podemos rapidamente agitar um script de shell para fazer isso nos dá uma sintaxe muito semelhante ao script perl rename, enquanto falta algum erro de manuseio, ele faz o trabalho.

sedrename() {
  if [ $# -gt 1 ]; then
    sed_pattern=$1
    shift
    for file in $(ls $@); do
      mv -v "$file" "$(sed $sed_pattern <<< $file)"
    done
  else
    echo "usage: $0 sed_pattern files..."
  fi
}

Uso

sedrename 's/Beethoven\ -\ //g' *.mp3

before:

./Beethoven - Fur Elise.mp3
./Beethoven - Moonlight Sonata.mp3
./Beethoven - Ode to Joy.mp3
./Beethoven - Rage Over the Lost Penny.mp3

after:

./Fur Elise.mp3
./Moonlight Sonata.mp3
./Ode to Joy.mp3
./Rage Over the Lost Penny.mp3

Digamos que também criássemos pastas de destino ...

Como mv não cria pastas, não podemos usar sedrename como é aqui, mas é uma pequena mudança, então eu acho que seria legal inclua também.

Precisamos de uma função de utilidade, abspath (ou caminho absoluto) para que possamos gerar a (s) pasta (s) de destino para um padrão sed / rename que inclua nova estrutura de pastas.

abspath () { case "$1" in
               /*)printf "%s\n" "$1";;
               *)printf "%s\n" "$PWD/$1";;
             esac; }

Isso garantirá que sabemos os nomes das nossas pastas de destino. Quando nós renomear vamos precisar usá-lo no nome do arquivo de destino.

# generate the rename target
target="$(sed $sed_pattern <<< $file)"

# Use absolute path of the rename target to make target folder structure
mkdir -p "$(dirname $(abspath $target))"

# finally move the file to the target name/folders
mv -v "$file" "$target"

Este é o script ciente de pasta completa ...

sedrename() {
  if [ $# -gt 1 ]; then
    sed_pattern=$1
    shift
    for file in $(ls $@); do
      target="$(sed $sed_pattern <<< $file)"
      mkdir -p "$(dirname $(abspath $target))"
      mv -v "$file" "$target"
    done
  else
    echo "usage: $0 sed_pattern files..."
  fi
}

Claro, ainda funciona quando não temos pastas de destino específicas também.

Se quiséssemos colocar todas as músicas em uma pasta, ./Beethoven/ , podemos fazer isso:

Uso

sedrename 's|Beethoven - |Beethoven/|g' *.mp3

before:

./Beethoven - Fur Elise.mp3
./Beethoven - Moonlight Sonata.mp3
./Beethoven - Ode to Joy.mp3
./Beethoven - Rage Over the Lost Penny.mp3

after:

./Beethoven/Fur Elise.mp3
./Beethoven/Moonlight Sonata.mp3
./Beethoven/Ode to Joy.mp3
./Beethoven/Rage Over the Lost Penny.mp3

Rodada de bônus ...

Usando este script para mover arquivos de pastas para uma única pasta:

Supondo que queríamos reunir todos os arquivos correspondentes e colocá-los na pasta atual, podemos fazer isso:

sedrename 's|.*/||' **/*.mp3

before:

./Beethoven/Fur Elise.mp3
./Beethoven/Moonlight Sonata.mp3
./Beethoven/Ode to Joy.mp3
./Beethoven/Rage Over the Lost Penny.mp3

after:

./Beethoven/ # (now empty)
./Fur Elise.mp3
./Moonlight Sonata.mp3
./Ode to Joy.mp3
./Rage Over the Lost Penny.mp3

Nota sobre padrões de regex de sed

As regras regulares do padrão sed são aplicadas neste script, esses padrões não são PCRE (expressões regulares compatíveis com Perl). Você poderia ter sed sintaxe de expressão regular estendida, usando sed -r ou sed -E dependendo da sua plataforma.

Veja o man re_format compatível com POSIX para obter uma descrição completa de sed padrões básicos e estendidos de regexp.

    
por 11.03.2018 / 02:37