Esses dias, um pouco antes da BSD Day pra dize a verdade, eu aceitei o convite do prof. Juliano pra falar sobre shell scripts.
Eu não preparei muito antes, e fiz um tipo de live coding sobre shell scripts mostrando um pouco de cada coisa. Não espero que seja tido com um tipo de aprendizado justamente porque eu realmente não preparei nada como aula ou palestra, mas espero que sirva de inspiração pra quem quiser iniciar.
Boa diversão!
Chamada pro vídeo.
Vídeo completo.
Por muitos anos o meu comando preferido pra baixar páginas e até fazer mirrors foi o comando wget. Até eu descobrir o curl.
Não que eu já não conhecesse o curl. Com tantos anos de estrada com Unix, principalmente Linux e FreeBSD, curl era um conhecido que eu evitava usar. O motivo? Zona de conforto. wget era um comando conhecido e que eu sempre usava, desde que ando comecei a aprender Unix, em 1997. curl por outro lado era talvez tão antigo quanto, mas cheio de opções cabulosas que eu sentia um certo receio de usar.
Atualmente eu trabalho bastante com backend web e curl virou meu braço direito. E conforme fui aprendendo a usar mais, fui adorando. Hoje em dia não faço um container que seja sem o curl dentro. E acabei até deixando pra lá o wget mas... hoje é dia de falar de curl.
Durante essa semana no trabalho tivemos um problema de servidor web down. Ao tentar conectar ele ficava um tempo tentando dar a resposta e depois enviava um erro 500 (acho que era 503, mas isso não importa). Então como eu queria acessar o serviço assim qeu estivesse disponível e não queria ficar dando reload na aba do navegador, fiz um script com curl. Ele usa uma das opções do curl de retorna um valor do header de resposta, que no caso era os status code.
status_code=0
while [ $status_code -ne 200 ]
do
sleep 10
status_code=$(curl -s -o /dev/null -w "%{http_code}" https://helio.loureiro.eng.br/)
echo "status_code=$status_code"
done
O script fica monitorando o site e retorna o valor do status code em loop.
status_code=500 status_code=500 status_code=500 status_code=500 status_code=500 status_code=200
Assim que receber uma resposta 200, que é ok, para. Deixei isso rodando num shell no canto do desktop (uso duas telas então não bloqueou minha visão de nada). Assim que parou, voltei ao browser e acessei o serviço.
Coisa linda, não?
Entre os vários grupos do Telegram, um que é muito bom é o de shell, o t.me/shellbr pros mais íntimos.
Um dia desses, entre discussões de como fazer um shell melhor e eu postando sticker pros falantes de língua inglesa de que o grupo é em língua portuguesa, apareceu algo que abriu minha visão em shell pra algo muito maravilhoso. Não é uma novidade de um comando mágico que faz algo completamente novo, mas a simplicidade da solução que esteve esse tempo todo na minha cara e eu nunca vi foi o que me fascinou.
Pra dar um pouco mais de contexto, o que se referia isso: quem nunca precisou mandar um "ps auxwww | grep firefox" e pegou o próprio comando grep na saída?
~> ps auxwww | grep firefox helio 5719 15.5 2.9 3994484 475156 ? Rl 20:57 4:38 /usr/lib/firefox/firefox --ProfileManger --no-remote helio 5815 6.0 1.6 3021712 259472 ? Sl 20:58 1:47 /usr/lib/firefox/firefox -contentproc -childID 1 helio 5876 1.0 1.2 2687192 201516 ? Sl 20:58 0:18 /usr/lib/firefox/firefox -contentproc -childID 2 helio 5916 0.5 1.0 2646492 161856 ? Sl 20:58 0:10 /usr/lib/firefox/firefox -contentproc -childID 3 helio 5939 5.8 2.0 3008700 325944 ? Rl 20:58 1:44 /usr/lib/firefox/firefox -contentproc -childID 4 helio 9210 1.0 1.5 2875692 241532 ? Sl 21:08 0:12 /usr/lib/firefox/firefox -contentproc -childID 9 helio 10161 1.5 1.1 2676620 179336 ? Rl 21:11 0:15 /usr/lib/firefox/firefox -contentproc -childID 10 helio 10394 0.2 0.7 2583360 120484 ? Sl 21:12 0:02 /usr/lib/firefox/firefox -contentproc -childID 11 helio 11818 0.0 0.4 2549948 77524 ? Sl 21:18 0:00 /usr/lib/firefox/firefox -contentproc -childID 13 helio 14368 0.0 0.0 18056 1052 pts/2 S+ 21:27 0:00 grep --color=auto firefox
Comecei com Linux em 1997, quando aprendi a usar as Sparc stations da universidade. Mais de 20 anos nessa indústria vital e eu sempre, sempre, usei desse jeito:
~ > ps auxwww | grep firefox | grep -v grep helio 5719 14.6 3.0 3991196 481364 ? Sl 20:57 4:56 /usr/lib/firefox/firefox --ProfileManger --no-remote helio 5815 6.2 1.7 3019784 279384 ? Sl 20:58 2:05 /usr/lib/firefox/firefox -contentproc -childID 1 helio 5876 0.9 1.2 2687192 202532 ? Sl 20:58 0:19 /usr/lib/firefox/firefox -contentproc -childID 2 helio 5916 0.5 1.0 2646492 164072 ? Sl 20:58 0:10 /usr/lib/firefox/firefox -contentproc -childID 3 helio 5939 5.4 2.0 3008700 330532 ? Sl 20:58 1:49 /usr/lib/firefox/firefox -contentproc -childID 4 helio 9210 0.9 1.5 2875692 241876 ? Sl 21:08 0:13 /usr/lib/firefox/firefox -contentproc -childID 9 helio 10161 1.3 1.1 2676620 179336 ? Sl 21:11 0:16 /usr/lib/firefox/firefox -contentproc -childID 10 helio 10394 0.2 0.7 2583360 120588 ? Sl 21:12 0:02 /usr/lib/firefox/firefox -contentproc -childID 11 helio 11818 0.0 0.4 2549948 77524 ? Sl 21:18 0:00 /usr/lib/firefox/firefox -contentproc -childID 13
Com essa maravilhosa dica do Hélio Campos, basta fazer assim:
~ > ps auxwww | grep [f]irefox helio 5719 14.5 3.1 4005676 500088 ? Sl 20:57 5:01 /usr/lib/firefox/firefox --ProfileManger --no-remote helio 5815 6.7 1.8 3034264 293864 ? Rl 20:58 2:18 /usr/lib/firefox/firefox -contentproc -childID 1 helio 5876 0.9 1.2 2687192 203656 ? Sl 20:58 0:19 /usr/lib/firefox/firefox -contentproc -childID 2 helio 5916 0.5 1.0 2646492 164072 ? Sl 20:58 0:10 /usr/lib/firefox/firefox -contentproc -childID 3 helio 5939 5.3 2.0 3008700 331836 ? Sl 20:58 1:51 /usr/lib/firefox/firefox -contentproc -childID 4 helio 9210 0.9 1.5 2875692 241876 ? Sl 21:08 0:14 /usr/lib/firefox/firefox -contentproc -childID 9 helio 10161 1.3 1.1 2676620 179336 ? Sl 21:11 0:17 /usr/lib/firefox/firefox -contentproc -childID 10 helio 10394 0.2 0.7 2583360 120588 ? Sl 21:12 0:02 /usr/lib/firefox/firefox -contentproc -childID 11 helio 11818 0.0 0.4 2549948 77524 ? Sl 21:18 0:00 /usr/lib/firefox/firefox -contentproc -childID 13
Eu achei espetácular. Pode ser que eu esteja exagerando, mas achei mesmo. Uma dica muito simples e acabou com décadas usando um extra "grep" pra resolver as coisas.
Muito obrigado Hélio Campos e grupo shellbr!
Em várias ocasiões, preciso de alguma automação via script que utilize um comando telnet. Existem vários problemas de segurança em relação ao uso do telnet, mas vários equipamentos de rede, entre switches e roteadores, fazem uso dele (se bem que é possível substituir por ssh).
Para usar em scripts, uma das formas mais fáceis de fazer isso é concatenando comandos. É possível fazer login, entrar com a senha, e enviar os comandos necessários.
Como exemplo, uma conexão telnet normalmente seria da seguinte forma:
[helio@linux ~]$ telnet server
Trying 10.10.7.4...
Connected to server.
Escape character is '^]'.
login: user
Password:
user@server> exit
logout
Connection to server closed by foreign host.
Agora no formato para scripts, utilizando o pipe:
[helio@linux ~]$ (echo "user"; sleep 1; echo "user"; sleep 1;echo "date"; sleep 1) | telnet server
Trying 10.10.7.4...
Connected to server.
Escape character is '^]'.
login:
Password:
user@server>date
Thursday, July 29, 2010 8:11:52 PM BRT
user@server>
Connection to server closed by foreign host.
Cada comando echo envia para o telnet os comandos que seriam digitados. Utilizei um comando date como exemplo, mas é possível enviar outros comandos e até mesmo ler a saída do comando, redirecionando para um arquivo.
Por motivos bizarros e nada claros para ninguém, resolveram fazer alguma "regra de segurança" na empresa para bloquear as máquina que não estejam rodando Windows Vista. Não que eu seja o único fora do padrão, mas existem os consultores externos que, assim como eu, são lembrados dessa limitação de tempos em tempos.
Como resolvi não perder mais tempo com isso, ou ficar bloqueado durante horário de trabalho sem aviso, e não migrar pro "Vista", resolvi fazer um script que altera meu MAC address da placa de rede a cada boot.
Fiz uma função em shell para poder ser utilizado em qualquer Unix, mas estou rodando em bash e não testei seu funcionamento em /bin/sh e /bin/ksh.
make_mac() {
mac=""
for blk in 0 1 2 3 4 5
do
for id in 0 1
do
macid=`jot -r 1 0 15`
case $macid in
10) macid="a";;
11) macid="b";;
12) macid="c";;
13) macid="d";;
14) macid="e";;
15) macid="f";;
esac mac="$mac$macid"
done
mac="$mac:"
done
mac=`echo $mac | sed 's/:$//'`
if [ ! $mac ]; then
echo "Failed to generate MAC"
exit 1
else
echo "$mac"
fi
}
Para utilizar, basta fazer uma chamada como no código abaixo (já adaptado pra Linux e FreeBSD):
mymac=`make_mac`
echo "Using MAC ADDR: $mymac"
case `uname -s` in
FreeBSD) INTF="bge0"
ifconfig $INTF lladdr $mymac ;;
Linux) INTF="eth0"
ifconfig $INTF hw ether $mymac ;;
*) echo "Operating System not supported"
exit 1
esac