quarta-feira, 21 de dezembro de 2011

Soma dos débitos do extrato do Banco do Brasil

  Eu sempre fiz o controle dos meus gastos e para ter a resposta do custo do mês, desenvolvi um script que soma todas as parcelas debitadas da minha conta corrente do banco do Brasil.
  Começou de uma forma bem simples. Um conjunto de entradas e saídas era sequênciado da seguinte forma:
  • o comando cat exibe todo o conteúdo
  • o comando cut mostrar do caracter 60 em diante
  • o grep exibe somente as linhas de débito (indicadas por um "D")
  • o awk exibe somente o primeiro campo da linha de débito
  • o comando sed substitui vírgula por ponto
  • o paste e suas opções transformam a listagem de coluna para linha e insere um sinal de mais (+) entre os números
  • o comando bc faz a soma
Observação: a necessidade de substituir a vírgula por ponto é devido ao bc requerer este símbolo para interpretar valores fracionários.

  Até Maio de 2007 e anterior a esta data, o comando era:

cat extrato_07_05.txt | cut -c 60- | grep D | awk '{printf("%s\n",$1)}' | sed 's/,/./g' | paste -s -d"+" | bc

  De Junho de 2007 até o presente, usa-se:

cat extrato_07_06.txt | cut -c 71- | grep D | awk '{printf("%s\n",$1)}' | sed 's/,/./g' | paste -s -d"+" | bc

  Estes comandos combinados funcionavam para valores até 999 reais. A partir dos valores contendo 4 dígitos, este é exibido com um ponto separador de milhar. Exemplo: 1.000,00   Como consequência, causa um erro no interpretador do bc. Para resolver o problema, apresento a solução abaixo bem como os comentários.

#!/bin/bash
# Variáveis mes e ano capturam a data
mes=`date +%m`
ano=`date +%Y`

# Exige o número do arquivo ao executar o comando
 if [ $# != 1 ]
   then
    echo "Argumento: nome_de_arquivo"
    exit 1
  fi

cat $1 | cut -c 71- | grep D | awk '{printf("%s\n",$1)}' | sed 's/,/./g' > extrato.txt
# Conta a quantidade de linhas ao ler o arquivo
total_linhas=`wc -l extrato.txt | cut -f1 -d" "`
# Apaga o arquivo
rm -f gasto_"$ano"_$mes.txt
# Loop para executar um conjunto de ações até o final do arquivo
for i in `seq $total_linhas`
  do
# Analisa cada linha e conta o número de pontos (separadores de milhar e da parte fracionária)
   um_ponto=`head -n $i extrato.txt | tail -n 1 | tr -cd "." | wc -c`
   if [ $um_ponto = 1 ]
    then
# Se for apenas 1 ponto, simplesmente exibe o valor
    head -n $i extrato.txt | tail -n 1
   fi

# Analisa cada linha e conta o número de pontos (separadores de milhar e da parte fracionária)
  dois_pontos=`head -n $i extrato.txt | tail -n 1 | tr -cd "." | wc -c`
   if [ $dois_pontos = 2 ]
    then
# Se forem 2 pontos, substitui o primeiro ponto por nada (ponto aparece somente para parte fracionária)
    echo `head -n $i extrato.txt | tail -n 1` | sed 's/\.//'
   fi
  done >> gasto_"$ano"_$mes.txt
paste -s -d"+" gasto_"$ano"_$mes.txt | bc

sábado, 29 de outubro de 2011

Horas trabalhadas usando MySQL

  Na primeira publicação deste assunto com o título Horas trabalhadas armazenadas no MySQL eu abordei sobre um script que registra as horas trabalhadas. Passado um tempo tive que fazer alguma alterações para adequar meu sistema ao modelo usado pela empresa.
  As modificações são:
  • a substituição das colunas dia, mês e ano por data que agrupa as três informações;
  • pergunta se é um dia útil. Se a resposta for negativa, a forma como a variável saldo é calculada muda para diferenciar a quantidade de horas extras.

  A seguir está a descrição da tabela de acordo com o comando do MySQL describe ponto;

id int(11) NO PRI NULL auto_increment
in1 time YES NULL
out1 time YES NULL
in2 time YES NULL
out2 time YES NULL
tempo time YES NULL
saldo time YES NULL
data varchar(11) YES NULL
comment text YES NULL

  O script encontra-se abaixo bem como seus comentários para facilitar o entedimento das instruções.

#!/bin/bash

# Entrada dos horários
read -p "Entrada manhã: " in1
read -p "Saída almoço: " out1
read -p "Entrada tarde: " in2
read -p "Saída tarde: " out2

read -p "Data de hoje? [Y/n] " resp
# Entende que Y, y, S, s ou Enter signifiquem uma resposta a data de hoje
if [ "$resp" = Y -o "$resp" = y -o "$resp" = S -o "$resp" = s -o ! -n "$resp" ]
  then
   dia=`date +%d`
   mes=`date +%m`
   ano=`date +%Y`
   data=$dia/$mes/$ano
else
  read -p "dia " dia
  read -p "mes " mes
  read -p "ano " ano
  data=$dia/$mes/$ano
fi

# Subtrai o horário da manhã
manhaSQL=`mysql -uroot -psenha << SQL
SELECT SUBTIME('$out1','$in1');
QUIT
SQL`

# Filtra a resposta anterior ficando apenas um valor do tipo HH:MM:SS
manha=`echo $manhaSQL | awk '{printf "%s\n",$2}'`

# Subtrai o horário da tarde
tardeSQL=`mysql -uroot -psenha << SQL
SELECT SUBTIME('$out2','$in2');
QUIT
SQL`

# Filtra a resposta anterior ficando apenas um valor do tipo HH:MM:SS
tarde=`echo $tardeSQL | awk '{printf "%s\n",$2}'`

# Soma o horário da manhã e da tarde
tempoSQL=`mysql -uroot -psenha << SQL
SELECT ADDTIME('$manha','$tarde');
QUIT
SQL`

# Filtra a resposta anterior ficando apenas um valor do tipo HH:MM:SS
# Tempo total do dia (manhã + tarde)
tempo=`echo $tempoSQL | awk '{printf "%s\n",$2}'`

# Horas trabalhadas menos 9h para calcular o saldo de horas
tempo_add=`mysql -uroot -psenha << SQL
SELECT SUBTIME('$tempo','09:00:00');
QUIT
SQL`

read -p "Dia útil? [Y/n] " dia_util
if [ "$dia_util" = Y -o "$resp" = y -o "$resp" = S -o "$resp" = s -o ! -n "$dia_util" ]
  then # saldo de horas trabalhadas para dia útil
   saldo_horas=`echo $tempo_add | awk '{printf "%s\n",$2}'`
  else # saldo de horas trabalhadas para sábados, domingo e feriados
   saldo_horas="$tempo"
fi

read -p "Comentário? " comment

echo "$in1" "$out1" "$in2" "$out2" "$tempo" "$saldo_horas" "$data" "$comment"

cmd=`/usr/bin/mysql -uroot -psenha << SQL
   use imf
   insert into ponto (in1, out1, in2, out2, tempo, saldo, data, comment) values
    ("$in1", "$out1", "$in2", "$out2", "$tempo", "$saldo_horas", "$data", "$comment");
  quit
  SQL`

  Através do comando

select * from ponto where id > numero;

sendo numero o id que corresponde a uma data que procuro, o MySQL devolve a listagem de um determinado intervalo que através da ferramenta txt2tags crio as células que são facilmente portáveis para o Excel com um simples CTRL + C e CTRL + V.

sábado, 17 de setembro de 2011

Criando páginas rápidas com fotos

  O propósito deste script é gerar uma página para cada foto. Cada página tem dois links sendo o anterior e a próxima (exceção para a primeira e a última). Em outras palavras, aparecerá um número em ordem crescente(iniciado em 1) para cada foto, a foto e os links entre as páginas adjacentes.
  Esta necessidade surgiu para eu mostrar para os meus pais que tem dificuldade de lidar com o computador. Então juntei alguns conhecimentos para facilitar para eles. Recomendo redimensionar as fotos para não demorar no carregamento (veja Convertendo as fotos de um diretório específico ).
  O script exige que as fotos estejam numeradas sequencialmente. Para automatizar esta etapa, junte com o script que está em Renomear de maiúscula para minúscula e com sequência numérica . Copie e execute o segundo script desta página.
  As últimas instruções do script são 4 ajustes:
  • Trocar o link de número 010 por 10
  • Trocar o link de número 9 por 09
  • Eliminar da primeira página o link para página anterior
  • Eliminar da última página o link para a página seguinte
  Para entender como os arquivos TXT criaram os arquivos HTML, recomendo a leitura Marcas do Txt2tags do genial Aurélio Marinho Jargas.
  Depois de executar o script abaixo, transfira para o seu servidor web as fotos e os arquivos HTML. Uma alternativa que requer um pouco mais de conhecimento é configurar o Apache e o seu roteador para fazer um port forwarding. Assim, meus pais acessavam as fotos diretamente do meu computador.

#/bin/bash

# v1.1 September, 11th, 2010

total=`ls *.jpg | wc -l`
for i in `seq 9`
  do
   let j=$i-1
   let k=$i+1
echo "


=0$i/$total=

[0$i.jpg]


[anterior 0$j.html]


[proxima 0$k.html]
" > 0$i.txt
  done

for i in `seq 10 1 $total`
  do
   let j=$i-1
   let k=$i+1
echo "


=$i/$total=

[$i.jpg]


[anterior $j.html]

[proxima $k.html]
" > $i.txt
  done


# txt2html

for i in $total
  do
   txt2tags -t html *.txt
  done


sed 's/010/10/' 09.html > 09temp
mv -v 09temp 09.html

sed 's/9.html/09.html/' 10.html > 10temp
mv -v 10temp 10.html

sed '/anterior/d' 01.html > primeiroTemp
mv -v primeiroTemp 01.html

sed '/proxima/d' $total.html > ultimoTemp
mv -v ultimoTemp "$total".html

sábado, 3 de setembro de 2011

Horas trabalhadas armazenadas no MySQL

  Esta publicação tem o propósito de armazenar as suas horas trabalhadas. Nada do (argh!) excel. Este script armazena as informações e executa os cálculos.
  É preciso um certo conhecimento do banco de dados MySQL. Qualquer dúvida, consulte Introdução ao banco de dados MySQL.
  Primeiro passo é criar a database:

create database industria;

  Em seguida, cria-se a tabela com as colunas:

create table horarios (id int AUTO_INCREMENT, in1 time, out1 time, in2 time, out2 time, tempo tempo, saldo tempo, dia int(20), mes int(2), ano int(2), comment TEXT, PRIMARY KEY (id));

  Explicando cada coluna:

Coluna Tipo Explicação
id PRIMARY KEY número distinto
in1 time entrada de manhã
out1 time saída de manhã
in2 time entrada à tarde
out2 time saída à tarde
tempo time horas trabalhadas no dia somando manhã e tarde
saldo time saldo de horas
dia int(20) dia trabalhado
mes int(2) mês trabalhado
ano int(2) ano trabalhado
comment TEXT espaço para anotações do tipo "consulta médica" etc

  O banco de dados está pronto.
  Justificando por separar dia, mês e ano. Uma situação comum é fazer o levamento das horas trabalhadas de um determinado mês. Um select do tipo:

select * from horarios where mes=9 and ano=2011;

devolve todas as informações sobre o mês de setembro de 2011.
  A seguir disponibilizo o script que lê as informações introduzidas pelo usuário, executa somas e subtrações de horários e armazena no banco de dados.

#!/bin/bash

# Entrada dos horários
read -p "Entrada manhã: " in1
read -p "Saída almoço: " out1
read -p "Entrada tarde: " in2
read -p "Saída tarde: " out2

read -p "Data de hoje? [Y/n] " resp
# Entende que Y, y, S, s ou Enter signifiquem uma resposta a data de hoje
if [ "$resp" = Y -o "$resp" = y -o "$resp" = S -o "$resp" = s -o ! -n "$resp" ]
  then
   dia=`date +%d`
   mes=`date +%m`
   ano=`date +%Y`
else
  read -p "dia " dia
  read -p "mes " mes
  read -p "ano " ano
fi

read -p "Comentário? " comment

# Subtrai o horário da manhã
manhaSQL=`mysql -uroot -psenha << SQL
SELECT SUBTIME('$out1','$in1');
QUIT
SQL`

# Filtra a resposta anterior ficando apenas um valor do tipo HH:MM:SS
manha=`echo $manhaSQL | awk '{printf "%s\n",$2}'`

# Subtrai o horário da tarde
tardeSQL=`mysql -uroot -psenha << SQL
SELECT SUBTIME('$out2','$in2');
QUIT
SQL`

# Filtra a resposta anterior ficando apenas um valor do tipo HH:MM:SS
tarde=`echo $tardeSQL | awk '{printf "%s\n",$2}'`


# Soma o horário da manhã e da tarde
tempoSQL=`mysql -uroot -psenha << SQL
SELECT ADDTIME('$manha','$tarde');
QUIT
SQL`

# Filtra a resposta anterior ficando apenas um valor do tipo HH:MM:SS
# Tempo total do dia (manhã + tarde)
tempo=`echo $tempoSQL | awk '{printf "%s\n",$2}'`

# Horas trabalhadas menos 9h para calcular o saldo de horas
tempo_add=`mysql -uroot -psenha << SQL
SELECT SUBTIME('$tempo','09:00:00');
QUIT
SQL`

# saldo de horas trabalhadas
saldo_horas=`echo $tempo_add | awk '{printf "%s\n",$2}'`

# insere no banco de dados os valores armazenados nas variaveis
cmd=`/usr/bin/mysql -uroot -psenha << SQL
  use industria
  insert into horarios (in1, out1, in2, out2, tempo, saldo, dia, mes, ano, comment) values
    ("$in1", "$out1", "$in2", "$out2", "$tempo", "$saldo_horas", "$dia", "$mes", "$ano", "$comment");
  quit
  SQL`

sábado, 27 de agosto de 2011

Introdução ao banco de dados MySQL

  Vamos ao primeiro contato com o banco de dados MySQL. Depois desta introdução sobre as funcionalidades básicas do banco de dados, vamos unir com Shell Script nas futuras publicações.
  Para saber se o banco de dados já está instalado, digite:

dpkg -l mysql*

  Eu estou usando a versão 5.1.49-1ubuntu8.1
  Caso não esteja instalado, digite:

apt-get install mysql-server

  Para se autenticar, utilize o comando:

mysql -u user -p password

  Substitua o nome do user e a senha password pela combinação que autentica no sistema.
  Antes de sair digitando comando, entenda conceitos essenciais:

  • database: conjunto de tabelas.
  • table: depois de determinada a database a ser usada, é a vez de criar a tabela contendo os nomes das variáveis dispostas em colunas. Cada variável tem um tipo: varchar, int, time etc. Mais detalhes veja Data Types.
  Para os comandos a seguir, mostro anotações que fiz sobre meu estudo sobre C++. A medida que via informações da mais alta importância, fui armazenando num banco de dados.

  Para listar as databases:

show databases;

  Para criar uma database:

create database deitel;

  Para utilizar a database:

use deitel;

  Para listar as tabelas existentes na database, digite:

show tables;

  Para criar a tabela com 3 variáves sendo página, seção e texto:

create table livro ( pagina INT, secao INT, texto TEXT);

  Se quiser que a cada linha o contador incremente o número do registro, observe o tipo AUTO_INCREMENT e PRIMARY KEY que são usadas para a variável id.

create table livro ( id int AUTO_INCREMENT, pagina varchar(5), secao varchar(8), texto TEXT, PRIMARY KEY (id));

  Para o caso que um valor não poder aceito como vazio, digite o nome da variável, o tipo e a palavra NOT NULL.
  Exemplo:

create table livro ( id int AUTO_INCREMENT, pagina varchar(5) NOT NULL, secao varchar(8), texto TEXT, PRIMARY KEY (id));

  O comando a seguir descreve o nome, o tipo, se é permitido ou não preencher um valor e informações adicionais.

describe livro;

  Para inserir valores na tabela, observe:

insert into livro (pagina, secao, texto) values ('78', '3.9', 'A série Dive-Into mostra como compilar múltiplos arquivos.');

  Para alterar um dado, a sintaxe é:
update nome_da_tabela set Nome_da_variável='NOVO VALOR' where id='numero_unico';
  Exemplificando:

update livro set secao='4.6' where id=4;

  Caso queria descartar uma tabela, o comando é:

drop table nome_da_tabela;

  Exemplificando:

drop table livro;

  Com estes comandos já é possível criar databases e tabelas que atendam necessidades elementares. Na próxima publicação utilizaremos o Shell Script para manipular o MySQL.

quinta-feira, 25 de agosto de 2011

Configuração da minha rede de computadores

  Após várias tentativas finalmente cheguei na configuração de rede que atende exatamente o que preciso.
  Listando os elementos da rede:
  • modem ADSL
  • hub
  • roteador wireless
  • 2 computadores com windows
  • 1 computador com Linux
  • 1 impressora
  O modem ADSL deve ser o servidor DHCP para que os computadores entendam quem é o gateway da rede. Se puder o roteador wireless como servidor DHCP, não comunicação com a internet porque este dispositivo não tem interface com as redes externas.
  A função do hub é bem conhecida: é o distribuidor de pontos.
  O roteador wireless tem um recurso interessante que é um servidor de impressão. Basta conectar a interface USB da impressora com o roteador e instalar os drivers que a comunicação acontece sem transtornos. Desta forma, qualquer computador envia para fila de impressão sem depender de outro computador ligado.
  As duas estações windows recebem um IP que é negociado com servidor DHCP. Um ponto interessante chama-se "Expires In" que diz por quanto tempo o servidor DHCP reserva um IP para aquela máquina. Se o tempo expirar, outro computador pode receber o IP que estava com outra máquina.
  Apenas uma máquina tem um IP fixo e fora da faixa do servidor DHCP por razões óbvias: não conflitar com um IP que tem um intervalo reservado. A utilidade de um IP fixo é poder direcionar serviços. Lembrando que para estabelecer uma comunicação é preciso um IP e uma porta. Desta forma, quando uma solicitação vem de fora da minha rede, o roteador analisa qual a porta procurada e se este número estiver listado na configuração, faz o redirecionamento para meu computador. Perfeito quando se esquece um arquivo em casa e a conexão remota economiza tempo!
  Enfim, apresento o diagrama. A figura foi elaborada com o software dia e através do export foi convertida para jpg.

terça-feira, 16 de agosto de 2011

Análise dos números da Quina

  Não há dúvida que programação e matemática combinam para fazer análises das mais variadas formas.
  Este script executa as seguintes etapas:
  • baixa um arquivo compactado contendo todos os jogos realizados pela quina
  • apaga os arquivos textos criados para evitar que fique poluindo seu diretório
  • remove as tags html para que fiquem somente os cinco números sorteados
  • organiza os números de colunas para linhas
  • ordena em ordem crescente os números sorteados
  • calcula a soma da primeira coluna a quinta coluna individualmente
  • a soma de cada coluna é divida pelo número de jogos para obter a média aritmética
  • exibe os 5 números sorteados com maior frequência

  Copie e execute! Boa análise!
  E se você for premiado com ajuda deste script, aceito doações! :)

#!/bin/bash

# by Murilo Fujita
# v1.1 Exibe os 5 numeros sorteados com maior frequencia
# v1.0 Extrai os numeros sorteados, ordena em ordem crescente, soma cada coluna e divide pela quantidade de jogo

#read -p "Entre com jogo " inicio

wget http://www1.caixa.gov.br/loterias/_arquivos/loterias/D_quina.zip
unzip D_quina.zip

rm -f D_quina.zip
rm -f T7.GIF
rm -f quina1.txt
rm -f quina2.txt
rm -f quina3.txt
rm -f quina4.txt
rm -f quina5.txt
rm -f quina6.txt
rm -f quina7.txt
echo Limpando HTML

sed '/html/d' D_QUINA.HTM | sed '/table/d' | sed '/body/d' | sed '/tr/d' | sed '/,/d' | sed '/SIM/d' | sed '/N/d' | sed 's/<td>//' | sed 's/<\/td>//' > quina1.txt
linhas1=`wc -l quina1.txt | awk '{printf "%s\n",$1}'`

#rm -f D_QUINA.HTM

echo Extraindo numeros sorteados

seq=7
while [ $seq -le $linhas1 ]
  do
   head -n $seq quina1.txt | tail -n 5
   let seq=$seq+10
  done >> quina2.txt

echo Formatando numeros em colunas

linha2=`wc -l quina2.txt | awk '{printf "%s\n",$1}'`
seq2=5
while [ $seq2 -le $linha2 ]
  do
   head -n $seq2 quina2.txt | tail -n 5 | paste -s -d" "
   let seq2=$seq2+5
  done >> quina3.txt

tr -d '\r' < quina3.txt > quina4.txt


echo Organizando os números sorteados em ordem crescente

total_jogos=`sed '/^$/d' quina4.txt | wc -l`
mv -v D_QUINA.HTM D_QUINA$total_jogos.HTM
for i in `seq $inicio 1 $total_jogos`
  do
   head -n $i quina4.txt | tail -n 1 | tr " " "\n" | sort -n | paste -s -d" " >> quina5.txt
  done

s1=`cut -f1 -d" " quina5.txt | paste -s -d"+" | bc`
s2=`cut -f2 -d" " quina5.txt | paste -s -d"+" | bc`
s3=`cut -f3 -d" " quina5.txt | paste -s -d"+" | bc`
s4=`cut -f4 -d" " quina5.txt | paste -s -d"+" | bc`
s5=`cut -f5 -d" " quina5.txt | paste -s -d"+" | bc`
echo Soma de todos os numeros
echo $s1 $s2 $s3 $s4 $s5

#let jogos_processados=$total_jogos-$inicio

# linhas5=`wc -l /home/murilo/programas/quina5.txt | cut -f1 -d" "`
media1=`echo $s1/$total_jogos | bc` #jogos_processados total_jogos
media2=`echo $s2/$total_jogos | bc`
media3=`echo $s3/$total_jogos | bc`
media4=`echo $s4/$total_jogos | bc`
media5=`echo $s5/$total_jogos | bc`
echo Media dos numeros sorteados nos $total_jogos jogos realizados
echo $media1 $media2 $media3 $media4 $media5

printf "\n"
echo Exibindo a frequencia do numero sorteado
sleep .5
  for i in `seq 9`;
   do
    printf "0$i `grep 0$i quina2.txt | wc -l` "
   done
  printf "10 `grep 10 quina2.txt | wc -l` "
  printf "\n"

inicio=11
fim=20
while [ $inicio -le 80 ]
do
  for i in `seq $inicio 1 $fim`;
   do
    printf "$i `grep $i quina2.txt | wc -l` "
   done
  printf "\n"
  let inicio=$inicio+10
  let fim=$fim+10
done


for i in `seq 9`; do printf "0$i `grep 0$i quina2.txt | wc -l`\n" ; done >> quina6.txt
for i in `seq 10 1 80`; do printf "$i `grep $i quina2.txt | wc -l`\n" ; done >> quina6.txt
awk '{printf "%s %3s\n",$2, $1}' quina6.txt | sort -n | tail -n 5 > quina7.txt

printf "\n"
echo Os numeros mais sorteados sao

for i in `seq 5`
  do
   head -n $i quina7.txt | tail -n 1 | awk '{printf "%s %3s\n",$2, $1}'
  done

   Caso queria baixar diretamente o código, salve este link.

domingo, 14 de agosto de 2011

Espiral de Arquimedes

  Depois de ver a Espiral de Arquimedes , quis entender a matemática que gera a figura. Até chegar no resultado, usei C++, Shell Script e gnuplot.
  Uma vez lido sobre o assunto no link, é preciso entender como converter de coordenadas cartesianas para polares. O assunto foi estendido para realizar uma figura 3D.
  A parte que utiliza C++ é composta de três arquivos: uma classe, a definição da classe e o programa-cliente (main).

A classe


  Apenas uma função que não retorna nada (void) com o nome de Polar e não recebe nenhum parâmetro.

cat espiral.h

#ifndef ESPIRAL_H
#define ESPIRAL_H

class espiral {
public:
  void Polar();
private:

};
#endif /* ESPIRAL_H */

Definição da classe


  Os includes chamam a biblioteca matemática cmath , iostream para imprimir e mudar de linha (cout e endl) e a biblioteca criada espiral.h .
  void espiral::Polar(). É necessário a palavra espiral e duas vezes :: para que o compilador saiba em qual classe foi feita sua declaração.
  Na função há a declaração da constante pi e algumas variáveis. O laço for gera a quantidade de pontos desejada e foi decidido 10 voltas (3600 pontos). Traduzindo o que x e y armazenam, é


x = raio * cos θ
y = raio * sen θ


  É preciso converter de radianos para graus!
  A variável z é incrementada de 0.001 em 0.001.
  O cout << gera a saída para as variáveis.

cat espiral.cpp

#include< cmath >
#include< iostream >
using std::cout;
using std::endl;
#include "espiral.h"

int espiral::Polar()
{
  const double pi=3.141592;
  const int pontos=3600;
  double x[pontos],y[pontos];
  double z, r=1;

  z=0;
  for (int teta=0; teta < pontos; teta++)
  {
    x[teta]=static_cast(r*cos(teta*pi/180));
    y[teta]=static_cast(r*sin(teta*pi/180));
    z+=0.001;
    r+=.1;

    cout << x[teta] << " " << y[teta] << " " << z << endl;
  }

main


  O programa-cliente que ao ser executado é responsável por chamar os métodos em uma determinada ordem.
  espiral é a classe e myespiral é o objeto criado. O software só pode manipular o objeto e por isso cada classe tem seu objeto.
  Assim, o que é visto em seguida é o objeto myespiral chamando o método Polar.

cat main.cpp

#include <cstdlib>
#include "espiral.h"
using namespace std;
int main(int argc, char** argv) {
  espiral myespiral;
  myespiral.Polar();
  return 0;
}

  Agora que os arquivos estão prontos, uma instrução precisa ser passada ao compilador para saber como juntar os códigos-fontes e gerar o código-objeto (a linguagem de máquina). Assim:

$ g++ espiral.cpp main.cpp -o arquimedes.out -ansi

  Ao executar o binário, redirecione para um arquivo-texto:

$ ./arquimedes.out > plot.txt

  A participação do shell script foi a de apontar valores extremos dos eixos X e Y.

$ cat xy.sh

#!/bin/bash
menorX=`cat plot.txt | awk '{printf "%s\n",$1}' | sort -n | head -n 1`
maiorX=`cat plot.txt | awk '{printf "%s\n",$1}' | sort -nr | head -n 1`
menorY=`cat plot.txt | awk '{printf "%s\n",$2}' | sort -n | head -n 1`
maiorY=`cat plot.txt | awk '{printf "%s\n",$2}' | sort -nr | head -n 1`
echo ">X" $menorX
echo "<X" $maiorX
echo ">Y" $maiorY
echo "<Y" $menorY

  Executando o script xy.sh para a massa de dados plot.txt , o resultado foi:
>X -343.048
<X 361
>Y 334.049
<Y -352.046

  Este resultado servirá para entrar com os limites do gráfico (instruções xrange e yrange).
  Finalmente, para gerar a figura, chame o gnuplot:

  $ gnuplot
   G N U P L O T
   Version 4.4 patchlevel 0
   last modified March 2010
   System: Linux 2.6.35-30-generic
  
   Copyright (C) 1986-1993, 1998, 2004, 2007-2010
   Thomas Williams, Colin Kelley and many others
  
   gnuplot home:     http://www.gnuplot.info
   faq, bugs, etc:   type "help seeking-assistance"
   immediate help:   type "help"
   plot window:      hit 'h'
  
  Terminal type set to 'wxt'
  gnuplot> 

Entre com as seguintes instruções no prompt do gnuplot:
  gnuplot> set xrange[-400:400]
  gnuplot> set yrange[-400:400]
  gnuplot> set ticslevel 0
  gnuplot> splot "plot.txt" u 1:2:3 with lines

  Caso queira apenas um figura 2D, remova a variável z da linha cout << x[teta] << " " << y[teta] << " " << z << endl; para que imprima x e y. Os passos seguintes são os mesmo: direcionar a saída para plot.txt e com um comando no gnuplot, o gráfico é gerado:

gnuplot> plot [-400:400][-400:400] "plot.txt" with lines
  Os gráficos feitos pelo gnuplot permitem ser rotacionados. Use o ponteiro do mouse para visualizar milhares de ângulos!
  O resultado pode ser visto na figura abaixo.

quinta-feira, 11 de agosto de 2011

Renomeando diretórios e arquivos recursivamente

  Depois de fazer um certo curso, fui ver a documentação que recebi e os nomes dos arquivos estavam em letras maiúsculas e espaços. Resolvi organizar de forma que estejam com letras minúsculas e sem espaço.
  Primeiro tratei dos nomes dos diretórios e subdiretórios. Observe que o comando find find -type d encontra os diretórios a partir de onde foi dado o comando.
Nota: o comando ls -l mostra os detalhes. Se o primeiro caracter é d, é um diretório. Se for um - é um arquivo comum.
  Tudo que é encontrado é redirecionado para o arquivo /tmp/files_diretorios.txt através do caracter >.
  Em seguida, a variável total_diretorios armazena a quantidade de diretórios. Essa informação é passada para o laço for que avança linha por linha através da combinação de head e tail. A variável Maiuscula guarda o nome original do arquivo buscando dentro do arquivo /tmp/files_diretorios.txt enquanto que minuscula armazena o mesmo nome, porém trocando de maiúscula para minúscula através do comando tr. Uma vez obtido o nome original e o nome personalizado, o comando mv renomeia o que está na primeira variável para a segunda. Extremamente importante as aspas porque os nomes dos arquivos geralmente possuem espaços.   Para remover o espaço, a saída do comando echo é a entrada do comando sed que interpreta 's/ //g' para substituir espaços por nada de forma global (observe a letra g).
  Terminado o tratamento para os diretórios, é a vez de levantar os arquivos comuns. O comando find -type f > /tmp/files_arquivos.txt busca todos arquivos e armazena no arquivo /tmp/files_arquivos.txt (reforçando, o levantamento é feito a partir de onde foi dado o comando).

#!/bin/bash

find -type d > /tmp/files_diretorios.txt
total_diretorios=`wc -l /tmp/files_diretorios.txt | cut -f1 -d' '`

for i in `seq $total_diretorios`
  do
   Maiuscula=`head -n $i /tmp/files_diretorios.txt | tail -n 1`
   minuscula=`head -n $i /tmp/files_diretorios.txt | tail -n 1 | tr A-Z a-z`
   mv -v "$Maiuscula" "$minuscula"
   sem_espaco=`echo $minuscula | sed 's/ //g'`
   mv -v "$minuscula" "$sem_espaco"
  done

find -type f > /tmp/files_arquivos.txt
total_arquivos=`wc -l /tmp/files_arquivos.txt | cut -f1 -d' '`

for i in `seq $total_arquivos`
  do
   Maiuscula=`head -n $i /tmp/files_arquivos.txt | tail -n 1`
   minuscula=`head -n $i /tmp/files_arquivos.txt | tail -n 1 | tr A-Z a-z`
   mv -v "$Maiuscula" "$minuscula"
   sem_espaco=`echo $minuscula | sed 's/ //g'`
   mv -v "$minuscula" "$sem_espaco"
  done

  Para um demonstração, digitei o comando abaixo dentro do diretório /tmp e veja a quantidade de diretórios e arquivos para organizar:

$ wc -l file*
377 files_arquivos.txt
56 files_diretorios.txt
433 total
  Para saber quanto tempo levou a execução do script, usa-se o comando time seguido no nome do seu script. Eu dei o nome de organiza.sh.

time ./organiza.sh

  E a resposta foi:

0m6.396s

  Apenas 6 segundos e 396 milésimos de segundo!

  Aproveitando a oportunidade, gostaria de introduzir o uso de funções. O conceito é simples. Se em outra parte do código realiza a mesma tarefa, este bloco de instruções pode ser atribuído um nome e delimitado por chaves ({}). A função deve ser codificada antes da função chamada. O código abaixo mostra uma versão enxuta usando funções. Uma diferença é que o armazenamento das informações vão para o arquivo /tmp/files.txt em vez de separar em dois arquivos. Não há problema porque primeiro trata de todos os diretórios e só então começa o processo de alterar os nomes de arquivos.

#!/bin/bash

tratamento()
{
   Maiuscula=`head -n $i /tmp/files.txt | tail -n 1`
   minuscula=`head -n $i /tmp/files.txt | tail -n 1 | tr A-Z a-z`
   mv -v "$Maiuscula" "$minuscula"
   sem_espaco=`echo $minuscula | sed 's/ //g'`
   mv -v "$minuscula" "$sem_espaco"
}

find -type d > /tmp/files.txt
total_diretorios=`wc -l /tmp/files.txt | cut -f1 -d' '`

for i in `seq $total_diretorios`
  do
   tratamento
  done

find -type f > /tmp/files.txt
total_arquivos=`wc -l /tmp/files.txt | cut -f1 -d' '`

for i in `seq $total_arquivos`
  do
   tratamento
  done

  Seja visualizar no modo texto ou no modo gráfico (usando nautilus, por exemplo), eu gosto que os arquivos sigam um padrão. Por isso, nada melhor do que um pouco de script para fazer um serviço trabalhoso em poucos segundos!
  Foi uma boa oportunidade para mostrar funções que é comum às linguagens de programação. Entendendo o conceito, é fortemente recomendado o seu uso, pois garante que as tarefas serão executadas todas da mesma forma.

quarta-feira, 10 de agosto de 2011

Automatização de download do servidor FTP

  Uma das rotinas em uma empresa que trabalhei era conferir os dados de arquivos-texto e fazer uma contagem da produção. Então por que não automatizar já que é uma rotina?
  Este script conecta em um servidor FTP e realiza algumas instruções. Primeiro, o comando ftp -ivnp ip conecta ao servidor FTP (substitua ip pelo endereço ip). O símbolo << (here-document) diz qual é a palavra que ao encontrar novamente, encerrará as atividades. A linha seguinte inicia com user e é obrigatória. As duas palavras seguintes devem ser o nome de usuário e senha para efetuar a autenticação.
  Em seguida o comando cd acessa diretório1 e o mget faz download de múltiplos arquivos. Caso queria apenas um arquivo, use apenas get. Se for para entrar em outro diretório, use cd ../ para subir um nível e entrar no diretorio2. Por fim, ao encontrar fimftp, o script finaliza suas ações.
  Uma vez que os arquivos foram trazidos, faça o tratamento que for necessário: ter uma cópia em determinado diretório, fazer uma contagem com as informações dentro do arquivo etc.

#!/bin/bash


ftp -ivnp ip << fimftp
user usuario senha

cd diretorio1
mget arquivo1 arquivo2
cd ../diretorio2
mget outro_arquivo
fimftp



  Este é excelente exemplo para mostrar a utilidade do Shell Script. Tudo que for repetitivo pode ser automatizado. Cito como vantagens a garantia que a tarefa não será esquecida (salvo se a conexão cair) e o ganho de tempo. O crontab pode ser usado para disparar o script de acordo com a sua necessidade.

terça-feira, 9 de agosto de 2011

Backup seletivo

  Um dos serviços que funciona na minha máquina é o backup. Através deste script é feita uma compactação dos arquivos importantes combinado com o crontab, responsável por agendar certas tarefas de acordo com a sua programação.
  O primeiro comando, o cp copia meus favoritos para dentro do diretório text. Foi decidido que o nome do arquivo contém a data do dia do backup. Como não é incremental, posso recuperar arquivo com até 30 dias. Os nomes dos arquivos são backup_01.tar.gz, backup_02.tar.gz e assim por diante.
  Abaixo do comando tar estão os diretório e nomes de arquivos (indicados pela extensão ou mesmo por "*") que devem ser compactados. É importante usar o backslash (\) no final de cada linha para que o tar entenda que a instrução não acabou na primeira linha.
  Por fim, é feita uma verificação se o HD externo está montado no sistema operacional. O comando df serve para listar partições e dispositivos montados. Caso a resposta do if seja igual a 0 (zero), ou seja, verdadeiro, o cp copia para um diretório específico do HD externo. Caso negativo, responde que não está montado.
  Recomendo uma lida na man page do comando date para entender como obter determinados valores como mes, ano, hora, minuto entre muitas outras. Talvez criar 30 arquivos seja incômodo demais dependendo do volume que cada compactação ocupe. Então pode usar, por exemplo, um para cada dia da semana gerando apenas 7 arquivos.

#!/bin/bash

# copy my bookmarks from firefox to text directory
cp -v `ls -1tr ~/.mozilla/firefox/s9fan4kw.default/bookmarkbackups/*.json | tail -n 1` ~/text/bookmark.html

data=`date +%d`

tar cvfz /dados/backup/backup_$data.tar.gz \
~/documents/geocities/*.html \
~/documents/geocities/*.txt \
~/programas/* \
~/text/* \
~/documents/*.ldif \
~/documents/CV*


df -h /media/FUJITA250/
if [ `echo $?` = 0 ]
  then
   cp -v /dados/backup/backup_$data.tar.gz /media/FUJITA250/backup/
  else
   echo not mounted
fi

  Não deixe para o seu backup para amanhã. Saiba automatizá-lo para evitar momentos desagradáveis depois da perda.

segunda-feira, 8 de agosto de 2011

Sequência cronológica para jpg e mpg


   Para o mesmo caso de juntar fotos e vídeos de uma mesma viagem, é preciso colocar ordem nas suas recordações. Resumindo em 3 etapas o que este script faz, temos:
  • renomear de maiúscula para minúscula
  • mostrar a data original para cada foto e vídeo através do exiftool
  • renomear usando 2 dígitos para numerar (01.jpg, 02.jpg, ..., 10.mpg, ..., 99.jpg)
Os arquivos THM que acompanham os vídeos devem estar juntos, pois ao iniciar a gravação de vídeo, é registrado no THM a data do vídeo.    Os três primeiros for e a utilização das variáveis ano, mes, dia, hora, min, seg já foram comentados em Numerando arquivos de forma cronológica .    A variável total mais uma vez se encarrega de obter a quantidade de arquivos a minupular.    Ambos os laços for fazem o mesmo serviço, apenas para renomear os arquivos com um ou dois dígitos. Dentro do loop é verificado se o arquivo tem extensão JPG ou THM. De acordo com o arquivo fotos.txt, o if> seleciona entre as duas opções qual deve ser renomeado.

#/bin/bash

for M in *.JPG
  do
   m=$(echo $M | tr A-Z a-z)
   mv -v $M $m
  done

for M in *.THM
  do
   m=$(echo $M | tr A-Z a-z)
   mv -v $M $m
  done

for M in *.MPG
  do
   m=$(echo $M | tr A-Z a-z)
   mv -v $M $m
  done


ls -1 *.jpg *.thm | {
  while read arq; do
  ano=`exiftool "$arq" | grep Original | sed 's/://g' | sed 's/ //g' | cut -c 18-21`
  mes=`exiftool "$arq" | grep Original | sed 's/://g' | sed 's/ //g' | cut -c 22-23`
  dia=`exiftool "$arq" | grep Original | sed 's/://g' | sed 's/ //g' | cut -c 24-25`
  hora=`exiftool "$arq" | grep Original | sed 's/://g' | sed 's/ //g' | cut -c 26-27`
  min=`exiftool "$arq" | grep Original | sed 's/://g' | sed 's/ //g' | cut -c 28-29`
  seg=`exiftool "$arq" | grep Original | sed 's/://g' | sed 's/ //g' | cut -c 30-31`
  echo "$arq" $ano$mes$dia$hora$min$seg
  done
} | tee -a fotos.txt

cat fotos.txt | awk '{printf "%s %4s\n",$2,$1}' | sort -n > fotos2.txt

total=`ls *.jpg *.thm | wc -l`
echo *********************
echo Handling $total files
echo *********************
sleep 400

for i in `seq 9`
  do
  arq=`head -n $i fotos2.txt | tail -n 1 | cut -c 25-`
  if [ "$arq" = jpg ]
   then
    foto=`head -n $i fotos2.txt | tail -n 1 | cut -c 16-23`
    mv -v "$foto".jpg "0$i.jpg"
  fi
  if [ "$arq" = thm ]
   then
    video=`head -n $i fotos2.txt | tail -n 1 | cut -c 16-23`
    mv -v "$video".mpg "0$i.mpg"
  fi
  done

for i in `seq 10 1 $total`
  do
   arq=`head -n $i fotos2.txt | tail -n 1 | cut -c 25-`
   if [ "$arq" = jpg ]
    then
     foto=`head -n $i fotos2.txt | tail -n 1 | cut -c 16-23`
     mv -v "$foto".jpg "$i.jpg"
   fi
   if [ "$arq" = thm ]
    then
     video=`head -n $i fotos2.txt | tail -n 1 | cut -c 16-23`
     mv -v "$video".mpg "$i.mpg"
   fi
  done

   Script indicado para quem quer organizar rigorosamente a sequência dos acontecimentos tanto em fotos como em vídeos.    Adicionalmente, esta é uma ideia para mostrar o poder do BASH para organizar de acordo com os seus critérios.

sexta-feira, 5 de agosto de 2011

Renomeando arquivos para o padrão Unix


Muitas vezes recebo arquivos que vem com espaços e parenteses e não é muito conveniente tratá-los no shell. Então eu prefiro eliminar esses caracteres. É o serviço do script abaixo.
Para executar, proceda assim:

./script nome_arquivo

para que o script saiba qual arquivo deve renomear.

Então, a primeira providência é uma checagem se foi passado o argumento através da condição if [ $# != 1 ].
Estando tudo bem, o script começa a renomear. O nome do arquivo fica armazenado na variável $1 e passa a transferir novos valores para as variáveis seguinte que foram usados nomes bem intuitivos.
De com_espaco passa o novo valor para sem_espaco.
sem_espaco para minuscula através do comando tr.
De minuscula para dash que substitui a sequência "_-_" por "-" através do sed.
Do dash para abre_parenteses e em seguida para fecha_parenteses que em ambos os casos usam o sed para substituir os caracteres.




#!/bin/bash
# remove spaces, uppercase to lowercase, replace " - " for "-", replace "(" for "-" and replace ")"for ""

# If file name isn't given show message
if [ $# != 1 ]
  then
   echo "Argumento: nome_de_arquivo"
   exit 1
fi

# grab the file name
com_espaco=`ls -1 "$1"`
# change space for underline
sem_espaco=`ls -1 "$1" | sed 's/ /_/g'`
#echo "$sem_espaco"
mv -v "$com_espaco" "$sem_espaco"
minuscula=$(echo "$sem_espaco" | tr A-Z a-z)
# change upper for lowercase
mv -v "$sem_espaco" "$minuscula"
# change _-_ for -
dash=`echo "$minuscula" | sed 's/_-_/-/'`
mv -v "$minuscula" "$dash"

ls "$dash" | grep "("
if [ $? -eq 0 ]
  then
   abre_parenteses=`ls "$dash" | sed 's/(/-/g'`
   mv -v "$dash" "$abre_parenteses"
fi

ls "$abre_parenteses" | grep ")"
if [ $? -eq 0 ]
  then
   fecha_parenteses=`ls "$abre_parenteses" | sed 's/)//g'`
   mv -v "$abre_parenteses" "$fecha_parenteses"
fi


Podemos automatizar este trabalho se forem muitos arquivos. Se for para os arquivos do mesmo diretório, há uma forma bem simples. Digite a linha de comando no seu terminal:


$ ls -1 | { while read arq; do ./script "$arq"; done; }


Apacerá uma mensagem de erro caso o nome de arquivo não tenha parênteses, mas garanto que no fim tudo estará devidamente renomeado.
É mais ágil quando é dado um duplo clique numa palavra e o terminal seleciona inteira facilitando o trabalho de copiar e colar.

quinta-feira, 4 de agosto de 2011

Numerando arquivos de forma cronológica


Desenvolvi este script para organizar a reunião de fotos de mais de uma máquina digital. Desta forma, independente como as câmera registram o nome de arquivo, as fotos são renomeadas de acordo com a sequência cronológica.
Primeiro, os nomes são renomeados para maiúsculas como foi no post Renomear de maiúscula para minúscula e com sequência numérica .

O comando ls -1 *.jpg trata de colunar todos os arquivos com essa extensão e a cada linha que avança, as variáveis ano, mes, dia, hora, mim, seg recebem seus respectivos valores e o comando tee -a faz duas tarefas:
  • exibe a saída na tela
  • armazena a saída no arquivo foto.txt
Como extrair a informação através do exiftool demanda processamento e dependendo da quantidade parece travado, exibir as mensagens mostra que o programa está executando. O passo seguinte é contar a quantidade de arquivos jpg e armazenar na variável total. Essa informação é usada no laço for para ser o critério de parada. Neste exemplo, fiz para mais de 100 fotos para que todos os nomes de arquivos fiquem com três dígitos (001.jpg, 002.jpg, .., 010.jpg, ..., 100.jpg, ...). Fica a seu critério a quantidade de dígitos. Caso opte por não preencher com 0s (zeros), use o exemplo sem dígitos.

#/bin/bash

for M in *.JPG
  do
    m=$(echo $M | tr A-Z a-z)
    mv -v $M $m
done

ls -1 *.jpg | {
  while read arq; do
    ano=`exiftool "$arq" | grep Original | sed 's/://g' | sed 's/ //g' | cut -c 18-21`
    mes=`exiftool "$arq" | grep Original | sed 's/://g' | sed 's/ //g' | cut -c 22-23`
    dia=`exiftool "$arq" | grep Original | sed 's/://g' | sed 's/ //g' | cut -c 24-25`
    hora=`exiftool "$arq" | grep Original | sed 's/://g' | sed 's/ //g' | cut -c 26-27`
    min=`exiftool "$arq" | grep Original | sed 's/://g' | sed 's/ //g' | cut -c 28-29`
    seg=`exiftool "$arq" | grep Original | sed 's/://g' | sed 's/ //g' | cut -c 30-31`
    echo "$arq" $ano$mes$dia$hora$min$seg
done
} | tee -a fotos.txt

cat fotos.txt | awk '{printf "%s %4s\n",$2,$1}' | sort -n > fotos2.txt

total=`ls *.jpg | wc -l`

for i in `seq 9`
  do
    file=`head -n $i fotos2.txt | tail -n 1 | cut -f2 -d ' '`
    mv -v $file 00$i.jpg
  done

for i in `seq 10 1 99`
  do
    file=`head -n $i fotos2.txt | tail -n 1 | cut -f2 -d ' '`
    mv -v $file 0$i.jpg
  done

for i in `seq 100 1 $total`
  do
    file=`head -n $i fotos2.txt | tail -n 1 | cut -f2 -d ' '`
    mv -v $file $i.jpg
  done

Recomendo esta automatição de renomear arquivos de acordo com o data e hora quando várias pessoas participaram da mesma viagem, por exemplo. Assim, a visualização não será exibida em dias alternados. Para encerrar, dois cuidados:

  • Garantir a câmera de todos estejam com a data e hora correta. Não precisam estar sincronizadas, apenas corretas.
  • Difícil acontecer, mas caso exista um arquivo que até foi tirada no mesmo segundo, uma das fotos será sobreescrita.

quarta-feira, 3 de agosto de 2011

Renomeando arquivos com sequência numérica a partir de um valor


O objetivo deste código-fonte é renomear arquivos com uma sequência numérica iniciando a partir de um determinado número. Neste exemplo, começa com o número 196. Executando no diretório que contém os arquivos *.jpg (observe que obedece o critério que está na linha com a variável nome), os novos nomes de arquivos tornam-se:

pag196.jpg, pag197.jpg, pag198.jpg, ...

até o último arquivo jpg que for encontrado.
A variável total conta os arquivos jpg para entregar ao laço for o critério de parada.
A variável nome armazena o nome do arquivo através do laço for que coloca os nomes em uma coluna e vai avançando linha a linha.
O comando mv renomeia cada arquivo.
O comando let incrementa a variável j.


#!/bin/bash

total=`ls *.jpg | wc -l`
j=196;

for i in `seq $total`
 do
   nome=`ls -1 *.jpg | head -n $i | tail -n 1`
   mv -v $nome pag$j.jpg
   let j++;
 done



Uma aplicação recomendada deste script como pode ser visto pelo novo nome de arquivo pag_NUMERO_.jpg é organizar de acordo com as páginas digitalizadas. Ler o documento no formato digital torna extremamente fácil localizar no livro digitalizado bastando apenas ver o nome do arquivo.

terça-feira, 2 de agosto de 2011

Alterando a permissão de todos os diretórios e subdiretórios

Alterando para 744 todos os subdiretórios a partir do script executado



  Seguindo a ideia de tratar arquivos dentro de um diretório, vamos abranger para uma execução recursiva. Em outras palavras, independente da quantidade de diretório e subdiretórios a partir do ponto que este script é executado, todos os diretórios e suas ramificações são tratados.

  Por exemplo, modificar a permissão de todos os diretórios e subdiretórios. Para cada path (caminho) encontrado, uma sintaxe do Shell Script destaca na cor azul.



#!/bin/bash

quantidade=`ls -R | grep './' | wc -l`

printf "\n       Mudando as permissoes de cada diretorios \n"
for i in `seq $quantidade`
  do
    dir=`ls -R1 | grep './' | sed 's/.\///' | sed 's/://' | head -n $i | tail -n 1`
    echo -e '\033[34;40;1m' "$dir" '\033[m'
    chmod -R 744 "$dir" 
    
    if [ $? == 0 ]
      then
      echo ok
    fi
done



  A variável quantidade informa o total de diretório e subdiretórios e o laço for faz a passagem por cada um deles.

  A sintaxe referido no início do texto é a que aparece na linha echo -e listando em highlighting (destaque).

  Finalmente, a permissão é modificada para o octal 744 alcançando o nosso propósito.

  Apenas para termos um feedback, uma mensagem contendo ok é exibida a cada alteração realizada com sucesso.


  Faço uma advertência quanto à segurança. Determinados diretórios tem seus números octais configurados para restringir acessos. Certifique-se que a alteração recursiva não violará algum diretório que exija maior segurança!

domingo, 31 de julho de 2011

Convertendo as fotos de um diretório específico


Olá!
Este post mostra como redimensionar fotos. Por exemplo, se as fotos forem uma matriz 3072x2304, o script reduzirá para 1/4 deste tamanho tornando 768x576.
Deve ser executado nos mesmo diretório que estão as fotos. Neste momento a variável dirorig (diretório de origem) armazena o comando pwd mantendo intacto os arquivos. Deve-se criar o diretório menor um nível abaixo do diretório onde estão as fotos para dar um destino às fotos tratadas (variável dirtrat). Para obter o tamanho de cada arquivo é necessário usar a saída do awk para obter o terceiro campo como entrada do sed para extrair os números no meio de outros caracteres.
Uma diferença com relação ao post anterior é a forma de selecionar os arquivos. No anterior, é usado um for porque é necessário incrementar um contador. O critério de seleção é um ls e um while executa enquanto encontrar o tipo selecionado. Desta forma, para cada arquivo que entra na seleção, executa a ação de redimensionar.


#!/bin/bash

##### Configuracao ####
# diretorio de origem
dirorig="$PWD"
# Entre com o diretorio onde ficarao as fotos tratadas
dirtrat="$PWD/menor"

mkdir "$dirtrat"

ls -1 *.jpg | {
  while read arq
    do
      l=`identify "$arq" | awk '{printf "%s\n",$3}' | sed 's/x/ /' | awk '{printf "%s\n",$1}'`
      c=`identify "$arq" | awk '{printf "%s\n",$3}' | sed 's/x/ /' | awk '{printf "%s\n",$2}'`
      width=`echo $l/4 | bc`        # 1/4 do comprimento
      height=`echo $c/4 | bc`       # 1/4 da altura
  echo linha=$width coluna=$height "$arq"

  if [ "$width" -gt "$height" ]
    then
      convert -resize "$witdh"x"$height" "$arq" "$dirtrat"/"$arq"
      echo "$witdh"x"$height"
    else
      convert -resize "$height"x"$witdh" "$arq" "$dirtrat"/"$arq"
      echo "$height"x"$witdh"
  fi
done
}


Um exemplo de aplicação deste script é fazer com que os anexos dos e-mail sejam bem mais leves. Ou mesmo quando for criar uma página na web, seu carregamento será bem mais rápido do que se for usar a do tamanho original.

sábado, 30 de julho de 2011

Renomear de maiúscula para minúscula e com sequência numérica

  Bem-vindos!
  Há um certo tempo que estudo Shell Script do GNU/Linux e agora passo a publicar meus códigos-fontes com a intenção de incentivar as pessoas a resolverem seus problemas programando. Um outro propósito é reunir pessoas que também programam para que todos se beneficiem ganhando novas técnicas de programação.

  Neste primeiro post eu mostro como modificar arquivos atendendo a um critério. Por exemplo, suponha um diretório que tenham uma diversidade de arquivos misturados. Vamos fazer as seguintes alterações:
1. Mudar de letras maiúsculas para minúsculas;
2. Alterar o nome de arquivos usando uma sequência numérica.

  Para resolver o item 1, temos:
for M in *.JPG
  do
     m=$(echo $M | tr A-Z a-z)
     mv -v $M $m
  done 

  Para a problema 2, o formato que os nomes de arquivos terão contem sempre 2 dígitos. Por exemplo: 01.jpg, 02.jpg, ..., 10.jpg, 99. jpg.

#!/bin/bash

declare -i i=1
declare -i qtde
qtde=`ls *.jpg | wc -l`

for i in `seq 9`
  do
    mv -v `ls -1 *.jpg | head -n $i | tail -n 1` 0$i.jpg
  done

for i in `seq 10 1 "$qtde"`
  do
    mv -v `ls -1 *.jpg | head -n $i | tail -n 1` $i.jpg 
  done
 


  Caso deseje que seja 1.jpg, 2.jpg, ..., 10.jpg, ou seja, sem o número 0 (zero) à esquerda, o código pode ser enxugado para este abaixo:

#!/bin/bash

declare -i i=1
declare -i qtde

qtde=`ls *.jpg | wc -l`
for i in `seq "$qtde"`
  do
    mv -v `ls -1 *.jpg | head -n $i | tail -n 1` $i.jpg
  done

  As câmeras digitais armazenam os nomes de arquivos com letras maiúsculas. Portanto, caso queira manter a extensão JPG (maiúsculas), troque a linha

qtde=`ls *.jpg | wc -l`


por


qtde=`ls *.JPG | wc -l`

para que o sistema operacional faça a contagem correta.

  O exemplo apresentado tratou da extensão jpg. Modifique de acordo com as suas necessidades tornando aplicável à outras extensões ou mesmo o nome do arquivo.


  Espero que possa ser útil para organizar seus arquivos pessoais e profissionais.

Murilo Fujita
murilofujita@gmail.com