Remover caracteres de nomes de arquivos recursivamente

5

Eu tenho centenas de diretórios, alguns aninhados em outros diretórios, com dezenas de milhares de arquivos. Os arquivos precisam ter um carimbo de data / hora removido deles.

Um nome de arquivo de exemplo é Letter to Client 27May2016~20160531-162719.pdf e eu gostaria que ele voltasse a ser Letter to Client 27May2016.pdf

Outro exemplo de nome de arquivo é ABCDEF~20160531-162719 e eu gostaria que ele voltasse a ser ABCDEF . Note que este arquivo não tem extensão, ao contrário do exemplo acima.

O ideal é que eu esteja esperando um comando que possa ser executado na raiz das pastas afetadas que percorrerão recursivamente e encontrarão / corrigirão os nomes dos arquivos.

Eu tentei resolver isso com sed ou mmv , mas não vejo uma solução. Qualquer ajuda seria muito apreciada.

(Caso alguém esteja curioso para saber por que estou tentando resolver isso, eu uso o Syncthing para sincronizar arquivos e restaurei arquivos excluídos copiando-os do diretório .stversions de volta para onde eles estavam, mas descobri que o Syncthing anexa esse carimbo de data / hora ...)

    
por file woes 11.12.2017 / 19:09

3 respostas

5

Conheça a ferramenta Perl rename :

$ rename -n -v  's/~[^.]+//' *~*
rename(ABCDEF~20160531-162719, ABCDEF)
rename(Letter to Client 27May2016~20160531-162719.pdf, Letter to Client 27May2016.pdf)

( página man online , também verse isto Q )

Esse regex diz para combinar um til, como muitos caracteres que não são pontos, mas pelo menos um; e para substituir o que combina com uma string vazia. Remova o -n para realmente fazer a substituição. Poderíamos alterar o padrão para ~[-0-9]+ para substituir apenas dígitos e traços.

Desculpe, você disse "recursivamente", então vamos usar find :

$ find -type f -name "*~*" -execdir  rename -n -v  's/~[-0-9]+//' {} +
rename(./ABCDEF~20160531-162719, ./ABCDEF)
rename(./Letter to Client 27May2016~20160531-162719.pdf, ./Letter to Client 27May2016.pdf)

Ou apenas com o Bash ou o ksh, embora os diretórios com ~ seguido por dígitos quebrem isso:

$ shopt -s extglob       # not needed in ksh (as far as I can tell)
$ shopt -s globstar      # 'set -o globstar' in ksh
$ for f in **/*~* ; do 
    g=${f//~+([-0-9])/}; 
    echo mv -- "$f" "$g" 
  done
mv -- ABCDEF~20160531-162719 ABCDEF
mv -- Letter to Client 27May2016~20160531-162719.pdf Letter to Client 27May2016.pdf

Novamente, remova o echo para fazer a renomeação.

    
por 11.12.2017 / 19:15
3

No bash:

shopt -s globstar
for file in **/*~[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9][0-9][0-9]*
do
  echo mv -- "$file" "${file/~[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9][0-9][0-9]/}"
done

Isso localiza todos os nomes de arquivos (recursivamente) que correspondem ao padrão de data (após um til) e, em seguida, exibe um comando mv de amostra para renomeá-los. O destino do comando mv é o resultado de uma expansão de parâmetro bash que substitui qualquer texto de data e hora sem nada.

    
por 11.12.2017 / 19:27
-1

Código:

echo "ABCDEF~20160531-162719" | sed "s/~.*//g"
echo "Letter to Client 27May2016~20160531-162719.pdf" |sed "s/~.*[^.pdf]//g"

Os comandos acima atingem o resultado mencionado

    
por 12.12.2017 / 02:57

Tags