Scripting for Real Life

Idee per l’utilizzo dello scripting nella vita quotidiana di uno sviluppatore

Questo articolo si propone di presentare l’importanza dello scripting e dell’automazione nella “vita quotidiana” di uno sviluppatore, ovvero, di dimostrare che lo scripting si può rivelare uno strumento molto importante per automatizzare numerosi compiti ripetitivi.

Il plus, a parere di chi scrive, è che lo scripting permette di automatizzare molte operazioni esercitando attivamente la propria capacità di problem solving.

Ci sono molti strumenti che permettono di “bypassare” lo scripting, ma due vantaggi di un semplice script possono essere:

  • permette di imparare attivamente ed esercitare le proprie abilità di programmatore;
  • non richiede l’installazione di alcun nuovo software sul proprio sistema.

Non stiamo sostenendo qui che lo scripting sia la soluzione di ogni problema; suggeriamo, invece, che mediante lo scripting si possano risolvere numerosi problemi con soddisfazione, capendo i principi che vi sottostanno.

Linguaggi di Scripting

Vi sono oggigiorno moltissimi linguaggi di scripting. Non è possibile menzionare qui nemmeno i principali. Ci limitiamo a presentare brevemente tre linguaggi:

  • Bash,
  • PowerShell,
  • Python.

Bash è utilizzabile principalmente su sistemi Unix, ma è disponibile qualche programma che permette di utilizzarlo anche su Windows. PowerShell, viceversa, è integrato nei sistemi Windows, ma è scaricabile anche su numerosi sistemi Unix. Infine, Python: un vero e proprio linguaggio di programmazione, completo e multifunzionale, che, grazie alla sua natura interpretata, si presta benissimo allo scripting.

Bash

Bash (acronimo per Bourne Again SHell, vedi Wikipedia), è una shell GNU. Si indica con lo stesso nome anche la sintassi che si utilizza per impartire comandi alla shell. Si parla in questo senso di Bash come “linguaggio”.

Il vantaggio di Bash è che si trova ormai su pressoché tutti i sistemi Unix. Se si ha a che fare con un server Linux, ad esempio, è facile che vi si troverà installato Bash (o qualche altra shell analoga, come Zsh, che ha una sintassi per molti versi simile e compatibile).

Per che cosa si può utilizzare Bash? Per quasi ogni compito automatizzabile. Vediamo un esempio concreto.

Bash: Esempio

Bash si può utilizzare, ad esempio, per automatizzare il backup di un database.

Immaginiamo, ad esempio, di avere un database MySQL in esecuzione su un server Linux (possiamo immaginare Debian o Ubuntu). Immaginiamo, inoltre, che il backup debba avvenire all’inizio di ogni mese.

Il sistema Linux ci mette a disposizione i cron jobs, dei task che vengono eseguiti automaticamente con una certa scadenza o ciclicità sul sistema.

Possiamo quindi schedulare a cron un task che esegua uno script di backup del database.

Il comando che esegue il backup di un database MySQL è

mysqldump -u [username] –p [password] -h [hostname] [database_name] > [dumpfilename.sql]

Immaginiamo, inoltre, di dover copiare il dump su un altro server, ad esempio un file server usato per l’archiviazione di dati storici. Possiamo eseguire la copia del dump mediante il comando scp:

scp -i [private_key] [username]@[hostname/IP]:[location_in_filesystem]

Cominciamo ad integrare i comandi fin qui visti in uno script:

#!/bin/bash

time=$(date +%Y%m%d%H%M%S)

db_pass=$(cat /home/user/.secret_db_pw_file)

mysqldump -u user –p "${db_pass}" my_database > "/tmp/my_db_dump_${time}.sql"

scp -i /home/user/.ssh/server_key "/tmp/my_db_dump_${time}.sql" user@remote.backup.server:/var/backups

Infine, salviamo lo script in /usr/local/bin, rendiamolo lo script backup.sh eseguibile e aggiungiamo al crontab del database server qualcosa di simile a quanto segue:

0 0 1 * * /usr/local/bin/backup.sh

Ovviamente lo script è modificabile per salvare il backup in modo diverso, ad esempio su un bucket S3 di AWS: basta conoscere i comandi da eseguire e aggiungerli allo script!

PowerShell

PowerShell è una shell disponibile per vari sistemi, sviluppata da Microsoft e molto utilizzata per la gestione dei server Windows. Maggiori informazioni sono disponibili sulla documentazione di Microsoft e su Wikipedia.

PowerShell, a differenza di altre shell, funziona utilizzando oggetti chiamati cmdlets (“command lets”): possiamo quindi immaginare PowerShell come una shell “orientata agli oggetti”. Da Wikipedia:

La differenza fondamentale tra l'approccio Unix e quello di PowerShell risiede nel fatto che piuttosto che creare una "pipeline" (lett. tubo) basata su input ed output testuali, PowerShell fa passare i dati da una cmdlet all'altra come oggetti (dati dotati di una struttura ben precisa).

Possiamo creare uno script PowerShell semplicemente nominando un file con l’estensione .ps1; l’esecuzione si lancia semplicemente richiamando il nome dello script con path relativo o assoluto rispetto alla directory d’esecuzione, ad esempio:

.\my_script.ps1

PowerShell: Esempio

Presentiamo un esempio di script PowerShell che permette di scaricare una serie di file da un server remoto mediante il comando scp.

Immaginiamo di avere un server (diciamo, per facilità, Linux) che archivia una lunga serie di file, il cui nome è prevedibile. Possiamo, specificando maggiormente, immaginare di avere una lista di file ZIP chiamati split.zXX, dove XX indica un numero tra 01 e 99. Eseguire la copia manuale di tutti i file richiede il lancio di 99 comandi scp; se, da un lato, ci sono tool che permettono di utilizzare un’interfaccia grafica per eseguire questa operazione, poche righe di uno script PowerShell ci permettono di raggiungere lo stesso obiettivo, imparare la sintassi del linguaggio ed evitare l’installazione di nuovi tool.

PowerShell (come anche Bash e altri linguaggi) permette l’esecuzione di cicli for. Scriviamo quindi un ciclo for in PowerShell che formatta il nome del file e lo scarica:

for ($i=1; $i -le 99; $i++)
{
         if ($i -le 9)
        {
              $j = "0$i"
        }
        else
        {
             $j = "$i"
        }
        scp -i C:\Users\User\.ssh\server_key user@${SERVER_IP}:/home/user/split.z$j .
}

Salviamo questo ciclo in un file chiamato download.ps1 ed eseguiamolo:

.\download.ps1

Al termine dell’esecuzione, avremo i file salvati nel sistema locale.

Python

Più che un linguaggio di scripting, Python è un linguaggio di programmazione completo e multi-funzionale. Non è questo lo spazio dove presentare il linguaggio in sé, qui vogliamo piuttosto concentrarci sulle sue potenzialità per lo scripting.

Python presenta, a nostro avviso, alcuni vantaggi essenziali nel panorama dei linguaggi di scripting:

  • integra moltissime funzionalità tramite le numerose librerie;
  • si trova installato di default su molti sistemi UNIX;
  • ha una sintassi semplice, essenziale e pulita.

Python può essere usato per moltissimi scopi diversi nell’ambito dello scripting: amministrazione di sistema, gestione di reti, elaborazione di dati, elaborazione di file (sia di testo che immagini). Inoltre, Python è molto usato come linguaggio per l’Intelligenza Artificiale: si hanno quindi molte possibilità di integrare strumenti di IA in uno script in Python.

Python: Esempio

Vediamo un paio di semplici esempi di scripting in Python.

Il primo esempio ci permette di interrogare un endpoint API per ottenere un valore di riferimento, inviando un alert quando viene superata una certa soglia massima o una certa soglia minima.

Immaginiamo che i dati restituiti dall’API abbiano una formato JSON del tipo:

{
          'time': Timestamp,
          'data' : {
                          'key1': Number,
                         'key2': Number,
                         'key3': Number
         }
}

Possiamo allora monitorare il range dei valori restituiti con lo script seguente:

import requests

url = '...'

data = requests.get(url)
data_json = data.json()
rate = data_json["data"]["key3"]

if rate > 50_000:
print("More than 5_000!")
elif rate < 20_000:
print("Less than 2_000!")
else:
print("The value is in the expected range...")

Nel secondo caso, vediamo come modificare dei file usando Python. Supponiamo di voler generare una serie di file in formato JSON. Supponiamo di lavorare con lo stesso formato dell’esempio precedente. Vogliamo generare dei file con il timestamp corrente e dei valori key1, key2, key3 calcolati seguendo una procedura specifica.

import os
import json
from datetime import datetime

def get_val1():
...

def get_val2():
...

def get_val3():
...

if not os.path.exists("files"):
os.mkdir("files")

for i in range(10):
val1 = get_val1()
val2 = get_val2()
val3 = get_val3()

my_json = {
"time": datetime.now(),
"data": {
"key1": val1,
"key2": val2,
"key3": val3
}
}

file_number = f"0{i}"
file_path = f"files/file{file_number}.json"
with open(file_path, "w") as f:
f.write(json.dumps(my_json, default=str))

Speriamo di riuscire a dare con quest’esempio un’idea della complessità dei compiti che si possono svolgere mediante uno script Python. Qui stiamo usando:

  • il modulo os per gestire directory sul filesystem;
  • il modulo json per lavorare con il formato JSON;
  • il modulo datetime per la gestione di date e ore.

Le funzioni get_val1, get_val2 e get_val3 ci permettono di calcolare i valori da salvare nell’oggetto JSON; lo script verifica inoltre che sia presente la directory files nel path da cui viene eseguito e, nel caso in cui non la trova, la crea. Il ciclo for rappresenta poi un ciclo di iterazioni di lavoro su diversi file.

Conclusioni

Questo breve articolo è solo un assaggio di ciò che si può fare mediante lo scripting con un po’ di perseveranza, qualche ricerca sul web e un po’ di inventiva: pochi problemi resistono a una soluzione che combini tali ingredienti.

Continua a leggere altre tech-pills nel nostro tech-blog!