De acordo com as Leis 12.965/2014 e 13.709/2018, que regulam o uso da Internet e o tratamento de dados pessoais no Brasil, ao me inscrever na newsletter do portal DICAS-L, autorizo o envio de notificações por e-mail ou outros meios e declaro estar ciente e concordar com seus Termos de Uso e Política de Privacidade.


Renomeando Vários Arquivos Simultaneamente

Colaboração: Thiago Cesar Vieira

Data de Publicação: 01 de abril de 2010

Sabe aquela boa funcionalidade do MS Windows para renomear arquivos simultaneamente? Você seleciona alguns arquivos no gerenciador de arquivos Windows Explorer, clica com o botão direito do mouse, então Renomear, escreve um nome e os arquivos são magicamente nomeados seguindo uma ordem de numeração!

Sente falta desse recurso no seu Linux?

Esse script tem a mesma função. Mas, ainda não no Nautilus (gerenciador de arquivos do GNOME)... por enquanto apenas no terminal!

Como usar o script

As câmeras digitais armazenam arquivos com nomes sequenciais, que fazem pouco sentido para os usuários, por exemplo: DSC74201.JPG, DSC74202.JPG.

Suponhamos que queiramos renomeá-las de acordo com um tema. Por exemplo, para renomear todas as fotos que tirar na praia, use o script da seguinte forma:

  $ renaming_files.sh  "passeio_praia"  /home/eu/fotos/

Os arquivos do diretório /home/eu/fotos/ serão renomeados. Veja na tabela abaixo o resultado.

Antes Depois
DSC74218.JPG passeio_praia (1).JPG
DSC74223.JPG passeio_praia (2).JPG
DSC74247.JPG passeio_praia (3).JPG

ATENÇÃO: todos os arquivos do diretório serão renomeados! Se você tem documentos, fotos e vídeos no mesmo lugar, provavelmente não queira renomeá-los da mesma forma. Assim, é interessante renomear por grupos de arquivos.

Para trabalhar com uma lista de arquivos, basta apenas informar os arquivos a renomear. Por exemplo:

  $ renaming_files.sh  "passeio_praia"  DSC74218.JPG DSC74223.JPG

Isso faz com que somente os arquivos DSC74218.JPG e DSC74223.JPG sejam renomeados para passeio_praia (1).JPG e passeio_praia (2).JPG, respectivamente.

Aos usuários inexperientes: tenha muito cuidado ao usar comando que renomeiam arquivos em lotes. O resultado talvez seja irreversível. Então, assegure-se do que está fazendo.

Script

Segue abaixo o Bash script.

Por favor, opine caso não tenha gostado de uma linha de código, por motivos de performance, perigo ao executar tal comando, ilegibilidade ou qualquer outro que ache conveniente.

Gostaria de aprender como se faz corretamente.

  #!/bin/bash
  #
  # Rename a list of files or all files in a directory.
  # File:   renaming_files.sh
  # Author: Thiago Cesar Vieira
  # Date:   2010-02-27
  # Usage:  renaming_files.sh "{new file name}" {list of files or directory}
  # Note:   file extension will NOT be changed. Only files in that directory will be renamed, NOT enter in subdirectories.
  # Todo:   Try to reorder the list of files before changing name.
  #
  # For example:
  #  Running    'renaming_files.sh "my travel" /home/me/pictures/'
  #  Files in the /home/me/pictures/ directory will be renamed to: 'my travel (1).jpg', 'my travel (2).jpg', 'my travel (3).PNG', etc.
  #
  #  Running    'renaming_files.sh "workshop"  2010-02-08.doc 2010-02-25.doc'
  #  Rename  '2010-02-08.doc' and '2010-02-25.doc' to: 'workshop (1).doc' and 'workshop (2).doc'.
  
  
  helpfunc()
  {
  echo $'\n'"Rename a list of files or all files in a directory."
  echo "Usage: $0 {\"new file name\"} {list of files or directory}"
  echo "For example:"
  echo " Running    '$0 \"my travel\" /home/me/pictures/'"
  echo " Files in the /home/me/pictures/ directory will be renamed to: 'my travel (1).jpg', 'my travel (2).jpg', 'my travel (3).PNG', etc."
  echo
  echo " Running    '$0 \"workshop\"  2010-02-08.doc 2010-02-25.doc'"
  echo " Rename '2010-02-08.doc' and '2010-02-25.doc' to: 'workshop (1).doc' and 'workshop (2).doc'."
  echo $'\a' # alert (bell)
  exit 1
  }
  
  
  # new file names
  NEW_FILENAME="$1"
  
  # reassigns the positional parameters, shifting them to the left one notch. $1 <- $2, $2 <- $3
  shift
  
  # directory or a file
  DIRECTORY_OR_FILE="$1"
  
  
  # Bash scripts use $IFS (Internal Field Separator) variable to determine what are field separators. By default $IFS is set to the space character. Changing to new line.
  # setting $IFS: now it will only split on newlines, not spaces
  IFS=$'\n'
  
  
  # checking if the pattern is not empty
  if [ "$NEW_FILENAME" != "" ] ; then
  
  # checking if trying to renames files in directory or a list of files
  # checking if directory exist
  if [ -d "$DIRECTORY_OR_FILE" ] ; then
  
    echo "Renaming all files in '$DIRECTORY_OR_FILE'..."
  
    # get all files in the directory (ignore sub-directories)
    ORIGINAL_FILES=$(find $DIRECTORY_OR_FILE  -maxdepth 1  -type f)
  
  # checking if file exist
  elif [ -f "$DIRECTORY_OR_FILE" ] ; then
  
    ORIGINAL_FILES=$*
  
    echo "Renaming files:"
    echo "$ORIGINAL_FILES"
  
  else
    echo "Fatal error. No input found. Enter a directory of a list of files to rename."
    helpfunc
  fi
  
  
  # start counter (used to rename files sequentially
  intCounter=1
  
  # loop for all files
  for ORIGINAL_FILE in $ORIGINAL_FILES ; do
  
    # checking if file really exist. Note, -e test also return true if argument is a directory!
    if [ -f "$ORIGINAL_FILE" ] ; then
  
      # get the file-extension
      FILE_EXTENSION="${ORIGINAL_FILE##*.}"  # searching for the last dot
  
      # set the new file-name
      NEW_FILE="$(dirname $ORIGINAL_FILE)/$NEW_FILENAME ($intCounter).$FILE_EXTENSION"
  
      # checking if file already exist
      if [ ! -e "$NEW_FILE" ] ; then
        # renaming the file
        mv --verbose $ORIGINAL_FILE  $NEW_FILE
  
        # increment the counter
        let "intCounter+=1"
      else
        echo "Warning. File '$NEW_FILE' already exists. NOT renaming '$ORIGINAL_FILE'."
      fi
    else
      echo "Warning. File not exist '$ORIGINAL_FILE'. Ignoring..."
    fi
  done
  
  else
  echo "Fatal error. File-name is empty."
  helpfunc
  fi
  
  exit 0

Referências

Existem muitas soluções para esse problema. Como não encontrei nenhuma que satisfazia as minhas necessidades, escrevi um script.

Solução em apenas 1 linha de código!
http://www.slackbr.org/forum/viewtopic.php?f=201&t=16354
Script similar, mas com alguns problemas: não renomeia arquivos com espaços no nome, em meus testes o contador sempre iniciou do 1 quando renomeava mais de um arquivo
http://www.vivaolinux.com.br/script/Script-para-renomear-arquivos/
Script similar, mas com alguns problemas: não renomeia arquivos com espaços no nome, não permite espaços no novo nome, renomeia diretórios, precisa ser rodado dentro do diretório com os arquivos
http://www.dicas-l.com.br/dicas-l/20080301.php
Script para mudar extensão de arquivos, mas com alguns problemas: é estático, não renomeia arquivos com espaços no nome (nessas condições, renomeia outros arquivos fora do padrão especificado), precisa ser rodado dentro do diretório com os arquivos, retorna erro caso tenha diretório com ".txt" no nome, processa arquivos dentro de diretório com ".txt" no nome
http://www.dicas-l.com.br/dicas-l/20080221.php
Script para mudar extensão de arquivos, mas com alguns problemas: é estático, não renomeia arquivos com espaços no nome (nessas condições, renomeia outros arquivos fora do padrão especificado), precisa ser rodado dentro do diretório com os arquivos, retorna erro caso tenha diretório com ".txt" no nome, processa arquivos dentro de diretório com ".txt" no nome, arquivos com mais de um ponto separador não são renomeados corretamente
http://www.dicas-l.com.br/dicas-l/20080219.php
Script para alterar nomes de arquivos
http://www.dicas-l.com.br/dicas-l/20050305.php
Comando rename:
http://linux.about.com/library/cmd/blcmdl1_rename.htm

Error: No site found with the domain 's2.dicas-l.com.br' (Learn more)