helio.loureiro.eng.br
  • Home
  • Unix
  • Linux
  • Blog
  • Python
  • Programação
  • Tudo
  • Suécia
  1. You are here:  
  2. Home
  3. Programação
  4. Shell Scripts

Os artigos mais lidos de 2024

  • linux-br.org num ritmo mais lento
  • Criando um serviço de relay de DNS-over-HTTPS
  • Minha palestra sobre a história do Unix na IX BSD Day
  • Pedal forte de 2023 em dados do Google
  • Linux vs GNU/Linux

Imprimindo uma caixa em volta do texto em shell

Details
Written by: Helio Loureiro
Category: Shell Scripts
Published: February 26, 2025
Hits: 368
  • bash
  • UI

Nada muito glamoroso. Só um script usando utf-8 pra fazer uma caixinha bonitinha em volta do texto.

  #!/usr/bin/env bash

sizeof() {
    local msg="$1"
    local size=$(echo $msg | wc -L)
    # one space at beginning and other at the end
    size=$((size+2))
    echo $size
}

printchar() {
    local char="$1"
    local nr="$2"
    while [ $nr -gt 0 ]
        do
        echo -ne "$char"
        nr=$((nr-1))
    done
}


printbox() {
    local msg="$1"
    local s=$(sizeof "$msg")

    echo -n "┌"
    printchar "─" $s
    echo "┐"
    echo -e "│ ${msg} │"
    echo -n "└"
    printchar "─" $s
    echo -e "┘\n"
}

message="$@"
printbox "$message"

O código também está publicado no GitHub.

https://github.com/helioloureiro/homemadescripts/blob/master/printbox.sh

Adicionando uma pergunta em shell script

Details
Written by: Helio Loureiro
Category: Shell Scripts
Published: November 06, 2024
Hits: 743

Esse é um código que estamos usando bastante aqui na firma nova.  Ajuda a fazer seu script decidir se segue em frente ou para.  E basta apenas apertar uma teclar, sem enter.

 

#! /usr/bin/env bash
read -p "Deseja continuar (s/n)? " -n 1 -r resposta

if [[ "$resposta" =~ [sS] ]];then
  echo "Resposta foi sim"
else
  echo "Resposta foi não"
fi

Adeus Twitter. Longa vida Mastodon!

Details
Written by: Helio Loureiro
Category: Shell Scripts
Published: November 26, 2022
Hits: 1630
  • mastodon
  • toot
  • twitter

Como um tsunami, Elon Musk assumiu o Twitter e literalmente varreu como uma onde destruidora a empresa.  De cara mandou metade pra rua, depois pediu code review pra cada um que ficou e deu prazo para irem trabalhar fisicamente na empresa ou automaticamente estariam demitidos.   Claro que as coisas não foram muito bem.  E no momento atual continuam indo por água abaixo.

Enquanto isso redes alternativas ganharam tração, entre elas a Mastodon.  Ao contrário do Twitter, Mastodon não é uma empresa ou uma rede: é um conjunto de servidores conversando o mesmo protocolo e que se comunicam entre si.   Eu já tinha uma conta na instância mastodon.social, onde tudo surgiu.  Mas desde que foi criada, em 2015, eu tinha postado 2 mensagens.  E só.   Nunca teve muita gente ali pra conversar pra tornar a rede minimamente interessante.

Mas com a ascensão do Elon ao Twitter isso tudo mudou.  E pra melhor.  Muita gente interessante migrou pra rede Mastodon, ao ponto de atingir o efeito rede e manter um crescimento sustentando em termos de usuários e posts.  Se os servidores vão aguentar esse tráfego, daí já são outros 500.

No Twitter eu automatizava muita coisa.  Então pra mim era essencial ter as mesmas coisas no Mastodon.  Eu primeiramente descobri o programa "toot", em Python.  Com ele é possível criar posts usando shell script (e na verdade foi o que fiz de início).

Não sei se tem pacotes pra instalar o toot, mas eu usei o pip do próprio python pra instalar.

helio@MacOS> pip3 install toot

Com isso o programa "too" vai parar em ~/.local/bin, que eu já tenho na minha variável PATH, então funciona no shell.  Mas é preciso corrigir o PATH se for usar num script via crontab (como eu fiz depois).

O começo é criar um login na instância que for usar.   Eu por exemplo comecei com This email address is being protected from spambots. You need JavaScript enabled to view it., mas como eu já tinha conta numa outra instância que uso pra fotos ao invés do Instagram, o pixelfed.social, adicionei também.   E pra isso usei o parâmetro "-i".

helio@MacOS> toot login This email address is being protected from spambots. You need JavaScript enabled to view it.
helio@MacOS> toot login -i This email address is being protected from spambots. You need JavaScript enabled to view it.

As configurações ficam armazenadas num arquivo for json em ~/.config/toot/config.json, o que depois facilitou minha vida pra criar scripts em python (mas que vou descrever em outro artigo).

Daí você pode começar a mandar mensagens usando a conta padrão ou usando o "-i" pra qual instância quer mandar.

helio@MacOS> toot post "testing"

E o toot aceita mesmo passar conteúdo via pipe:

helio@MacOS> uname -a | toot post

Pra subir imagens e usando minha instância que posto em português:

helio@MacOS> toot activate helioloureiroBR@This email address is being protected from spambots. You need JavaScript enabled to view it.
✓ User helioloureiroBR@This email address is being protected from spambots. You need JavaScript enabled to view it. active
helio@MacOS> toot post "só li verdades" --media=$HOME/Pictures/chicobuarque-mastodon.jpg
Uploading media: /Users/ehellou/Pictures/chicobuarque-mastodon.jpg
Toot posted: https://mastodon.social/@helioloureiroBR/109410489057504335

Então é possível ver as possibilidades infinitas de scripts em shell com o uso de toot.

Pra terminar o artigo, deixo aqui a imagem muito significativa que enviei no teste.  Afinal não existe prazer maior na vida que ajudar um bilionário a ficar milionário.

Em tempo: eu não apaguei minhas contas no Twitter.  Estão lá mas inativas.

Shell é lento?

Details
Written by: Helio Loureiro
Category: Shell Scripts
Published: June 04, 2022
Hits: 2263

Durante a apresentação do grande prof. Júlio Neves na BSD Day 2022 sobre shell, ele fez uma comparação interessante sobre shell ser dito lento.  E mostrou o seguinte slide:

Eu achei muito interessante o exemplo, mas resolvi testar ele pra valer.

Então testei não com 200 interações, mas com 20 milhões.  Daí sim a coisa fica mais interessante.

Fiz o mesmo script em shell:

#! /usr/bin/env bash

for ((i=1; i<20000000; i++)) {
  : > arq-shell
}

Em python:

#! /usr/bin/env python3

for i in range(20000000):
    with open("arq-python3", "w") as fd:
        None

em perl:

#! /usr/bin/env perl

for ($i=0;$i<20000000;$i++) {
  open(FD, ">arq-perl");
}

e finalmente em Go:

package main

import (
        "log"
        "os"
)

func main() {
        for i := 0; i < 20000000; i++ {
                fd, err := os.Create("arq-go")
                fd.Close()
                if err != nil {
                        log.Fatal(err)
                }
        }
}

Os resultados foram os seguintes:

  
helio@goosfraba /t/comparacao-shell> time ./20M-touch.sh
________________________________________________________
    Executed in  303.69 secs    fish           external 
    usr time  164.93 secs    0.00 micros  164.93 secs 
    sys time  133.79 secs  533.00 micros  133.79 secs 
    
helio@goosfraba /t/comparacao-shell> time./20M-touch.py
________________________________________________________ 
    Executed in  374.49 secs    fish           external 
    usr time  225.16 secs  623.00 micros  225.16 secs 
    sys time  143.90 secs  125.00 micros  143.90 secs 
    
helio@goosfraba /t/comparacao-shell> time ./20M-touch.pl
________________________________________________________ 
    Executed in  173.94 secs    fish           external 
    usr time   47.95 secs    1.05 millis   47.95 secs 
    sys time  122.10 secs    0.00 millis  122.10 secs
    
helio@goosfraba /t/comparacao-shell> time ./20M-touch 
________________________________________________________ 
    Executed in  147.80 secs    fish           external 
    usr time   45.82 secs  579.00 micros   45.82 secs 
    sys time  107.38 secs  113.00 micros  107.38 secs 
    

Eu achei os resultados um pouco miseráveis pra python.  Então re-escrevi a função como era feito desde o python 1.2 (usando 3.10.4):

#! /usr/bin/env python3

for i in range(20000000):
    fd = open("arq-python3", "w")
    fd.close()

e o resultado não melhorou muita coisa.

  
helio@goosfraba /t/comparacao-shell> time ./20M-touch.py
________________________________________________________
    Executed in  370.23 secs    fish           external
    usr time  218.59 secs  641.00 micros  218.59 secs
    sys time  146.02 secs  132.00 micros  146.02 secs
  

Acho que agora os números falam por si só sobre shell ser lento ou não.  Claro que pra coisas mais simples é bem mais fácil fazer em shell, mas isso não significa um desempenho melhor.

Tirando essa parte de desafio, a palestra foi espetacular.  Quem não viu, recomendo que assistam.

 

Refatorando meu script de bloqueio de youtube no openwrt

Details
Written by: Helio Loureiro
Category: Shell Scripts
Published: December 19, 2021
Hits: 2968

Filho aborrecente é... aborrecente.  E infelizmente tenho de tempos em tempos de usar a artimanha de bloquear o YouTube pra conseguir sua atenção e fazer as suas tarefas.

Hoje eu estava revendo o script que criei em bloqueando Youtube no OpenWRT, criado em 2018.  Dei uma melhorada no código e fiz o cáculo do horário de uma forma melhor.

Precisei carregar os módulos "bc" e "iptables-mod-filter" no openwrt pra funcionar como desejado.


#! /bin/sh
# save it into /usr/lib/scripts/firewall.sh
# and add into scheduled tasks as
# */5 * * * * /usr/lib/scripts/firewall.sh timetable

NOW=$(date +"%H:%M")
TIMETABLE="07:55,10:00 12:00,18:00 20:30,22:00"

status_file=/tmp/firewall_status

blocked_pattern="youtubei.googleapis.com"
blocked_pattern="$blocked_pattern googlevideo.com"
blocked_pattern="$blocked_pattern ytimg-edge-static.l.google.com"
blocked_pattern="$blocked_pattern i.ytimg.com"
blocked_pattern="$blocked_pattern youtube-ui.l.google.com"
blocked_pattern="$blocked_pattern www.youtube.com"
blocked_pattern="$blocked_pattern googleapis.l.google.com"
blocked_pattern="$blocked_pattern youtubei.googleapis.com"
blocked_pattern="$blocked_pattern video-stats.l.google.com"
blocked_pattern="$blocked_pattern ytimg-edge-static.l.google.com"

enable_firewall() {
    echo "Enabling firewall"
    for chain in INPUT FORWARD OUTPUT
        do
        count=1
        for proto in tcp udp
            do
                for blocked in $blocked_pattern
                    do
                    echo iptables -I $chain $count -p $proto -m string --algo bm --string "$blocked" -j DROP
                    iptables -I $chain $count -p $proto -m string --algo bm --string "$blocked" -j DROP
                    count=`expr $count + 1`
                done
        done
        echo iptables -I $chain $count -p udp --sport 443 -j DROP
        iptables -I $chain $count -p udp --sport 443 -j DROP
        count=`expr $count + 1`
        echo iptables -I $chain $count -p udp --dport 443 -j DROP
        iptables -I $chain $count -p udp --dport 443 -j DROP
        count=`expr $count + 1`
    done
    echo -n "enabled" > $status_file
}

disable_firewall() {
    echo "Disabling firewall"
    for chain in INPUT FORWARD OUTPUT
        do
        for proto in tcp udp
            do
                for blocked in $blocked_pattern
                    do
                    echo iptables -D $chain -p $proto -m string --algo bm --string "$blocked" -j DROP
                    iptables -D $chain -p $proto -m string --algo bm --string "$blocked" -j DROP
                done
        done
        echo iptables -D $chain -p udp --sport 443 -j DROP
        iptables -D $chain -p udp --sport 443 -j DROP
        echo iptables -D $chain -p udp --dport 443 -j DROP
        iptables -D $chain -p udp --dport 443 -j DROP
    done
    echo -n "disabled" > $status_file
}

_get_time_as_integer() {
  time=$1

  hour=$(echo $time | cut -d: -f 1)
  minute=$(echo $time | cut -d: -f 2)

  echo "$hour * 100 + $minute" | bc
}

_get_start_time(){
    # expected format: 07:00,10:00
    time_str=$1

    time_start=$(echo $time_str | cut -d, -f 1)
    _get_time_as_integer $time_start
}

_get_stop_time() {
    #expected format: 07:00,10:00
    time_str=$1

    time_stop=$(echo $time_str | cut -d, -f 2)
    _get_time_as_integer $time_stop
}

get_timetable() {

do_activate=0
for value in $TIMETABLE
    do
    start=$(_get_start_time $value)
    stop=$(_get_stop_time $value)
    cur_time=$(_get_time_as_integer $NOW)
    if [ $start -lt $cur_time ]; then
        if [ $cur_time -lt $stop ]; then
           do_activate=1
        fi
    fi
done

cur_status=$(cat $status_file)
if [ $do_activate ]; then
    if [ "$cur_status" = "enabled" ]; then
        echo "firewall already activated"
    else
       echo "activating firewall"
       enable_firewall
    fi
else
    if [ "$cur_status" = "enabled" ]; then
       echo "deactivating firewall"
       disable_firewall
    else
        echo "firewall already deactivated"
    fi
fi
}

case $1 in
    start) enable_firewall
           exit 0;;
    stop) disable_firewall
          exit 0;;
    timetable) get_timetable
               exit 0;;
    status) echo "firewall rules are $(cat $status_file)";;
    *) echo "Use: $0 [start|stop|timetable|status]"
       exit 0
esac

exit 0

Agora os horário de bloqueio ficam na variável TIMETABLE e no format "<horário início HH:MM>,<horário fim HH:MM>".  O firewall permite um direto "start" e "stop" pra ativar, assim como um "status".  Crie alguma funções com o "_" no início, pra seguir um pouco o padrão do python de funções internas/privadas.

Seu funcionamento agora ficou muito bom e fácil, pra desespero dos aborrecentes.

root@OpenWrt:/usr/lib/scripts# ls
firewall.sh
root@OpenWrt:/usr/lib/scripts# ./firewall.sh status
firewall rules are disabled
root@OpenWrt:/usr/lib/scripts# ./firewall.sh timetable
activating firewall
Enabling firewall
iptables -I INPUT 1 -p tcp -m string --algo bm --string youtubei.googleapis.com -j DROP
iptables -I INPUT 2 -p tcp -m string --algo bm --string googlevideo.com -j DROP
iptables -I INPUT 3 -p tcp -m string --algo bm --string ytimg-edge-static.l.google.com -j DROP
iptables -I INPUT 4 -p tcp -m string --algo bm --string i.ytimg.com -j DROP
iptables -I INPUT 5 -p tcp -m string --algo bm --string youtube-ui.l.google.com -j DROP
iptables -I INPUT 6 -p tcp -m string --algo bm --string www.youtube.com -j DROP
iptables -I INPUT 7 -p tcp -m string --algo bm --string googleapis.l.google.com -j DROP
iptables -I INPUT 8 -p tcp -m string --algo bm --string youtubei.googleapis.com -j DROP
iptables -I INPUT 9 -p tcp -m string --algo bm --string video-stats.l.google.com -j DROP
iptables -I INPUT 10 -p tcp -m string --algo bm --string ytimg-edge-static.l.google.com -j DROP
iptables -I INPUT 11 -p udp -m string --algo bm --string youtubei.googleapis.com -j DROP
iptables -I INPUT 12 -p udp -m string --algo bm --string googlevideo.com -j DROP
iptables -I INPUT 13 -p udp -m string --algo bm --string ytimg-edge-static.l.google.com -j DROP
iptables -I INPUT 14 -p udp -m string --algo bm --string i.ytimg.com -j DROP
iptables -I INPUT 15 -p udp -m string --algo bm --string youtube-ui.l.google.com -j DROP
iptables -I INPUT 16 -p udp -m string --algo bm --string www.youtube.com -j DROP
iptables -I INPUT 17 -p udp -m string --algo bm --string googleapis.l.google.com -j DROP
iptables -I INPUT 18 -p udp -m string --algo bm --string youtubei.googleapis.com -j DROP
iptables -I INPUT 19 -p udp -m string --algo bm --string video-stats.l.google.com -j DROP
iptables -I INPUT 20 -p udp -m string --algo bm --string ytimg-edge-static.l.google.com -j DROP
iptables -I INPUT 21 -p udp --sport 443 -j DROP
iptables -I INPUT 22 -p udp --dport 443 -j DROP
iptables -I FORWARD 1 -p tcp -m string --algo bm --string youtubei.googleapis.com -j DROP
iptables -I FORWARD 2 -p tcp -m string --algo bm --string googlevideo.com -j DROP
iptables -I FORWARD 3 -p tcp -m string --algo bm --string ytimg-edge-static.l.google.com -j DROP
iptables -I FORWARD 4 -p tcp -m string --algo bm --string i.ytimg.com -j DROP
iptables -I FORWARD 5 -p tcp -m string --algo bm --string youtube-ui.l.google.com -j DROP
iptables -I FORWARD 6 -p tcp -m string --algo bm --string www.youtube.com -j DROP
iptables -I FORWARD 7 -p tcp -m string --algo bm --string googleapis.l.google.com -j DROP
iptables -I FORWARD 8 -p tcp -m string --algo bm --string youtubei.googleapis.com -j DROP
iptables -I FORWARD 9 -p tcp -m string --algo bm --string video-stats.l.google.com -j DROP
iptables -I FORWARD 10 -p tcp -m string --algo bm --string ytimg-edge-static.l.google.com -j DROP
iptables -I FORWARD 11 -p udp -m string --algo bm --string youtubei.googleapis.com -j DROP
iptables -I FORWARD 12 -p udp -m string --algo bm --string googlevideo.com -j DROP
iptables -I FORWARD 13 -p udp -m string --algo bm --string ytimg-edge-static.l.google.com -j DROP
iptables -I FORWARD 14 -p udp -m string --algo bm --string i.ytimg.com -j DROP
iptables -I FORWARD 15 -p udp -m string --algo bm --string youtube-ui.l.google.com -j DROP
iptables -I FORWARD 16 -p udp -m string --algo bm --string www.youtube.com -j DROP
iptables -I FORWARD 17 -p udp -m string --algo bm --string googleapis.l.google.com -j DROP
iptables -I FORWARD 18 -p udp -m string --algo bm --string youtubei.googleapis.com -j DROP
iptables -I FORWARD 19 -p udp -m string --algo bm --string video-stats.l.google.com -j DROP
iptables -I FORWARD 20 -p udp -m string --algo bm --string ytimg-edge-static.l.google.com -j DROP
iptables -I FORWARD 21 -p udp --sport 443 -j DROP
iptables -I FORWARD 22 -p udp --dport 443 -j DROP
iptables -I OUTPUT 1 -p tcp -m string --algo bm --string youtubei.googleapis.com -j DROP
iptables -I OUTPUT 2 -p tcp -m string --algo bm --string googlevideo.com -j DROP
iptables -I OUTPUT 3 -p tcp -m string --algo bm --string ytimg-edge-static.l.google.com -j DROP
iptables -I OUTPUT 4 -p tcp -m string --algo bm --string i.ytimg.com -j DROP
iptables -I OUTPUT 5 -p tcp -m string --algo bm --string youtube-ui.l.google.com -j DROP
iptables -I OUTPUT 6 -p tcp -m string --algo bm --string www.youtube.com -j DROP
iptables -I OUTPUT 7 -p tcp -m string --algo bm --string googleapis.l.google.com -j DROP
iptables -I OUTPUT 8 -p tcp -m string --algo bm --string youtubei.googleapis.com -j DROP
iptables -I OUTPUT 9 -p tcp -m string --algo bm --string video-stats.l.google.com -j DROP
iptables -I OUTPUT 10 -p tcp -m string --algo bm --string ytimg-edge-static.l.google.com -j DROP
iptables -I OUTPUT 11 -p udp -m string --algo bm --string youtubei.googleapis.com -j DROP
iptables -I OUTPUT 12 -p udp -m string --algo bm --string googlevideo.com -j DROP
iptables -I OUTPUT 13 -p udp -m string --algo bm --string ytimg-edge-static.l.google.com -j DROP
iptables -I OUTPUT 14 -p udp -m string --algo bm --string i.ytimg.com -j DROP
iptables -I OUTPUT 15 -p udp -m string --algo bm --string youtube-ui.l.google.com -j DROP
iptables -I OUTPUT 16 -p udp -m string --algo bm --string www.youtube.com -j DROP
iptables -I OUTPUT 17 -p udp -m string --algo bm --string googleapis.l.google.com -j DROP
iptables -I OUTPUT 18 -p udp -m string --algo bm --string youtubei.googleapis.com -j DROP
iptables -I OUTPUT 19 -p udp -m string --algo bm --string video-stats.l.google.com -j DROP
iptables -I OUTPUT 20 -p udp -m string --algo bm --string ytimg-edge-static.l.google.com -j DROP
iptables -I OUTPUT 21 -p udp --sport 443 -j DROP
iptables -I OUTPUT 22 -p udp --dport 443 -j DROP
root@OpenWrt:/usr/lib/scripts# ./firewall.sh timetable
firewall already activated
root@OpenWrt:/usr/lib/scripts# ./firewall.sh status
firewall rules are enabled
root@OpenWrt:/usr/lib/scripts# date
Sun Dec 19 13:51:32 CET 2021

Boa diversão.  Ou não caso seja o aborrescente lendo esse artigo pra descobrir o porquê seu YouTube parou de funcionar.

No roadmap: incluir TikTok e Instagram.

UPDATE: eu por fim criei um repositório no github pra ficar mais fácil a manutenção: https://github.com/helioloureiro/opewrt-youtube-blocker

  1. Shell das trincheiras no Tchelinux
  2. Uma conversa introdutória sobre shell scripts com o prof. Juliano
  3. Usando curl pra monitorar um site
  4. A dica mais preciosa de shell scripts dos últimos tempos

Page 1 of 3

  • 1
  • 2
  • 3

Estatísticas

  • Users 2
  • Articles 457
  • Articles View Hits 3236979

Imagem aleatória