script para renomear fotos em massa[RESOLVIDO]

1. script para renomear fotos em massa[RESOLVIDO]

Jean César
dark777

(usa Slackware)

Enviado em 15/03/2018 - 06:06h

wiki.ano

tenho um script que renomeia varios arquivos
porem estava modificando ele para renomear fotos adicionando no nome da mesma o numero em relação a quantidade
mas o meu script nao esta funcionando direito.
pois ao inves de renomear de:

minha - imagen de casa.jpg
minha - imagen do shopping.jpg

para
minha_imagen_de_casa01.jpg
minha_imagen_do_shopping02.jpg

ele esta fazendo

minha_imagen_de_casa1.jpg
minha_imagen_do_shopping1.jpg

#!/bin/sh

IFS='
'

for i in $(ls $1)
do
filtra=$(echo $i |grep ' ')

if [ $filtra ]; then
corpo=$(echo $i | awk -F "." '{print $1}')
extensao=$(echo $i | awk -F "." '{print $2}')
under=$(echo $corpo | sed 's/^ //g;s/ - /_/g;s/ /_/g;')

n=0;
n=$[$n+1];

final=$(echo $under$n.$extensao | sed 's/ $//g;')
mv $i $final

if [ $? -ne 0 ]; then
echo -e "\e[37;1m$i \e[m<-\e[31;1m nothing done.!!\e[m"
else
echo -e "\e[36;1m\n\tFile\e[35;1m: $i\e[m$\e[31;1m\n\n\tRenamed\e[35;1m: \e[33;1m$final\e[m successfully\n\n"
fi
fi
done


wiki.anon


  


2. Re: script para renomear fotos em massa[RESOLVIDO]

Paulo
paulo1205

(usa Ubuntu)

Enviado em 15/03/2018 - 17:15h

dark777 escreveu:

#!/bin/sh 


Perigo: você diz “/bin/sh” mas usa recursos que não são suportados pelo sh original (por exemplo, a sintaxe “$( comando )” para redirecionar a saída de um comando como parte da instrução).

Possivelmente sua distribuição usa o Bash no lugar do tradicional Bourne Shell, mas seria bom se você se precavesse contra possíveis acidentes no dia em que seu script for executado numa máquina que não faça a mesma substituição (por exemplo: Debian e derivados, todos os BSDs, versões comerciais de UNIX etc.).

Você pode fazer isso de duas maneiras: chamando explicitamente o Bash na primeira linha (i.e. usar “#!/bin/bash”) ou evitar os recursos que o shell tradicional não suporta.

IFS='
'

for i in $(ls $1)


Novo problema aqui.

Supondo que $1 se refira a um diretório, você não sabe de antemão quantos arquivos haverá nesse diretório. Se for uma quantidade muito grande, você pode acabar violando limites do shell de tamanho máximo que um comando pode ter. E mesmo que alguns shells modernos tenham praticamente eliminado tais limites, essa expansão vai provocar consumo de memória para armazenar todos os eventuais argumentos, que pode, em diretórios muito, muito grandes, causar problemas para seu script ou mesmo para o sistema.

Mesmo que você não vislumbre trabalhar com diretórios tão grandes assim, isso não significa que seus scripts não devam ser feitos de modo seguro.

Outro potencial problema é que é teoricamente possível ter arquivos contendo quebras de linha como parte do nome. Embora a chance disso ocorrer seja baixíssima (trabalhando com UNIX desde 1993, eu mesmo nunca vi um arquivo desses, a não ser nos casos em que eu mesmo os criei, para testar), seu script pode, com pouco esforço, lidar com tais arquivos. Então, por que não o preparar para tanto?

A maneira de fazer é trocar a forma “for i in [lista de arquivos]”, que tem de fazer o shell expandir toda a lista de arquivos em memória, mesmo que só vá trabalhar com um arquivo de cada vez, por uma forma que entregue um arquivo de cada vez ao laço de repetição. Além disso, seria bom que essa entrega soubesse lidar com qualquer caráter válido como parte do nome do arquivo.

Eis um jeito de fazer, usando o Bash (lembre-se da observação feita acima sobre como garantir que o usuário vai realmente usar o Bash):

exec 3< <(find $1 -maxdepth 1 -type f -print0)
# Associa o descritor nº 3 à saída do comando find. Esse find, por sua vez,
# vai pesquisar no caminho indicado por $1, sem entrar em eventuais
# subdiretórios desse caminho (“-maxdepth 1”), mostrando apenas arquivos
# (“-type f”) e usando como delimitador do nome do arquivo um byte nulo,
# em vez de uma quebra de linha (“-print0”).
#
# A associação do descritor deve ser posteriormente desfeita (por exemplo,
# quando acabarem os dados) com o comando “exec 3<&-”.

while read -d $'\0' i <&3
# Tenta ler para a variável i (que, por sinal, é um nome ruim...), a partir do
# descritor nº 3 (“<&3”), o próximo valor de texto delimitado por um byte nulo
# (“-d $'\0'”). Se a leitura for bem sucedida, executa a próxima iteração do
# laço de repetição; caso contrário, termina o laço.


do
filtra=$(echo $i |grep ' ')
if [ $filtra ]; then


Eu sou adepto de evitar comandos externos ao shell sempre que possível, bem como de evitar variáveis desnecessárias.

As duas linhas de código acima podem ser trocadas por uma só, usando apenas recursos internos do Bash.

    if [[ "$i" == *\ * ]]; then 


Para acomodar arquivos que eventualmente contenham outros tipo de caracteres de espaçamento, como tabulações, quebras de linha ou de página.

    if [[ "$i" =~ [[:space:]] ]]; then 


Para ser ainda mais seguros, poderíamos pensar em outros tipos de caracteres problemáticos, como caracteres de controle.

    if [[ "$i" =~ [[:space:][:cntrl:]] ]]; then 


     corpo=$(echo $i | awk -F "." '{print $1}')
extensao=$(echo $i | awk -F "." '{print $2}')
under=$(echo $corpo | sed 's/^ //g;s/ - /_/g;s/ /_/g;')


De novo, seria melhor não depender de programas externos para essas operações.

        corpo=${i%.*}
extensao=${i##*.}
[[ "$corpo" =~ ^[[:space:]]+(.*) ]] && under="${BASH_REMATCH[1]}" || under="$corpo"
while [[ "$under" =~ (.*){[[:space:][:cntrl:]]| - }(.*) ]]; do
under="${BASH_REMATCH[1]}_${BASH_REMATCH[2]}"
done


        
n=0;
n=$[$n+1];


Essas duas linhas parecem ser redundantes, pois fazem com que o valor final de n seja igual a 1 em todas a iterações do laço de repetição.

Você deveria ter colocado o valor inicial de n apenas uma vez, antes do laço de repetição começar, para que, dentro do laço, ele receba apenas valores sucessivamente crescentes.

        
final=$(echo $under$n.$extensao | sed 's/ $//g;')
mv $i $final


Dá para melhorar isso que vai acima.

Se você quer que os números sejam precedidos por zeros (por exemplo: “001” em lugar de apenas “1”), você pode usar o comando interno printf.

Além disso, por segurança, você deveria colocar os nomes da variáveis entre aspas.

        final=$(printf "%s%02u.%s" "$under" $n "$extensao")
mv "$i" "$final"



if [ $? -ne 0 ]; then
echo -e "\e[37;1m$i \e[m<-\e[31;1m nothing done.!!\e[m"
else
echo -e "\e[36;1m\n\tFile\e[35;1m: $i\e[m$\e[31;1m\n\n\tRenamed\e[35;1m: \e[33;1m$final\e[m successfully\n\n"
fi
fi
done