Renomeia arquivos baseados em seu diretório pai usando o comando find / xargs?

5

Eu tenho uma estrutura de diretórios como esta:

Project/
  |
  +--Part1/
  |    |
  |    +--audio.mp3
  |
  +--Part2/
  |    |
  |    +--audio.mp3
  |
  +--Part3/
  |    |
  |    +--audio.mp3
...

Eu quero acabar com arquivos chamados Part1.mp3, Part2.mp3, etc.

Cada pasta contém apenas um único arquivo, portanto, não há risco de danificar arquivos ou lidar com vários arquivos com o mesmo nome.

Eu sinto que poderia fazer isso com algum tipo de comando find / xargs acoplado com cut e mv , mas não consigo descobrir como realmente formar o comando.

    
por fdmillion 31.12.2015 / 01:09

5 respostas

11

Estes exemplos funcionam em qualquer shell POSIX e não requerem programas externos.

Isso armazena os arquivos Part * .mp3 no mesmo nível que o diretório Project:

(cd Project && for i in Part*/audio.mp3; do echo mv "$i" ../"${i%/*}".mp3; done)

Isso mantém os arquivos Part * .mp3 no diretório Project:

for i in Project/Part*/audio.mp3; do echo mv "$i" ./"${i%/*}".mp3; done

Essas soluções usam o pattern matching parameter expansion do shell para produzir o novo nome de arquivo.

 ${parameter%word}     Remove Smallest Suffix Pattern.  The word is expanded
                       to produce a pattern.  The parameter expansion then
                       results in parameter, with the smallest portion of
                       the suffix matched by the pattern deleted.
    
por 31.12.2015 / 01:26
7

Se você tiver o perl rename (às vezes chamado de prename ), você pode fazer isso:

( cd Project && rename 's!(.+)/(.+)(\.mp3)!$1.$3!' */audio.mp3 )

Isso leva cada nome de arquivo correspondente ao shell glob */audio.mp3 e o divide nos componentes de diretório, nome do arquivo e extensão. Em seguida, descarta a parte do nome do arquivo e renomeia o arquivo.

Use rename -n ... para ver o que aconteceria ou use -v em vez de -n para assisti-lo enquanto é executado.

    
por 31.12.2015 / 01:45
3
pax -rwls'|.*/\(.*\)/audio\(\.mp3\)$||p' \
    -s'|.*||' /path/to/Project .

Isso usará o utilitário de arquivador de linha de comando POSIX pax para criar hardlinks no diretório atual denominado parent_dirs_base.mp3 para cada audio.mp3 encontrado com raiz na árvore em /path/to/Project . Ao fazer isso, ele imprimirá qualquer modificação de nome de arquivo feita no stderr.

Use -k para evitar que seja possível sobrescrever arquivos existentes com nomes idênticos como seus destinos de link ou, melhor ainda, primeiro mudar para um diretório vazio antes de executá-lo.

Na minha opinião, há uma vantagem significativa em usar o hardlink primeiro do que diretamente em mv os arquivos com os quais você procura trabalhar: e é que você tem a chance de verificar se os resultados esperados são os mesmos daqueles que você você obtém antes de remover originais. Quando você tiver marcado, você pode:

find /path/to/Project -name audio.mp3 -exec rm {} +

... para limpar e cortar os links de arquivo em um.

    
por 31.12.2015 / 02:59
-1

Você pode tentar algo assim:

Estes são seus arquivos:

$ cd Project
$ find . -type f
./Part2/audio.mp3
./Part3/audio.mp3
./Part1/audio.mp3

Usar dirname retornará o nome do diretório (supondo que você tenha apenas um nível de subdiretórios). Assim:

$ find . -type f \
   | while read i ; do \
       d=$(dirname $i); echo renaming "$i" to "$d.mp3" ; \
     done
renaming ./Part2/audio.mp3 to ./Part2.mp3
renaming ./Part3/audio.mp3 to ./Part3.mp3
renaming ./Part1/audio.mp3 to ./Part1.mp3

E isso irá renomeá-los:

$ find . -type f | while read i ; do d=$(dirname $i); mv "$i" "$d.mp3" ; done
    
por 31.12.2015 / 01:17
-1

Bash com estilo perl

for file in 'find . -type f -name "*.mp3"';
    do
        dir=$(dirname $file);
        bdir=$(basename $dir);
        bname=$(basename $file);
        new=$bdir.$bname;
        newname=${new//\.\./};
        newname_with_path=$dir/$newname
        if [ "$file" != "$newname_with_path" ]
        then
            echo mv -u $file  $newname_with_path ;
        fi
    done


    # replace 2 dots with nothing
    # bash 4.1.2 centos 6.4 no problem with or without bashslash
    newname=${new//../};
    
por 31.12.2015 / 03:58