Renomeia os arquivos a serem capitalizados, mas não afetam as extensões de arquivo

7

Estou usando isso no diretório de um cliente para renomear os arquivos com a primeira letra de cada palavra sendo capitalizada de acordo com a solicitação deles:

rename 's/\b(\w)/\u$1/g' *

Isso funciona bem, mas também coloca em maiúscula a primeira letra da extensão, então eu uso isso para corrigir isso:

rename 's/\.Txt$/.txt/' *.Txt

que funciona bem se a maioria dos arquivos em uma pasta for da mesma extensão (geralmente verdadeira), mas será um problema se eles forem muito misturados.

Para contornar esse problema, criei um pequeno script que se parece com isso (não ria!):

#!/bin/bash
rename 's/\.Txt$/.txt/' *.Txt
rename 's/\.Doc$/.doc/' *.Doc
rename 's/\.Docx$/.docx/' *.Docx
...
rename 's/\.Xlsx$/.xlsx/' *.Xlsx

Eu ignoro os erros 'Não consigo renomear * .Txt * .txt: No such file or directory', e se eu encontrar uma extensão que está faltando, basta adicionar essa linha ao meu script.

Eu não acho que isso importará, mas os arquivos estão em um servidor Windows, mas estou acessando-o usando o Ubuntu 16.04LTS. Se isso importa, então eu poderia copiá-los para a minha unidade local primeiro, executar um comando no Ubuntu e, em seguida, mover os arquivos de volta, se necessário.

Existe alguma maneira de alterar o primeiro comando de renomeação para ignorar as extensões e deixá-las em minúsculas? Posso executar o novo comando em um diretório de nível superior e recursá-lo em todos os subdiretórios?

    
por Alan 31.10.2017 / 00:07

4 respostas

7

Uma maneira de conseguir isso pode ser usar Negativo Lookbehind para corresponder apenas ao limite de palavras - caractere de palavra seqüência quando não é precedida por um período literal, por exemplo dado

$ ls
alan's file.txt  bar.txt  foo

então

$ rename -n 's/(?<!\.)\b\w*/\u$&/g' *
rename(alan's file.txt, Alan'S File.txt)
rename(bar.txt, Bar.txt)
rename(foo, Foo)

Supondo que você também queira evitar capitalizar o s pluralizante, poderemos modificá-lo para

$ rename -n 's/(?<![.'\''])\b\w*/\u$&/g' *
rename(alan's file.txt, Alan's File.txt)
rename(bar.txt, Bar.txt)
rename(foo, Foo)

ou até mesmo

$ rename -n 's/(?<![[:punct:]])\b\w*/\u$&/g' *
rename(alan's file.txt, Alan's File.txt)
rename(bar.txt, Bar.txt)
rename(foo, Foo)
    
por steeldriver 31.10.2017 / 01:04
5

Isto irá capitalizar a primeira letra de cada palavra, exceto a extensão final:

rename -n 's/\b(.+?)\b/\u$1/g; s/(.+)\.(.)/$1\.\l$2/' *

Eu testei com esses arquivos:

$ ls -1
'a file with a '$'\n''new line.foo'
'a file with spaces.txt'
justonelongfilename.ext
no-extensions-here
this.has.many.extensions.pdf

E ele será renomeado como:

$ rename -n 's/\b(.+?)\b/\u$1/g; s/(.+)\.(.)/$1\.\l$2/' *
a file with a 
new line.foo -> A File With A 
New Line.foo
a file with spaces.txt -> A File With Spaces.txt
justonelongfilename.ext -> Justonelongfilename.ext
no-extensions-here -> No-Extensions-Here
this.has.many.extensions.pdf -> This.Has.Many.Extensions.pdf

O truque é primeiro capitalizar cada primeira letra, ignorando as extensões, e depois voltar e fazer a extensão em minúsculas:

  • s/\b(.+?)\b/\u$1/g; : O .+? é um padrão não-ganancioso, o que significa que encontrará a correspondência mais curta possível. Como ele está ancorado por limites de palavras ( \b ), isso localizará todas as palavras (todas por causa do% finalg). Estes são então substituídos pela versão capitalizada (primeira letra maiúscula) deles mesmos ( \l$1 ).

  • s/(.+)\.(.)/$1\.\l$2/ : o .+ é ganancioso, por isso encontrará a correspondência mais longa possível. Isso significa a string mais longa até um% final . , após o qual será a extensão (se houver). Substituímos a correspondência por tudo antes da extensão ( $1 ), um . e a extensão com a primeira letra inferior novamente ( \l$2 ).

A recursão é bastante fácil também. Se o seu shell é bash (se você não sabe, provavelmente é), você pode usar a opção globstar que faz com que ** corresponda a 0 ou mais subdiretórios:

shopt -s globstar

Agora, execute o comando rename assim (isso também funcionará em qualquer arquivo do diretório atual):

rename -n 's/\b(.+?)\b/\u$1/g; s/(.*)\.(.)/$1\.\l$2/' **

Para limitá-lo apenas a arquivos ou diretórios com extensões, use **/*.* em vez de ** .

Como alternativa, use find :

find /path/to/dir -exec rename -n 's/\b(.+?)\b/\u$1/g; s/(.*)\.(.)/$1\.\l$2/' {} +

E, para limitar a esses arquivos e diretórios com uma extensão:

find /path/to/dir -name '*.*' -exec rename -n 's/\b(.+?)\b/\u$1/g; s/(.*)\.(.)/$1\.\l$2/' {} +

Note que todas essas soluções renomearão alegremente os diretórios, bem como os arquivos . Se você não quiser isso, tenha cuidado com o local para reciclar ou forneça um padrão mais específico, como *.txt .

Em todos os exemplos, remova o -n para fazê-los realmente fazer alguma coisa. O -n faz com que rename simplesmente imprima o que ele faria e não realmente faça qualquer coisa. Útil para testes.

    
por terdon 31.10.2017 / 00:45
4

A maneira mais sensata seria abordar todas as "palavras" (com o uso do limite de palavra \b e referindo-se via $1 a qualquer primeiro caractere) incluindo a extensão, mas em minúsculas a extensão em si:

$ prename -nv 's/\b(.)/\u$1/g;s/^(.*)\.(.*)/$1.\l$2/' *                                                                                                                
another filename trispaced.txt renamed as Another Filename Trispaced.txt
filename_with_underschore.txt renamed as Filename_with_underschore.txt
one filename.txt renamed as One Filename.txt

Observe que isso não funciona para o nome do arquivo com sublinhados, ou seja, os limites "word" são considerados em espaços em branco (guias, espaços, novas linhas - que, esperamos, não deveriam estar no nome do arquivo).

Observe o uso de prename para portabilidade para ksh , onde rename é realmente um comando interno, não o executável perl independente.

    
por Sergiy Kolodyazhnyy 31.10.2017 / 00:15
1

Use apenas rename 's/\b(\w)/\u$1/' * SEM a bandeira g.
A bandeira g significa "global = fazer várias vezes". Você faz 1ª vez no nome do arquivo, e você não quer fazer letras maiúsculas na 2ª vez?

    
por V-Mark 31.10.2017 / 00:12