Shell Script Eban Coded A Dos
Shell Script Eban Coded A Dos
1. Introdução
1.1. Pré-requisitos
1.2. Sobre o Tutorial
2. Preparando o Terreno
3. O Básico
4. Colocando dados na tabela
4.1. Arquivo com os Dados
4.1.1. Inserindo cada registro por vez
4.1.2. Criando um Arquivo SQL
4.2. Interativo
5. Pesquisando Dados
6. Removendo Registro
7. Atualizando um Registro
8. PostgreSQL
9. Considerações Finais
10. Agradecimentos
1. Introdução
Muitas pessoas, quando precisam fazer aplicações "mais complexas" e que utilizem banco de dados, optam por uma linguagem de
programação diferente de Shell Script. Muitas delas não compreendem o poder de um script em shell e/ou desconhecem a linguagem
interpretada contida nele.
Este tutorial se propõe a mostrar como podemos integrar shell script com banco de dados. Nos exemplos usaremos o MySQL, devido ao
fato dele ser GPL, fácil e rápido. Mas a idéia central abordada neste texto pode ser aplicada também a outros bancos de dados. No final,
mostrarei como podemos utilizar a mesma idéia com PostgreSQL. Será mostrado o básico, apenas para iniciar o leitor no assunto.
Ao final, você verá o poder de um shell script interagindo com um banco de dados, enxergará a luz e conhecerá a doutrina dos amantes
do shell. =8)
1.1. Pré-requisitos
Como não vou abordar o básico sobre shell script e SQL, espera-se que você já tenha conhecimento de ambos.
2. Preparando o Terreno
Vamos ao que interessa. Veremos os passos essenciais para criarmos um banco de dados para interagir com os nossos scripts. É
recomendado que você leia alguns tutoriais sobre MySQL antes de colocar o seu sistema em produção.
Neste ponto espera-se que você já tenha o mysql-server e o mysql-client do MySQL instalados. Como os nomes dos pacotes do server e
do client variam entre as distribuições Linux, verifique se você tem os arquivos mysqld e mysql.
http://thobias.org/doc/shell_bd.html 1/14
15/11/2018 Shell Script e Banco de Dados
Algumas distribuições inicializam o daemon do MySQL sem permitir acesso remoto. No Debian, por exemplo, caso você queira
permitir, comente a seguinte linha no arquivo /etc/mysql/my.cnf:
#skip-networking
Na instalação padrão, o MySQL cria um usuário sem senha chamado root que tem controle total sobre ele. Assim, a primeira coisa que
faremos será definir uma senha para este usuário:
Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
mysql>
mysql>
mysql> SET PASSWORD FOR 'root'@'localhost' = PASSWORD('senha');
Query OK, 0 rows affected (0.00 sec)
mysql>
Troque "senha" para a senha que você escolher. Pronto, definimos uma senha para o usuário root. Agora vamos criar uma base de dados
para os nossos experimentos e adicionar um usuário para utilizá-la.
Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
mysql>
mysql> create database mysql_bash;
Query OK, 1 row affected (0.00 sec)
mysql> GRANT CREATE, DROP, SELECT, INSERT, UPDATE, DELETE ON mysql_bash.* TO thobias@localhost;
Query OK, 0 rows affected (0.00 sec)
mysql> GRANT CREATE, DROP, SELECT, INSERT, UPDATE, DELETE ON mysql_bash.* TO thobias@'%';
Query OK, 0 rows affected (0.00 sec)
mysql>
O primeiro comando (create database mysql_bash;), cria uma base de dados com o nome mysql_bash, ou seja, um diretório onde
ficarão as nossas tabelas.
O segundo comando cria um usuário chamado thobias com a senha senha, e dá permissão para ele se conectar ao banco de dados. O
terceiro comando difere do segundo pelo fato de dar permissão para o usuário thobias se conectar ao banco à partir de qualquer máquina.
Poderíamos especificar a máquina, exemplo:
O % é um curinga que especifica qualquer máquina. Caso você não execute o terceiro comando, você poderá acessar o banco somente
na mesma máquina que está rodando o banco, em outras palavras, o localhost.
Os dois últimos comandos servem para dar permissão ao usuário thobias fazer o que quiser na base da dados mysql_bash.
Note: o usuário só pode mexer na base de dados mysql_bash. Nas demais ele não tem permissão
http://thobias.org/doc/shell_bd.html 2/14
15/11/2018 Shell Script e Banco de Dados
mysql> quit
Bye
prompt>
Beleza, já estamos com o nosso banco de dados pronto para começar a brincadeira. =8)
3. O Básico
Shell script, diferente de PHP, Perl, C, Python e outras linguagens de programação, não tem interação direta com o MySQL. Toda
comunicação entre os scripts com o banco de dados se dá através do cliente, ou seja, um comando.
O shell para se comunicar com o banco de dados usa o cliente (comando mysql)
O grande esquema está no fato do cliente do MySQL ser muito flexível, aceitando comandos SQL da entrada padrão (stdin), através da
linha de comando (utilizando a opção -e), fazendo dump da base, etc.
Como típico exemplo de banco de dados, vamos criar uma agenda. :P Primeiro, criaremos uma tabela chamada agenda:
Como sabemos que o comando foi executado com sucesso ou não ???
Simples. Como todo comando UNIX ele retorna 0 se foi executado com sucesso ou um número diferente de 0 caso ocorra algum erro.
prompt> echo $?
0
prompt>
Caso nós executássemos de novo o comando para criar a tabela agenda, ocorreria um erro, pois já existe uma tabela com este nome na
base de dados:
O echo $? retornou um número diferente de 0. Assim, podemos colocar o comando em um if, ou usar os operadores lógicos && e ||, ou
seja, tratá-lo como um típico comando UNIX.
Então vamos começar a utilizar o comando acima e apenas trocar o comando SQL para mexer nos nossos dados. Mas aí vem um
"problema". Se quando executamos aquele comando, algum usuário executa um ps aux. hmmmmm nossa senha vai aparecer, e aí já viu
né :/
A partir da versão 3.22, por padrão o cliente e o servidor na inicialização lêem o arquivo de configuração ~/.my.cnf, para pegarem
opções específicas dos usuários. Podemos criar este arquivo com as seguintes linhas:
http://thobias.org/doc/shell_bd.html 3/14
15/11/2018 Shell Script e Banco de Dados
> password=senha
> FIM
[client]
password=senha
prompt>
prompt>
prompt> cat .my.cnf
[client]
password=senha
prompt>
Caso você queira executar o comando SQL em uma máquina remota, utilize a opção -h e o host. Exemplo:
1º campo nome
2º campo telefone
3º campo E-mail
4º campo data de aniversário
Uma maneira seria criar um script, onde pegamos linha a linha e criamos um SQL para inserir os dados:
http://thobias.org/doc/shell_bd.html 4/14
15/11/2018 Shell Script e Banco de Dados
#
# $1 = arquivo com os dados já formatados
#
IFS=:
mysql -u thobias -e \
"INSERT INTO agenda VALUES('$nome','$fone','$mail','$aniver')" mysql_bash
prompt>
executando:
Nome: Batman
Telefone:
mail: batman@batmail.com
Aniversário: 1970-05-15
Operacao OK
Nome: Robin
Telefone: (21) 9999-1111
mail: robin@batmail.com
Aniversário: 1985-12-25
Operacao OK
Mas imagine que temos um arquivo imenso. Fazer uma conexão com o banco para executar cada insert não é a melhor alternativa.
IFS=:
prompt>
http://thobias.org/doc/shell_bd.html 5/14
15/11/2018 Shell Script e Banco de Dados
INSERT INTO agenda VALUES('Robin','(21) 9999-1111','robin@batmail.com','1985-12-25');
INSERT INTO agenda VALUES('Mulher Maravilha','','M.maravilha@bizarro.com','');
prompt>
ou
Ops! o nosso primeiro insert já existe. No nosso caso, todos os insert já existem, mas imagine que podem haver alguns que ainda não
existam e não sabemos quais são. O cliente mysql, por default, vai parar de executar os comandos SQL assim que algum comando
retornar um erro. Para garantirmos que ele executará todos os comandos, mesmo que alguns retornem erros, utilizamos a opção -f.
Note que, esta tática de colocar vários comandos SQL em um arquivo e passá-lo para o cliente mysql, pode ser utilizado com qualquer
comando SQL dentro do arquivo utilizando o ponto-e-vírgula para separá-los. Por exemplo, na instalação de um programa você pode
criar um arquivo.SQL com os comandos para criar as tabelas necessárias, popular o banco com alguns dados iniciais, etc.
4.2. Interativo
Outra possibilidade é fazer um script para ler do teclado uma nova entrada para a base:
prompt>
http://thobias.org/doc/shell_bd.html 6/14
15/11/2018 Shell Script e Banco de Dados
Executando:
prompt> ./input_3.sh
Entre com os dados para incluir na agenda
5. Pesquisando Dados
Para pesquisar dados na nossa base de dados utilizamos o comando SQL SELECT. Vamos fazer um script que procure por um nome na
tabela e mostra todas informações. Utilizaremos o curinga * para diferenciar a pesquisa exata da parcial (usando o LIKE do SQL).
prompt>
Note que a primeira pesquisa não retornou nada, pois não existe um registro onde o campo nome tenha o valor igual a super. Quando
usamos o curinga *, dizemos qualquer campo que começe por super.
http://thobias.org/doc/shell_bd.html 7/14
15/11/2018 Shell Script e Banco de Dados
A segunda pesquisa obteve sucesso, pois casou um registro com o campo nome igual ao que nós procurávamos.
Se quisermos usar o curinga para procurar por qualquer dado, temos que colocá-lo entre aspas para o shell não interpretá-lo:
prompt> ./search.sh *
prompt>
prompt> ./search.sh "*"
+------------------+------------------------+-------------------------------+-------------+
| nome | telefone | email | aniversario |
+------------------+------------------------+-------------------------------+-------------+
| Robin | (21) 9999-1111 | robin@batmail.com | 1985-12-25 |
| Batman | | batman@batmail.com | 1970-05-15 |
| Super Man | (21)1234-5678 trabalho | superman@palaciodajustica.com | 1965-10-25 |
| Mulher Maravilha | | M.maravilha@bizarro.com | 0000-00-00 |
| Formiga Atomica | | formiga@formigueiro.com | 1930-12-12 |
+------------------+------------------------+-------------------------------+-------------+
prompt>
Vamos deixar a saída mais fru-fru. O MySQL utiliza como separador de campos o TAB (\t), então colocaremos o \t como o separador
de campos default (IFS):
done
prompt>
Nome : Batman
Telefone : batman@batmail.com
E-mail : 1970-05-15
Aniversário:
prompt>
OPS! Algo está errado. O E-mail está com a data de aniversário?! Se analisarmos o registro do batman veremos que ele não tem telefone:
Como o separador de registros é o TAB e nós cadastramos o telefone dele usando aspas simples '' no INSERT do SQL, ele não mostra o
NULL, ficando então, dois TABs grudados (\t\t). Nós utilizamos o IFS com TAB. Para simular o que está acontecendo vamos a um
exemplo simples:
Repare que no echo não tem o valor 2, sendo omitido por dois TABs seguidos. Só que o nosso read não está considerando isto, ele está
tratando TABTAB como 1 campo. Para resolver vamos usar um sed macho para colocar um espaço em branco entre os TABs
Segundo problema é a data, na saída do MySQL está aaaa-mm-dd, vamos fazer um outro sed para tratar a data:
http://thobias.org/doc/shell_bd.html 9/14
15/11/2018 Shell Script e Banco de Dados
# colocamos um espaço em branco entre TABs repetidos (\t\t)
echo "$S" | sed ":a;s/\(`echo -e '\t'`\)\(\1\)/\1 \2/;ta" | \
while read nome fone mail aniver; do
echo "
Nome : $nome
Telefone : $fone
E-mail : $mail"
echo "Aniversário: $(data_mysql-to-brasil $aniver)"
done
prompt>
Nome : Batman
Telefone :
E-mail : batman@batmail.com
Aniversário: 15/05/1970
prompt>
prompt> consulta.sh super*
Nome : Robin
Telefone : (21) 9999-1111
E-mail : robin@batmail.com
Aniversário: 25/12/1985
Nome : Batman
Telefone :
E-mail : batman@batmail.com
Aniversário: 15/05/1970
6. Removendo Registro
Agora as coisas mudam um pouco. No DELETE, não importa se o registro existe ou não, o código de retorno sempre será zero, ou seja,
echo $? é 0.
prompt> mysql -u thobias -e "DELETE FROM agenda WHERE nome = 'nenhum'" mysql_bash
prompt> echo $?
0
prompt>
Mas repare que não existe ninguém com o nome nenhum na base. Para resolver o problema teremos que utilizar a opção -vv, que retorna
algumas informações e dentre elas, quantas "linhas" da tabela foram alteradas.
prompt> mysql -vv -u thobias -e "DELETE FROM agenda WHERE nome = 'nenhum'" mysql_bash
--------------
DELETE FROM agenda WHERE nome = 'nenhum'
--------------
Bye
prompt>
http://thobias.org/doc/shell_bd.html 10/14
15/11/2018 Shell Script e Banco de Dados
Repare 0 rows. Agora com um sed pra filtrar a saída:
prompt> mysql -vv -u thobias -e "DELETE FROM agenda WHERE nome = 'nenhum'" mysql_bash |\
sed -n '/^Query/s/.*, \([0-9]\+\) rows.*/\1/p'
0
prompt>
[ $S -eq 0 ] && echo "Registro não encontrado" || echo "Foram deletado(s) $S registro(s)"
[ $S -eq 0 ] && echo "Registro não encontrado" || echo "Foram deletado(s) $S registro(s)"
fi
prompt>
Testando:
7. Atualizando um Registro
Como no delete, aqui ocorre o mesmo problema. Pois o UPDATE do SQL sempre retorna zero. Bom, sempre retorna zero se a query
SQL estiver correta, caso contrário, o $? terá um valor diferente de zero.
prompt> mysql -u thobias -e "DELETE FROM agenda WHERE campo_invalido = 'nada'" mysql_bash
ERROR 1054 at line 1: Unknown column 'campo_invalido' in 'where clause'
prompt>
prompt> echo $?
1
prompt>
Repare que a query SQL está procurando o nada no campo campo_invalido da tabela agenda. Como este campo não existe, o código de
retorno foi 1.
Para descobrirmos se foi alterado algum registro na base temos que utilizar a opção -vv, para ver quantas linhas (rows) o comando SQL
alterou.
http://thobias.org/doc/shell_bd.html 11/14
15/11/2018 Shell Script e Banco de Dados
prompt> mysql -vv -u thobias -e "UPDATE agenda SET telefone='9999999' WHERE nome ='robin'" mysql_bash
--------------
UPDATE agenda SET telefone='9999999' WHERE nome ='robin'
--------------
Bye
prompt>
Podemos utilizar o mesmo algoritmo e o mesmo sed do DELETE. Só que aqui precisamos saber qual campo o usuário gostaria de
atualizar.
O script abaixo recebe como entrada o campo da tabela a ser atualizado e o nome da pessoal que será feita a atualização.
[ $S -eq 0 ] && echo "Registro não encontrado" || echo "Foram alterado(s) $S registro(s)"
# Procura por partes do nome
else
S=$(mysql -vv -u thobias -e \
"UPDATE agenda SET $campo='$dados' WHERE nome LIKE '${*//\\*/%}'" mysql_bash | linha)
[ $S -eq 0 ] && echo "Registro não encontrado" || echo "Foram alterado(s) $S registro(s)"
fi
prompt>
Hora de testar:
prompt> atualiza.sh
Campos Validos: nome telefone email aniversario
prompt>
prompt> atualiza.sh formiga
http://thobias.org/doc/shell_bd.html 12/14
15/11/2018 Shell Script e Banco de Dados
Campos Validos: nome telefone email aniversario
prompt>
prompt> atualiza.sh telefone robin
Novos dados para telefone: 111112222 casa
Foram alterado(s) 1 registro(s)
prompt>
prompt> atualiza.sh telefone supe*
Novos dados para telefone: 99999999
Foram alterado(s) 1 registro(s)
prompt>
prompt> atualiza.sh telefone nenhum
Novos dados para telefone: 12122
Registro não encontrado
prompt>
8. PostgreSQL
Outro banco de dados muito utilizado e GPL é o PostgreSQL. Como tinha comentado, o shell não se comunica diretamente com o banco
de dados, ou seja, nós precisamos do cliente. No PostgreSQL, o nome do programa cliente é psql. Como no MySQL, ele tem várias
opções que nos permitem trabalhar com shell. Por exemplo, ele aceita, através da opção -h, realizar um comando SQL em uma máquina
remota, especificar o usuário com a opção -U, gerar saída HTML com o uso da opção -H e mais um monte de coisas. Mas a parte
principal é que ele também aceita comandos SQL via linha de comando e gera o resultado na saída padrão (stdout). Exemplo:
prompt> su postgres
prompt>
prompt> createdb mysql_bash
prompt>
prompt> psql mysql_bash
Welcome to psql, the PostgreSQL interactive terminal.
mysql_bash=#
mysql_bash=# CREATE TABLE agenda (nome VARCHAR(50),email VARCHAR(35));
CREATE
mysql_bash=# \q
prompt>
prompt> echo "INSERT INTO agenda VALUES ('Super Man','superman@palaciodajustica.com')" | psql -f- mysql_bash
INSERT 16572 1
prompt>
prompt> echo "INSERT INTO agenda VALUES ('Batman','batman@batmail.com')" | psql -f- mysql_bash
INSERT 16573 1
prompt>
prompt> echo "\d agenda" | psql -U postgres -f- mysql_bash
Table "agenda"
Column | Type | Modifiers
--------+-----------------------+-----------
nome | character varying(50) |
email | character varying(35) |
prompt>
prompt> echo "\pset border 2; \d agenda" | psql -U postgres -f- mysql_bash
Border style is 2.
Table "agenda"
+--------+-----------------------+-----------+
| Column | Type | Modifiers |
+--------+-----------------------+-----------+
| nome | character varying(50) | |
| email | character varying(35) | |
+--------+-----------------------+-----------+
prompt>
prompt>
http://thobias.org/doc/shell_bd.html 13/14
15/11/2018 Shell Script e Banco de Dados
Com a opção -f podemos especificar um arquivo contendo os comandos SQL ou usar um hífen para ele ler os comandos da entrada
padrão (stdin). Com a opção -c, ele executa uma query SQL.
9. Considerações Finais
Fizemos um tour pelo maravilhoso mundo do shell script com banco de dados. Analisamos todas as operações básicas do SQL, ou seja, o
básico você já sabe. O que mudará serão os comandos SQL que, "no mundo real", serão mais complexos ou maiores. Mas o tratamento
para eles serão os mesmos descritos neste tutorial.
Vários outros scripts deveriam ser feitos e os scripts acima deveriam ser estendidos para termos uma verdadeira agenda. Por exemplo,
nosso script de pesquisa só aceita pesquisas pelo campo nome, então se você quer saber de quem é o telefone xxxxxx, não dá. Mas, para
adicionarmos esta funcionalidade, o algoritmo do script será o mesmo, alterando somente o comando SQL para fazer o SELECT pelo
campo telefone.
Estas extensões vou deixar para você fazer e, assim, se divertir um pouco também. Pô, só eu que faço a melhor parte! =8)
Imagine o poder de um shell script interagindo com um banco de dados mais CGI, dialog, etc.
10. Agradecimentos
Silvano Bolfoni Dias
Aurélio Marinho Jargas
http://thobias.org/doc/shell_bd.html 14/14