Renomeia vários arquivos para diminuir o número no nome do arquivo?

2

Eu nomeei incorretamente arquivos que não são sincronizados com -1. O problema é que eu preciso renomear 1000s deles.

  • DBGC180_805754
  • DBGC180_805755
  • DBGC180_805756

para

  • DBGC180_805753
  • DBGC180_805754
  • DBGC180_805755

Eu preferiria usar scripts bash ou um comando unix.

    
por iamunix 27.09.2016 / 18:48

6 respostas

3

  1. Mova os arquivos para renomear em um subdiretório (sem alterar o nome deles).
  2. Renomeie os arquivos do subdiretório para o diretório original.

Existem dois motivos pelos quais recomendo o passo 1, mesmo que seja possível sem ele:

  • Se o comando for interrompido, você poderá continuar de onde parou, já que é óbvio quais arquivos já foram renomeados e quais não foram.
  • Você não precisa se preocupar em renomear na ordem errada e sobrescrever um dos arquivos existentes.

Snippet de shell não testado (contando com o fato de que o número a decrementar nunca possui zeros à esquerda):

mkdir to_decrement
for x in DBGC180_80575[4-9] DBGC180_8057[6-9]? DBGC180_805[8-9]?? DBGC180_80[6-9]??? DBGC180_8[1-9]???? DBGC180_9?????; do
  mv "$x" to_decrement/
done
cd to_decrement
for x in *; do
  number="${x##*_}"
  mv -i -- "$x" "../${x%_*}_$((number-1))"
done
cd ..
rmdir to_decrement

Com zsh , você pode tornar isso muito mais simples, graças ao seu intervalo numérico glob , seu incorporado em mv que evita a execução em limites de comprimento de linha de comando e seu função de renomeação em massa baseada em padrões . Em zsh:

autoload -U zmv
zmodload -m -F zsh/files b:zf_\*
mkdir to_decrement
zf_mv DBGC180_<805754-> to_decrement/
zmv 'to_decrement/(*)_(*)' '${1}_$(($2-1))'
rmdir to_decrement
    
por 29.09.2016 / 03:31
2

Você pode fazer isso:

# {smallestfilenum..largestfilenum}

for i in {805754..999999}; do 
   mv "DBGC180_$i" "DBGC180_$(($i-1))";
done

Experimente com um número pequeno (por exemplo, 805754..805758) para garantir que ele funcione conforme o esperado. Esteja ciente de que, se um arquivo já existir com o novo nome, ele será substituído.

    
por 27.09.2016 / 19:52
0

Então, você deseja renomear DBGC180_805754 para DBGC180_805753 , ...55 para ...54 e assim por diante. Esse é o problema que vou abordar.

Primeiro, coloque esse script em algum lugar no seu PATH , chame-o de waltinator .

#!/bin/bash
#step through the parameters 
while [[ -n "$1" ]] ; do
    oldname="$1"
    # shift the arguments left
    shift;
    # strip off the fixed part of the old name
    oldnum=${oldname##DBGC180_}
    # decrement the number (this is what was wanted, right?)
    newnum=$(( $oldnum - 1 ))
    # build the new, improved filename
    newname="DBGC180_$newnum"
    if [[ -f "$newname" ]] ; then
        printf "Cannot rename $oldname to $newname, $newname exists.\n" >&2
        exit 1
    fi
    mv --no-clobber "$oldname" "$newname"
done
exit 0

Para a próxima etapa, suponha que o script esteja em $HOME/bin/waltinator e você tenha chmod +x $HOME/bin/waltinator .

find . -type f -name 'BDGC180_[0-9][0-9][0-9][0-9][0-9][0-9]' -print | \
    sort | \
    xargs $HOME/bin/waltinator

O find localiza os arquivos (em nenhuma ordem específica), cujos nomes correspondem ao padrão glob glob " BDGC180_ seguido por 6 dígitos ( [0-9] ). Como queremos uma lista ordenada (seria uma falha renomear ...97 para ...96 antes de renomear ...96 ) executamos a saída de find a sort Então usamos xargs para obter a lista (classificada) de nomes de arquivos e construir um comando para passar a (classificada) lista de nomes de arquivos para $HOME/bin/waltinator . Leia man xargs se você precisar encurtar a lista arg.

Para esse assunto, leia:

for page in bash mv find sort xargs ; do
    man "$page"
done   
    
por 27.09.2016 / 19:44
0

Se você quiser renomear esses arquivos específicos, aqui está a solução (estática). Primeiro renomeie e mova esses arquivos para o subdiretório. De lá, mova esses arquivos para o diretório atual

#!/bin/bash
# rename.sh

#make a subdirectory
mkdir -p subDir

#move all files to subdirectory with rename
for i in {5754..6754}; do
   mv "DBGC180_80$i" "./subDir/DBGC180_80$(($i-1))";
done

#move all files from subdirectory to current directory
for j in {5754..6754}; do
    mv "./subDir/DBGC180_80$(($j-1))" "./DBGC180_80$(($j-1))"
done

#remove subdirectory
rmdir subDir

Este programa pode ser modificado para ser genérico (dinâmico)

    
por 29.09.2016 / 07:37
-1

Uau, isso foi mais complicado do que eu esperava.

Como Gilles apontou , considerando o número de arquivos a serem manipulados, você deve renomeá-los de uma forma isso não lhe dará problemas se o comando for interrompido. O comando abaixo faz isso.

Eu escrevi este comando para ser bastante robusto contra falhas. Observe que explicitamente excluímos arquivos em que o número tem um 0 à esquerda; se você tiver arquivos como esse, poste um comentário e incluirei um comando para lidar com eles.

find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9]' -exec sh -c 'for f; do mv -i "$f" "${f%_*}_$((${f##*_}-1)).decremented"; done' find-sh-decrement {} + && find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9].decremented' -exec sh -c 'for f; do mv -i "$f" "${f%.decremented}"; done' find-sh-remove-prefix {} +

Com invólucros de linha (ainda podem ser copiados e colados):

find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9]' \
  -exec sh -c 'for f;
    do mv -i "$f" "${f%_*}_$((${f##*_}-1)).decremented";
    done' find-sh-decrement {} + &&
  find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9].decremented' \
  -exec sh -c 'for f;
    do mv -i "$f" "${f%.decremented}";
    done' find-sh-remove-prefix {} +

Explicação das partes (isso pode usar alguma limpeza de formatação):

##### Recursively find regular files in the current directory...
find . -type f
##### whose name matches this exact pattern...
-name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9]'
##### and run the following shell script...
-exec sh -c
##### (shell script: ) for every file given as an argument...
'for f;
##### rename the file, prompting for confirmation for any overwrites...
do mv -i
##### from the original file name...
"$f"
##### to the file name decremented by 1, with '.decremented' afterward...
"${f%_*}_$((${f##*_}-1)).decremented";
##### (End of shell script)
done'
##### on as many found files as possible at once,
##### using the name "find-sh-decrement" for error reporting.
find-sh-decrement {} +
##### If that completes successfully...
&&
##### Pass through again and remove the ".decremented" prefix.
find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9].decremented' -exec sh -c 'for f; do mv -i "$f" "${f%.decremented}"; done' find-sh-remove-prefix {} +

Resultados do teste:

$ ls
DBGC180_805754  DBGC180_805755  DBGC180_805756
$ cat DBGC180_805754
This file started as DBGC180_805754
$ cat DBGC180_805755 
This file started as DBGC180_805755
$ cat DBGC180_805756
This file started as DBGC180_805756
$ find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9]' -exec sh -c 'for f; do mv -i "$f" "${f%_*}_$((${f##*_}-1)).decremented"; done' find-sh-decrement {} + && find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9].decremented' -exec sh -c 'for f; do mv -i "$f" "${f%.decremented}"; done' find-sh-remove-prefix {} +
$ ls
DBGC180_805753  DBGC180_805754  DBGC180_805755
$ cat DBGC180_805753
This file started as DBGC180_805754
$ cat DBGC180_805754
This file started as DBGC180_805755
$ cat DBGC180_805755
This file started as DBGC180_805756
$ 

Para maior segurança, execute o primeiro comando find e inspecione os resultados antes de executar o segundo comando para remover o sufixo .decremented .

Execute isto:

find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9]' \
  -exec sh -c 'for f;
    do mv -i "$f" "${f%_*}_$((${f##*_}-1)).decremented";
    done' find-sh-decrement {} +

Em seguida, inspecione os resultados e, em seguida, execute:

find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9].decremented' \
  -exec sh -c 'for f;
    do mv -i "$f" "${f%.decremented}";
    done' find-sh-remove-prefix {} +
    
por 29.09.2016 / 08:56
-1

Use awk para criar um script de renomeação totalmente expandido:

find . -name "DBGC180_*" |sort |awk -F "_" '{print "mv -i "$0" "$1"_"$2-1}' >/tmp/rename.sh

Você pode revisar o script antes de executá-lo. Esse é o recurso exclusivo dessa solução. Então execute:

sh -e -x /tmp/rename.sh

Notas

  • você pode melhorar o padrão de localização, a pergunta não é 100% clara sobre quais arquivos precisam ser renomeados.
  • sort é importante para não sobrescrever arquivos existentes
  • mv option -i torna mais seguro nunca sobrescrever arquivos
  • sh option -e é abortar o script em caso de erro
  • sh option -x imprime um rastreio para ver o que foi feito até o momento, caso o script seja interrompido (para tornar possível a recuperação). Você também pode usar mv -v , se suportado.
por 27.09.2016 / 21:53