Eu tenho que renomear um conjunto de arquivos, usando o comando rename
(com uma expressão regular).
Depois de algumas tentativas, não consigo encontrar uma expressão que obtenha o resultado esperado.
Eu tenho um padrão de arquivo assim:
prefix_some_name_other.txt
Todos os arquivos começam com a string " prefix_
" e terminam com " _other.txt
",
e a parte algum_nome pode consistir em múltiplas palavras (alfanuméricas)
separados por sublinhados.
Então é possível ter:
prefix_one_name_other.txt
prefix_this_is_my_name_1_this1_other.txt
Eu preciso renomear os nomes de arquivos como estes:
other_one-name_datetime
other_this-is-my-name-1-this1_datetime
Em outras palavras:
- É necessário excluir "
prefix
" (deixando o sublinhado)
- O token "
other
" vai para o início do nome do arquivo
- Em algum_nome , converta sublinhado (_) em traço (-)
- O sublinhado no final do nome do arquivo (depois de algum_nome ) deve permanecer
- É necessário excluir a extensão
.txt
, substituída por datetime .
O que eu tentei:
rename 's/fw_([a-z]+)_(\d)_(\w+\d)_(\w+)\.txt/$4_$1-$2-$3_'$datahora'/' *.txt
$datahora
tem o valor datetime (testado). Isso funciona como esperado com
prefix_name_1_gnt1_other.txt
mas não com
prefix_other_name_2_gnt2_other.txt
Onde eu errei? De que outra forma eu poderia conseguir isso?
Suspenso, já que, por enquanto, não consigo encontrar um regex que funcione para todos os nomes de arquivo que tenho. Eu sei que o primeiro elemento na string é sempre prefix
part, e o último elemento é other.txt
parte da string. Portanto, é possível dividir a cadeia em uma matriz e obter os itens necessários para criar o novo nome. Na verdade, algo assim.
datahora="20140718-080000"
arrfiles=( *.txt )
for curfile in ${arrfiles[*]}
do
arrparts=( ${curfile//_/ } )
numitems=${#arrparts[*]}
newname=""
for (( c=1; c<numitems-1; c++ ))
do
newname+="${arrparts[c]}-"
done
newname=${newname%-}
arrparts[numitems-1]=${arrparts[numitems-1]/.txt/}
newname="${arrparts[numitems-1]}_${newname}_$datahora"
echo "$curfile pasa a $newname"
mv ${curfile} ${newname}
done
Depois disso, dou outra tentativa para @peterph suggestion, e finalmente faço algumas combinações de regex rename. Algumas coisas assim:
rename 's/_/-/g' *.txt
rename 's/^fw-(.*)-([^-]*)(\.txt)/$2.$1$3/' *.txt
rename 's/(\w+)\.(.*)(\.txt)/$1_$2_'$datahora'/' *.txt
Não sei qual é a melhor abordagem. Na minha opinião, a variante regex parece mais elegante, mas eu preciso de três operações de renomeação (acesso três vezes ao disco) para fazer o trabalho, enquanto a variante array
só grava uma vez no disco.
O que você acha dessas duas soluções? ...
Obrigado de novo.