Posso renomear arquivos dentro de uma pasta com o nome da pasta pai? [duplicado]

2

esta é uma situação única, que pode ser melhor explicada com um exemplo

Exemplo 1 Digamos que eu tenha uma pasta chamada A , B.mkv e C.srt são dois arquivos na pasta, quero renomear esses arquivos para A.mkv e A.srt .

exemplo prático seria, uma pasta chamada American Sniper (2014) e American.Sniper.2014.1080p.BluRay.x264.YIFY.mkv e American.Sniper.2014.Subtitle.BluRay.ShaAnig.srt são dois arquivos na pasta, deseja renomear esses arquivos para American Sniper (2014).mkv e American Sniper (2014).srt

Exemplo 2

Isso deve ser recursivo digamos que eu tenha uma pasta chamada A , B e C são duas subpastas na pasta A . conteúdo de B e C são como seguir

Deveserconvertidopara

Mesmoquandoeuexecutaroalgoritmo/script/comandonapastaA

3ªcoisaqueeledevefazeré:Ignorararquivosocultos

exemplo

deveresultarem

por último, deve funcionar em várias pastas de cada vez

    
por Sumeet Deshmukh 07.04.2017 / 12:19

2 respostas

3

Existem várias maneiras de abordar essa questão. Por favor, leia atentamente as instruções para obter melhores resultados.

Nesta resposta:

  1. abordagem Python
  2. find + bash approach
  3. abordagem somente do bash com globstar

1. Solução Python

O Python é uma linguagem bastante poderosa para a administração do sistema, e a passagem da árvore de diretórios pode ser feita através da função os.walk() . No script apresentado abaixo, estamos fazendo exatamente isso - estamos localizando todos os arquivos e operando em cada um deles, determinando o caminho completo para cada arquivo, a extensão do arquivo e renomeando-o via função os.rename() .

Conteúdo do script

#!/usr/bin/env python3
import os,sys

def get_all_files(treeroot):
    for dir,subdirs,files in os.walk(treeroot):
         for f in files: 
             if f in __file__: continue
             fullpath = os.path.realpath( os.path.join(dir,f) )
             extension = fullpath.split('.')[-1]
             newpath = os.path.join(dir, dir + '.' + extension)
             print('Move ' + fullpath + ' to ' + newpath   )
             # os.rename(fullpath,newpath)


def main():
    top_dir="."
    # If directory not given, assume cwd
    if len(sys.argv) == 2: top_dir=sys.argv[1]
    get_all_files(top_dir)

if __name__ == '__main__' : main()

NOTA: é muito importante renomear realmente os arquivos que você precisa remover # antes de # os.rename(fullpath,newpath) .

Configurando o script

Todas as regras padrão para scripts são aplicadas: - salve-o como add_location_name.py no diretório mais alto - faça executável com chmod +x ./add_location_name.py - execute com ./add_location_name.py

Testando o script

Aqui está um exemplo de como isso funciona na prática. Eu criei um diretório com outros dois, Movie A (2016) e Movie B (2016) . Dentro deles, ambos têm dois arquivos. Nosso script está no mesmo diretório:

$ tree                                                        
.
├── add_location_name.py
├── Movie A (2014)
│   ├── filea.mkv
│   └── fileb.srt
└── Movie B (2016)
    ├── filea.mkv
    └── fileb.srt

Então, quando executarmos o script, veremos a seguinte saída:

$ ./add_location_name.py                                                                                              
Move /home/xieerqi/testdir/Movie A (2014)/fileb.srt to ./Movie A (2014)/./Movie A (2014).srt
Move /home/xieerqi/testdir/Movie A (2014)/filea.mkv to ./Movie A (2014)/./Movie A (2014).mkv
Move /home/xieerqi/testdir/Movie B (2016)/fileb.srt to ./Movie B (2016)/./Movie B (2016).srt
Move /home/xieerqi/testdir/Movie B (2016)/filea.mkv to ./Movie B (2016)/./Movie B (2016).mkv

2. Solução via comando de localização e sinalizador -exec

O comando

find é útil de várias maneiras, especialmente ao executar operações em vários níveis da árvore de diretórios. Nesse caso específico, podemos usá-lo para filtrar todos os arquivos e executar uma operação de renomeação neles.

Antes de tudo, deixe-me dar a solução:

find -type f -exec bash -c 'fp=$(dirname "$1");fn=$(basename "$fp");px="${1##*.}";mv "$1" "$fp"/"$fn"."$px"' sh "{}" \;

Parece longo e assustador, certo? Mas não se preocupe, vamos ver como funciona.

Dissecando o comando

Primeiro de tudo, você precisa reconhecer que há duas coisas acontecendo: o comando find localiza todos os arquivos e bash part é o que realmente faz a parte de renomeação. Do lado de fora, o que vemos é o simples comando:

find -type f -exec <COMMAND> \;

Isso só encontra todos os arquivos (sem diretórios ou links simbólicos) e chama algum outro comando sempre que encontrar um arquivo. Neste caso, o comando específico que temos é bash .

Então, o que bash -c 'fp=$(dirname "$1");fn=$(basename "$fp");px="${1##*.}";mv "$1" "$fp"/"$fn"."$px"' sh "{}" faz? Bem, em primeiro lugar, reconheça a estrutura: bash -c 'command1;command2' arg0 arg1 . Sempre que -c flag for usado, o primeiro argumento de linha de comando arg0 será definido como $0 , nome do shell, portanto, isso é irrelevante, mas "{}" é importante. Esse é o espaço reservado entre aspas para o nome do arquivo que find passará como argumento para bash .

No interior do comando bash, extraímos o caminho do arquivo fp=$(dirname "$1") , o nome do diretório fn=$(basename "$fp") e a extensão ou prefixo do arquivo px="${1##*.}" . Tudo isso funciona muito bem, já que estamos executando o comando no diretório mais importante (muito importante!). Finalmente, o mv "$1" "$fp"/"$fn"."$px"' sh "{}" irá renomear o arquivo original que find nos deu para o novo nome de arquivo, o que construímos com "$fp"/"$fn"."$px" usando todas essas variáveis.

Exemplo de operação

O teste do comando é realizado no mesmo diretório de antes:

$ tree
.
├── Movie A (2014)
│   ├── filea.mkv
│   └── fileb.srt
└── Movie B (2016)
    ├── filea.mkv
    └── fileb.srt

2 directories, 4 files

E se executarmos o comando, com echo em vez de mv , poderemos ver que cada nome de arquivo é renomeado, respectivamente.

$ find -type f -exec bash -c 'fp=$(dirname "$1");fn=$(basename "$fp");px="${1##*.}";echo "$1" "$fp"/"$fn"."$px"' sh ">
./Movie A (2014)/fileb.srt ./Movie A (2014)/Movie A (2014).srt
./Movie A (2014)/filea.mkv ./Movie A (2014)/Movie A (2014).mkv
./Movie B (2016)/fileb.srt ./Movie B (2016)/Movie B (2016).srt
./Movie B (2016)/filea.mkv ./Movie B (2016)/Movie B (2016).mkv

Lembre-se : o comando acima usa echo apenas para testes. Quando você usa mv , não há saída, então o comando é silencioso.

3.Aproximação do simulador: Bash e glob star

As duas abordagens acima usam o percurso de árvore recursiva. Como no seu exemplo você tem apenas dois níveis na árvore de diretórios (diretório de filmes e arquivos), podemos simplificar nosso comando shell anterior da seguinte forma:

for f in */* ;do fp=$(dirname "$f"); ext="${f##*.}" ; echo "$f" "$fp"/"$fp"."$ext" ;done

Novamente, a mesma ideia - substitua echo por mv quando tiver certeza de que funciona corretamente.

Os resultados do teste são os mesmos:

$ tree                                                                                                                
.
├── add_location_name.py
├── Movie A (2014)
│   ├── filea.mkv
│   └── fileb.srt
└── Movie B (2016)
    ├── filea.mkv
    └── fileb.srt

2 directories, 5 files
$ for f in */* ;do fp=$(dirname "$f"); ext="${f##*.}" ; echo "$f" "$fp"/"$fp"."$ext" ;done                            
Movie A (2014)/filea.mkv Movie A (2014)/Movie A (2014).mkv
Movie A (2014)/fileb.srt Movie A (2014)/Movie A (2014).srt
Movie B (2016)/filea.mkv Movie B (2016)/Movie B (2016).mkv
Movie B (2016)/fileb.srt Movie B (2016)/Movie B (2016).srt
    
por Sergiy Kolodyazhnyy 07.04.2017 / 16:11
3

Dado

$ tree
.
└── A
    ├── B
    │   ├── somefile
    │   ├── T.txt
    │   ├── X.srt
    │   └── Z.mkv
    └── C
        ├── somefile
        ├── T.txt
        ├── W.mkv
        └── Y.srt

3 directories, 8 files

então

$ find A -type f \( -name '*.mkv' -o -name '*.srt' \) -not -name '.*' -exec sh -c '
  for f; do 
    dir="${f%/*}" ; ext="${f##*.}" ; new="${dir##*/}"
    echo mv -- "$f" "${dir}/${new}.${ext}"
  done' sh {} +
mv -- A/C/Y.srt A/C/C.srt
mv -- A/C/W.mkv A/C/C.mkv
mv -- A/B/Z.mkv A/B/B.mkv
mv -- A/B/X.srt A/B/B.srt

(remova o echo assim que tiver certeza que vai fazer o que quiser)

    
por steeldriver 07.04.2017 / 14:45