shell-script-pt
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [shell-script-pt] Localizar arquivos e substituir


From: Arkanon
Subject: Re: [shell-script-pt] Localizar arquivos e substituir
Date: Mon, 20 Sep 2021 20:54:14 -0300

Oi, Marcelo.

Sempre que aparece a necessidade de normalizar o nome de arquivos, lembro de como isso pode ser mais complicado do que parece à primeira vista :-/

Às vezes queremos apenas remover pontos, como no caso, mas às vezes queremos substituir um conjunto de caracteres, alterar case, limpar acentos e cedilhas; às vezes apenas nos nomes dos arquivos, às vezes incluindo os diretórios na jogada. Muitas vezes com espaços em branco. Às vezes em poucos arquivos, às vezes em centenas, senão milhares. Com caracteres em um charset diferente do usado no terminal. Arquivos que, renomeados, podem conflitar com outros já existentes. Filesystem case insensitive é outro complicador em potencial.

O Alfredo e o Julio mostraram uma forma bastante sintética e direta de fazer isso usando os comandos rev, sed e cut. De fato é como provavelmente faremos, principalmente interagindo com o terminal em tempo real :)

No curso altamente recomendado de Programação Shell Linux do Julio e do Rubens, um dos focos é a performance. Logo fica muito evidente a vantagem dos comandos builtin do shell em relação aos externos no que diz respeito à velocidade. Mesmo algoritmos um pouco mais complexos podem resultar em uma execução drasticamente(!) mais rápida se utilizarem recursos nativos do shell ao invés de externos.

Desejando renomear apenas os arquivos (não os diretórios), uma solução envolvendo apenas comandos nativos do bash seria nessa linha: (não está descartado o uso de nomes mais adequados para as variáveis :-p)

ren()
{
  p=$1                                 # caminho (relativo ou absoluto) composto por [hierarquia de diretórios/][nome do arquivo] (hierarquia possivelmente vazia, nome do arquivos possivelmente sem extensão)
  [[ $p == */* ]] && d=${p%/*}  || d=  # se houver uma barra no caminho, a hierarquia de diretórios é tudo que houver ANTES da última ocorrência da barra, senão é explicitamente vazia
  f=${p##*/}                           # o nome do arquivo é o que houver DEPOIS da última ocorrência da barra (se não houver ocorrẽncias, é tudo)
  b=${f%.*}                            # o basename do arquivo (nome sem extensão) é tudo que houver ANTES da última ocorrência de ponto no nome do arquivo
  b=${b//[. ]/_}                       # basename com pontos e espaços trocados por
  [[ $f == *.* ]] && e=${f##*.} || e=  # se houver um ponto no nome, a extensão é o que houver DEPOIS da última ocorrência do ponto, senão é explicitamente vazia
  e=${e// /_}                          # extensão com espaços trocados por _
  [[ $b ]] && n=$b${e:+.$e} || n=_$e   # se o basename não for vazio, o novo nome é o basename junto da extensão, senão (basename vazio), o novo nome é a própria extensão mas o ponto é substituído por um underscore
  [[ -e $d/$n ]] && n=$RANDOM-$n      # se o caminho/nome resultante já existir, adiciona ao basename um prefixo randômico
  echo -e "# p='$p'\n# d='$d'\n# f='$f'\n# b='$b'\n# e='$e'\n# n='$n'"
# [[ $f != $n ]] && mv "$d/$f" "$d/$n" # se o nome resultante for diferente do original, renomeia (passo desativado pelo # inicial)
}

Na função, o cut e sed foram substituídos por sequências de expansão de parâmetro com resultado equivalente. A diferença dessas expansões em relação aos comandos externos vai além da sintaxe: enquanto um comando externo precisa ser lido de uma mídia com IO possivelmente comprometido, a expansão de parâmetros é executada diretamente na pilha de variáveis do shell, que já está e continua na RAM. Dependendo das condições de execução, a velocidade de uma sequência de builtins justificará sua aparência extensa.

Teste:

ren 'a/b c/.file.1  bkp.ext ension'
# p='a/b c/.file.1  bkp.ext ension'
# d='a/b c'
# f='.file.1  bkp.ext ension'
# b='.file.1  bkp'
# e='ext_ension'
# n='_file_1__bkp.ext_ension'

Outros exemplos para teste:

> f_g_h.e
> _f_g.e
ren 'f'
ren 'f.e'
ren 'f.g.e'
ren 'f.g h.e'
ren './f.g h.e'
ren '.f'
ren '.f.e'
ren '.f g'
ren '.f g.e'
ren './.f g.e'

Ab,

Em seg., 20 de set. de 2021 às 14:01, Marcelo <msalavee@gmail.com> escreveu:
Boa Tarde,

Tenho um servidor samba que alguns usuários começaram a salvar arquivos e diretórios com (.) no nome, por exemplo:

Arquivo1-20.09.2021-Prof.Marcelo.xls

Estou querendo bloquear este tipo de arquivo, mas antes preciso renomeá-los.

gostaria de substituir os (.) pontos no nome por (_)underline e deixar obviamente o (.) na extensão.

o Nome do arquivo ficaria:

Arquivo1-20_09_2021-Prof_Marcelo.xls

Alguém poderia dar uma dica?


Obrigado,
Marcelo
_______________________________________________
Lista brasileira de usuários de shell script
Endereço de e-mail da lista: shell-script-pt@nongnu.org
Para se inscrever ou desinscrever acesse: https://lists.nongnu.org/mailman/listinfo/shell-script-pt
Para ver os arquivos da lista (mensagens anteriores) e pesquisar nelas, acesse https://lists.nongnu.org/archive/html/shell-script-pt/

NOTA: A lista anterior, no Yahoo Groups, foi *desativada*. Por favor utilize somente esta.


--
(o_  @arkanon  (Twitter)     __o
//\   arkanon@lsd.org.br   _`\<,
V_/_      www.lsd.org.br  (_)/(_)
---------------------------------

reply via email to

[Prev in Thread] Current Thread [Next in Thread]