Category Archives: bash

Fahrenheit to Celsius

Ieri faceva così caldo che non vi dico; proprio da solstizio. In questi casi l’idea di viaggiare con il bus è pessima se capita che i finestrini non si possono aprire e l’impianto di condizionamento non funzioni. A peggiorare il tutto il mio giovane compagno di sventura legge le brekkiniuss sul telefono: in Arizona fa così caldo che gli aerei non possono decollare, 120 gradi Fahrenheit.

Uh! peggio di noi, forse; quanto fa? Velocissimo con una googlata, 48°C.

Ma mi sono preso la rivincita; o almeno ci ho provato. Come fai a passare da una scala all’altra, basta uno script per quella formula semplicissima… 😊

Ora sembra che io sia prevenuto su certe cose come Micro$oft, la scuola, lo zeitgeist tutto ma la soluzione che mi ha prontamente fornito —N.B.: quelli di una certa età deboli di cuore valutino se continuare a leggere, avvisati nèh!— non l’avrei mai immaginata: ha usato un foglio di calcolo, tipo Excel 😯

Io non ero attrezzato al momento ma appena giunti a destinazione l’ho indottrinato, come si deve fare, o si dovrebbe o –almeno– si potrebbe. Basta uno script Bash, con Linux, ovvio.

f2c

#!/bin/bash
if [[ $# -eq 0 ]]; then
    exit 2
fi
    
F=$1
let C="$((($F-32) * 5 / 9))"
echo $F"°F ->" $C"°C"

e per la conversione inversa

c2f

#!/bin/bash
if [[ $# -eq 0 ]]; then
    exit 2
fi
    
C=$1
let F="$(($C * 9 / 5 + 32))"
echo $C"°C ->" $F"°F"

Sì c’è un arrotondamento, si usano gli interi, troncando. Ma volendo essere più precisi ci sono tanti linguaggi –parte lasciata come esercizio 😜 Anche perché qui fa molto caldo 😊

Aggiornamento: l’amico Flavio, the Man from Mars cinguettaGuida per l’Utente del C64 pag. 35. Ai tempi del C64 la conversione °F/°C era già un classico. Il foglio di calcolo è un’esagerazione!
E sì, io sono più vecchio, allora ero alle prese con il Fortran per le stesse cose che adesso vedo e rivedo con Python. Niente C64 ma ho pasticciato con il Vic20 (in Forth).
Tutti d’accordo sull’esagerazione. Non serve Excel, basta VisiCalc 😉

Aggiornamento: lunga conversazione con il giovane amico; ha ragione lui, sono stato parziale, con il telefono mica puoi fare certe cose…
Vero anche che –ma non apriamo un’altra tirata 😊
CMQ (cit.) un modo veloce, disponibile per tutti, al volo:

js-repl
Ah! sembra che la notizia sia confermata.

:mrgreen:

Spazi nei nomi dei files

Anche se non è vero che con Linux si usa sempre il terminale a volte –uh! spesso– è comodo, più semplice e veloce 😎 Poi, certo, quelli abituati alla Finestra Sghemba™ pensano che siamo rimasti agli anni ’80, quando ero ggiovane 😜

Con il terminale capita che i ggiovani (e gli emeriti che se lo sono dimenticato) fanno cose che –anche se si possono fare– poi mandano in errore gli script fatti dai vekki (hey, it’s me!). Per esempio dare ai files nomi contenenti spazi 😡

Ma niente panico (cit.) anche se scripts contenti cp e/o mv non funzionano sono solo one statement away. Ecco come faccio io (csp.sh):

OLDIFS="$IFS"
IFS=""
for f in $@ 
    do
      if [[ -f $f ]]; then
        echo "Processing file $f"
      fi
    done
IFS=$OLDIFS

Da provare, questo è il contenuto della directory

ed ecco:

OK 😁
Ma se non c’è bash, sapete quelli con la finestra di cui si diceva… Uh! on credo che loro siano invogliati a usare queste cose (se non costretti) ma in questo caso si può usare un linguaggio di scripting, ce ne sono tanti, per esempio Python:

#!/usr/bin/python3
import sys, os

for f in sys.argv[1:]:
    if os.path.isfile(f): 
        print("processing file", f)

OK 😁
Ovviamente gli scripts veri saranno resi eseguibili, via chmod (o in un modo più barocco per quelli meno fortunati ma mainstream).

:mrgreen:

Variabili d’ambiente (environment)

Quando si dice la serendipità! 💥
Un meraviglioso post di Julia b0rk Evans mi fornisce lo spunto per un post che diventerà presto (ma non subito) utile con la telenovela su JavaScript.

Mi sa che l’argomento viene visto in modo diverso da Linux e Windows. Comincio con Linux, anche perché è quello che 1) rockz! 🚀 ; e 2) il mio OS 💥.

Ci sono tante variabili predefinite, per esempio USER:

Posso definirne di nuove, per esempio nel terminale:

Così definita è una variabile locale al terminale che l’ha definita. Posso verificarlo con lo script vv.sh

echo $MYVAR

Non viene vista perché è locale al terminale. Per renderla globale (nel senso che sarà precisato tra poco) bisogna espertarla:

Apro uno nuovo terminale (con Ctrl-Alt-T o utilizzando il tasto destro del mouse all’interno del gestore dei files e selezionando “Apri nel terminale”) MYVAR non risulta definita:

Questo perché il nuovo terminale è indipendente da quello in cui la variabile MYVAR è stata definita.

Se invece dal terminale originario apro un terminale figlio (child), così:

MYVAR c’è come previsto. OK, con questo dovrebbe aver chiarito cosa s’intende per locale e globale.
Quando una variabile è davvero importane si può definire in uno dei file di configurazione, nel caso più normale ~/.bashrc.

Tutto questo per poterla usare negli script, ecco per esempio con Python:

import os
print(os.getenv("USER"))
print(os.getenv("MYVAR"))

E, come vedremo prossimamente con NodeJS:

console.log(process.env["USER"]);
console.log(process.env["MYVAR"]);

Windows

Io sono negato con Windows 10 ma sono riuscito a fare questo:

Per aprire il terminale che li si chiama Prompt dei comandi (o qualcosa di simile) ci sono diverse possibilità:

  • tasto Windows + S apre cerca; scrivere cmd + Invio;
  • tasto Windows + X apre il menu; selezionare findestra dei comandi (o qualcosa di simile);
  • tasto Windows + R apre una finestra per ricevere i comandi; scrivere cmd + Invio;

È possibile aprire quante finestre si vuole ma le variabili settate sono visibili solo nella finestra in cui sono state definite. A differenza di Linux non c’è distinzione tra maiuscolo e minuscolo e invece del $ iniziale il nome dev’essere riferito racchiudendolo tra %.
Inoltre l’history dei comandi viene cancellata quando si chiude la finestra.
Siccome non uso mai Windows forse ci sono altre cose che non so; suggerimenti benvenuti 😊

Argomenti sulla linea di comando
Lo vedremo anche questo prossimamente ma rispondo a una richiesta via mail. Come i normali linguaggi anche con NodeJS è possibile passare argomenti allo script che si vuole eseguire; ecco a.js:

args = process.argv
console.log(args.length)
console.log(args)
console.log(args[2])

:mrgreen:

Prompt Symbol personalizzato

c5-xxeguoamvabf

Un hack senza troppo senso ma:

  • ogni tanto ci vuole;
  • è un sottoprodotto di un’altra cosa, più seria (o seriosa).

È possibile cambiare il prompt del terminale in modo semplice? Certo! ecco:

p0

Quando si chiude il terminale e se ne apre un altro torna quello normale, definito in ~/.bashrc.
OK 😄
È possibile con uno script renderlo più generale, personalizzarlo a seconda dei casi e dell’umore? Sì, ha richiesto più tempo di quanto previsto (fondamentale l’aiuto della mia amica _s 😄). Ecco il risultato.
Per prima cosa occorre definire un alias:

alias psp='source ps_p $1 $2'

Se s’intende usare il comando in futuro l’alias va messo in ~/.bash_aliases (o –meno standard– in ~/.bashrc).

E questo è lo script ps_p, da mettere in ~/bin:

#!/bin/bash
function ps_p() {
    P=$1 #prompt . : string
    C=$2 #color y r

    if [ X$C == Xy ]; then
        color=33m #yellow
    else
        color=31m #red
    fi

    if [ $P == "." ]; then
        PS1="* \e[1;$color\W\e[m * "
    elif [ $P == ":" ]; then
        PS1="* \e[1;$color\w\e[m * "
    else
        PS1="* \e[1;$color$P\e[m * "
    fi
}

ps_p $1 $2

Eccolo all’opera:

p1

L’alias si rende necessario per rendere persistente (entro il terminale corrente) il nuovo prompt, come si vede dall’immagine.
Per un testo arbitrario funziona solo per parole singole, niente spazi.
Lo sappiamo che si potrebbe generalizzare, ma serve? davvero? e se arriva teh Boss? 👿
La shebang (la prima riga) di ps_p non serve, lasciata perché ce l’hanno tutti (kwasy tutty).

 Con binassione  Combinazione anche Randall… qui.

:mrgreen:

aqq – apri questi qui con Firefox

istock

Un post (-icino) che arriva da uno scambio di tweets e mails con l’amico CS –sapete che ha un blog nuovo di pakka? qui.
Siccome forse può interessare anche altri posto qui la risposta. Vale solo per Linux, ultimamente ho visto che c’è ancora chi preferisce qull’altro OS, quello con la finestra sghemba, sigh 😡 Per loro si potrebbe fare la versione Python 😉 No, quella C# no! 👿

Ho un file con un elenco di URLs da visualizzare nel blowser; io uso Firefox ma ovviamente è immediato cambiarlo con un altro (lasciato come esercizio). Il file elenco viene dal plugin di CS, quello che vi racconta nel suo blog.
In realtà il plugin produce files più completi ma estrarre gli URLs è immediato. E forse lo faccio solo io per la mia disorganizzazione: in genere ho la pagina di Twitter aperta ma la guardo solo nei momenti di pausa (quelli in cui i più tosti usano il pomodoro) e non approfondisco, prendo solo appunti; finora usavo un file di testo ma il plugin di CS è molto più efficiente. Poi a una certa ora, quando per stanchezza mentale non riesco più a combinare niente di buono, apro i files dell’elenco.

Lo script bash è semplicissimo; vi racconto come ci sono arrivato. Quando il gioco si fa duro (inizio-cit.) io ricorro a Stack Overflow. Oggi qui: Read a file line by line assigning the value to a variable.

La risposta che utilizzo è la seconda, ecco la mia personalizzazione:

#!/bin/bash
filename="$1"
while read -r line
do
    name="$line"
    if [ "$name" != "" ]; then
        echo "Name read from file - $name"
    fi
done < "$filename"

(aggiornamento: corretta la shebang)

che applicato al file di testo txt

uno
  due
    tre
    
   cinque

produce

a0

Notare che la riga vuota sia saltata e come vengano ignorati gli spazi e tab iniziali e finali; sono condizioni che non dovrebbero capitare nel caso in esame ma non si sa mai cosa ci riserva il futuro (e la prossima versione).

OK 😄 applico quanto appreso al caso reale. Un esempio del file degli URLs, urls-list:

ul

Nota: mettendo il testo del file WordPress visualizza i cinguettii e rende attivi gli URLs; poi indago se c’è la possibilità di disabilitarli.

Lo script aqq-b:

#!/usr/bin/bash
filename="$1"
while read -r line
do
    url="$line"
    if [ "$url" != "" ]; then
        firefox "$url"
    fi
done < "$filename"

E, kwasy-magia:

a1

🚀 Il resto ve lo racconta CS vero? 🎶 🎵 🍓

:mrgreen:

Bash – elencare solo i files

nikon-small-world-head-of-a-skinbow-zebrafish-larvae

È solo un gioco, di quelli senza senso, ma ecco un quiz su Bash o shells affini: qual è l’opzione per elencare solo i files e non le directories?
Uh! ce l’ho qui sulla punta della lingua, ho detto incautamente. Prova -f o -F o -t o -T. No fai ls --help. Azt! no 👿

Poi stante che quando il gioco si fa duro (inizio-cit.) e anch’io ci provo. Googlando un po’ perché mica è facile.

Vero che c’è il comando run-parts che run scripts or programs in a directory.

Sì, ecco la mia interpretazione; apre il file .html precedentemente salvato in locale con Firefox (per esempio quelli di Stack Overflow), funziona anche con nomi con spazi, insomma sarebbe OK.

#!/bin/bash

C=$1
firefox "$(run-parts --list --regex "^$C.*" .)"

Ma l’idea iniziale era di usare ls, comando cui sono affezionato, da trent’anni 😜

Si può fare! (cit.), ecco uff:

#!/bin/bash

C="$1*"
firefox "$(find ./$C -maxdepth 0 -type f)"

sì 😜 ho barato: niente ls ma find –sono affezionato anche a quello 😜

lsf

:mrgreen:

Semplificare l’inserimento di emoji da tastiera

giphotostock

Non ha la pretesa di essere un post serio. E poi non funziona da telefono e allora non interessa the lion share dei possibili utenti; qui dice Cina: China now has 731 million internet users, 95% access from their phones ma ho da poco sbirciato un gruppo di programmatori solo Web, quasi solo JavaScript, principalmente per il mobile.
Anzi i test vengono svolti (quasi) solo su dispositivi Android in verticale. Avevo salvato un link molto divertente (preso da Facebook) ma non riesco a ritrovarlo 😡

emo

Nell’immagine ci sono un po’ di faccine di quelle che se non se ne spruzza un paio per post (per un tweet ne basta una) sembra una cosa non finita. Si possono facilmente selezionare da un ricco catalogo sempre a portata di click ma sapete, io sono vecchio.
Approfittando del fatto che gira e toira (pron. gira e tuira, sarebbe gira e mescola, come quando si fa la polenta) sono sempre le stesse ecco uno script facile-facile e personalizzabile.

#!/bin/bash
function _e {
    case $1 in
        al*) echo -n "👽 " | xclip -f -selection clipboard ;;
        cu*) echo -n "❤️ " | xclip -f -selection clipboard ;;
        ev*) echo -n "👿 " | xclip -f -selection clipboard ;;
        fl*) echo -n "🌺 " | xclip -f -selection clipboard ;;
        fr*) echo -n "🍓 " | xclip -f -selection clipboard ;;
        gr*) echo -n "😄 " | xclip -f -selection clipboard ;;
        id*) echo -n "💡 " | xclip -f -selection clipboard ;;
        li*) echo -n "😜 " | xclip -f -selection clipboard ;;
        lo*) echo -n "😊 " | xclip -f -selection clipboard ;;
        mi*) echo -n "🚀 " | xclip -f -selection clipboard ;;
        oo*) echo -n "😯 " | xclip -f -selection clipboard ;;
        ra*) echo -n "🍇 " | xclip -f -selection clipboard ;;
        ro*) echo -n "🤖 " | xclip -f -selection clipboard ;;
        st*) echo -n "😇 " | xclip -f -selection clipboard ;;    
        tr*) echo -n "😡 " | xclip -f -selection clipboard ;;
        tu*) echo -n "🌷 " | xclip -f -selection clipboard ;;
    esac
}

_e $1
echo

OK, xclip; è tutto lì. Per esempio se digitate:

e0

l’echo finisce nella clipboard; potete verificare con

e1

Ahemmm… scopro adesso che si può semplificare (della serie RTFM 👿)

e2

Quindi lo script consente di inserire nella clipboard di X (quella solita) pronte per essere incollate le faccine elencate dalle sigle mnemoniche (almeno per me; sono pigro e scrivere evil o fragola è troppo impegnativo quando bastano ev e fr) che sono poi quelle (ingrandite) nell’immagine lassù.

Si può usare, lo userò? Chissà… 😜

:mrgreen:

RE – espressioni regolari – un esempio, anzi due; vecchi ma OK

pop1

Il blog di John D. Cook spesso scatena l’ispirazione. Come questo post sulle espressioni regolari, ognuno le fa a modo suo (io per tentativi), queste sono vecchie ma d’autore. Come è vecchio il post (allora il blog si chiamava the Endeavour –il Tentativo– per un motivo che dovete scoprire da soli; e non è quel che pensate) ma rilanciato su Twitter.

The first problem is to produce a list of all English words that contain all five vowels exactly once and in alphabetical order.

Anche se si potrebbe scrivere tutto nel terminale il consiglio è di creare il file alphavowels:

^[^aeiou]*a[^aeiou]*e[^aeiou]*i[^aeiou]*o[^aeiou]*u[^aeiou]*$

e poi lanciare grep. John usa egrep ma –ehi! siamo nel ’17!– l’help di grep dice:

“egrep” significa “grep -E”, “fgrep” significa “grep -F”.
L’invocazione diretta come “egrep” o “fgrep” è deprecata.

E poi il dizionario, almeno per Ubuntu, non si trova dove indicato da John:

j0

Ripasso per me, per nostalgia: i dizionari sono, come Unix prescriveva, file di testo ASCII:

j1

anzi no, ormai Unicode

j2

ma tutto questo è kwasy OT, torno al dunque. Il comando modificato è quindi grep -E -f alphavowels /usr/share/dict/american-english che produce

j3

molte meno di quelle ottenute da John ma la via è quella. Chissà in italiano?

j4

ahemmmm… no, non ne abbiamo 😦

The second problem is to produce a list of all English words of at least six letters with letters appearing in increasing alphabetical order.

The book creates a regular expression named monotonic

^a?b?c?d?e?f?g?h?i?j?k?l?m?n?o?p?q?r?s?t?u?v?w?x?y?z?$

Cerchiamo le parole lunghe almeno 6 caratteri: grep -E -f monotonic /usr/share/dict/american-english | grep '......' e abbiamo

j5

anche qui meno di quelle citate nel post.
Chissà se in italiano…

j6

niente con 6 caratteri, 3 con 5 e 12 con 4.
Ma un momento, manca qualcosa?

j7

Uh! dovrei cambiare nome, quello usato fuori dal Web; ma non risulta neanche il kilo del SI [1]. Continuerò come sempre.
Disclaimer: adoro queste cose ma non è così grave; posso smettere quando voglio; probabilmente; forse… 😳

:mrgreen:



1. kwasy, ricordo che Massimo mi ha già ripreso sull’argomento; forse dovrei scancellare.

Numeri, cambiare base

space_stars_cosmic

Aggiornamento: il post è stato modificato in più punti grazie agli aiuti dei miei amici (sì come Ringo dei Fab4, vedi in fondo) 😀

Un po’ di bash è quello che ci vuole per l’influenza, vero? Almeno ci provo.

Comincio con una cosa semplicissima, trasformare un numero (intero) decimale in esadecimale, ecco 2hex:

#!/bin/bash
echo "obase=16; $1" | bc

Dopo averlo abilitato (con chmod +x 2hex) e averlo spostato in ~/bin ecco:

b0

Questi sono numeri speciali per quelli come me che arrivano dal Fortran 😉 –OK, anche per altri; per quasi tutti.

L’operazione inversa 2dec è un po’ più complessa, bc pretende l’uso del maiuscolo, ma –ke ku c’è tr:

#!/bin/bash
echo "ibase=16;$(echo $1 | tr '[:lower:]' '[:upper:]')" | bc

Aggiormamento #2: ripristinata la versione originaria (questa qui sopra) per ragioni didattiche; la migliore resta ovviamente quella che segue, quella di Flavio.

Aggiornamento: come dice Flavio, the Man from Mars (da seguire qui e qui) si può semplificare, senza scomodare tr:

#!/bin/bash
echo "ibase=16;${1^^}" | bc

b1

A volte serve il binario; e si può partire da un numero decimale o esadecimale. Facciamo che –al solito– il numero è decimale tranne quando inizia con 0x (o 0X). Ecco allora 2bin:

#!/bin/bash
X=$(echo $1 | grep -i x)
case "$X"t in
    t) echo "obase=2; $1" | bc ;;
    *) echo "ibase=16; obase=2; $1" | sed s/0X//I | bc ;;
esac

b2

Adesso b2d, da binario a decimale:

#!/bin/bash
echo "ibase=2; $1" | bc

b3

Aggiornamento: da questo punto in poi il post è nuovo, sostituisce la versione precedente con lamentela per carenze mia (RTFM!). Grazie all’amico f_126_ck.

Da binario a esadecimale (b2x):

#!/bin/bash
echo "obase=16; ibase=2; $1" | bc

b7

Il mio errore era di settare ibase prima di obase. Così facendo avrei dovuto tener conto della base appena immessa per settare obase; invece credevo –erroneamente– che le due variabili fossero sempre da indicare in decimale. Finito il post controllo di non aver scritto qualcosa in proposito nel blog 😳

Ho pensato dapprima di lasciare (indicandola come superata perché errata) la versione precedente ma genera solo confusione, senza aggiungere informazione.

E sì: proprio come si dice qui.

:mrgreen:

Trovare i files cambiati recentemente

knuth-c31b

Non dovrebbe capitare mai ma conviene tener conto di Murphy, non si sa mai.
Non so voi ma a noi (ho un collaboratore che poi vi dico…) a volte capita di salvare un documento e poi non ricordare dov’è.
Recentemente nel Web è comparso questo post 17 Unix tricks for a happy 2017.
C’è un po’ di tutto, qualche dritta è davvero semplice (quelle che già si sanno) ma l’undicesima è sexy. Assay.

11: Finding recently changed files
An alias like the one below will report on the most recently modified files within the current directory.

Ma ha un problema —ioho: solo per la directory (cartella) corrente. Per renderla usabile ha bisogno di qualche hack. Alla fine eco il risultato (ulm):

N=${1:-5}
find $HOME/* -type f -printf '%TY-%Tm-%Td %TT %p\n' | sort -r | head --lines=$N

ulm

Rispetto alla versione pubblicata da Computerworld le variazioni sono la directory che da . diventa $HOME/* e il numero di righe da scrivere.

Ecco, questo è un altro hack che –scommettiamo?– pochi conoscono; per fortuna c’è Stack Overflow: Ternary operator (?:) in Bash.
Ah! mai fermarsi alla prima risposta, nel nostro caso vale la terza, quella di nemesisfixx (rockz!) 😀
Detto in parole comprensibili anche a me: se c’è il primo parametro —$1— a N viene assegnato quel valore; altrimenti N = 5. Provate a scriverla con if… minimo 5 righe 😳

E adesso provate a farla con Windows no dai in questo periodo siamo tutti più buoni (& fluenzati, probabilmente). Uh! 𝕒𝕦𝕘𝕦𝕣𝕚 😀 :mrgreen: