Bash - Bourne Again SHell

Ultimo aggiornamento: 15/45/2024 alle 14:45:14

Indice
  1. Introduzione
    1. Esercizi
      1. Terminale e Cellulari
      2. Primi passi con i comandi
  2. Comandi Principali
    1. man - mostra a schermo il manuale di un comando
    2. ls - elenca il contenuto delle directory
    3. mkdir - creare una directory
    4. cd - Cambiare directory
    5. pwd - Stampa la directory di lavoro
    6. echo - stampa testo nella finestra del terminale
    7. > - reindirizza lo stdout
    8. cat - legge un file, crea un file e concatena i file
    9. | - Tubo (pipe)
    10. grep - ricerca
    11. mv e cp - spostare, rinominare e copiare file
    12. clear - pulisce la finestra del terminale
    13. history - elenca i comandi più recenti
    14. exit - uscire dalla shell
    15. wget - download di file da internet
    16. curl - carica pagine web
  3. Esercizio - puzzle.sh
  4. Per approfondire

Introduzione

La maggior parte delle applicazioni utilizza un’interfaccia grafica (GUI - Graphical User Interface) per interagire con l’utente. Il flusso tipico di lavoro consiste nel cliccare sull’icona di un programa, aspettare il caricamento dell’interfaccia grafica ed interagire con essa tramite le icone presentate a schermo. Nel caso fosse necessario inserire del testo il programma provvederà a fornire una casella di testo in cui inserirlo.

Questo tipo di workflow è estremamente intuitivo perchè le azioni sono descritte da immagini e l’utente viene guidato passo passo, ma non permette di effettuare azioni complesse con semplicità. Inoltre l’interoperabilità con altri programmi non è sempre diretta o addirittura possibile.
Facciamo alcuni esempi:

  • Per salvare un documento (già esistente!) il workflow tipico consiste in:
    1. Muovere il mouse su File e fare click
    2. Nel menù a tendina cliccare su Salva
  • Per comprimere un file bisogna:
    1. Fare click destro sul file
    2. Selezionare l’opzione “Comprimi”
    3. Inserire il nome del file compresso nella finestra che si è aperta
    4. Cliccare su Inizia o simili per effettivamente far partire il processo di compressione
  • Supponiamo di avere un file file1.txt contenente un elenco di nomi (ripetuti) e di voler generare un file file2.txt con i nomi ripetuti una singola volta ed ordinati alfabeticamente. Per fare ciò dobbiamo:
    1. Aprire il file
    2. Selezionare tutto il contenuto e copiarlo
    3. Aprire un programma capace di ordinare i nomi o aprire l’estensione apposita dell’editor di testo
    4. Incollare l’elenco di nomi (sperando che la formattazione non generi caratteri strani) ed ordinarli
    5. Eseguire le due operazioni precedenti nuovamente per un programma capace di rimuovere i duplicati
    6. Aprire nuovamente l’editor di testo su un nuovo file o fare ‘Salva con nome’

Per velocizzare queste operazioni molto spesso vengono predisposte delle combinazioni di tasti (e.g. ctrl+s per salvare) o è possibile utilizzare dei programmi per generare delle macro che compiono le operazioni in automatico (e.g. gli auto clicker ) ma questo può semplificare il workflow solo fino ad un certo punto.
La shell (o terminale, la differenza fra i due termini non è rilevante ai fini di questo corso) fornisce un workflow molto più vicino al funzionamento del computer, quindi più diretto e veloce, al costo di essere meno intuitivo. Avendo un’interfaccia standard di input ed output è inoltre possibile far comunicare diversi programmi in modo diretto. Per esempio, utilizzando la shell e programmi pensati per essa, i compiti precedenti verrebbero svolti con i seguenti comandi:

  • Salvare il file (su Vim): premere il tasto esc e digitare :w
  • Comprimere una cartella: tar -czvf nome-cartella-compressa.tar.gz percorso/cartella-file/da-comprimere
  • Ordinare e selezionare i nomi una singola volta: sort file1.txt | uniq \> file2.txt

In parole povere, la shell fornisce un modo veloce, standardizzato e completo per operare sui file.

Esercizi

Terminale e Cellulari

Abbiamo parlato dei pregi e dei difetti per le GUI. Nel caso dei cellulare, avrebbe senso un’interfaccia basata sul terminale? Perchè?

Primi passi con i comandi

Come accennato, i comandi della shell non sono sempre intuitivi (almeno finchè non si entra nell’ottica del loro funzionamento). Fortunatamente esistono siti come https://explainshell.com/ che forniscono una spiegazione dettagliata dei vari comandi. Provate ad inserire i seguenti comandi sul sito e leggere la spiegazione.

  • cat file1.txt | sort | uniq > file2.txt
  • gcc filename.c -lm -Wall -o my\_program.out && my\_program.out
  • rm -rf *
  • find . *.zip -exec unzip {}\\;
  • for a in *.png; do convert ${a} ${a/.png}.jpg; done
  • sudo apt-get update && sudo apt-get upgrade && sudo apt-get autoremove

Non allarmatevi se non capite alla perfezione ogni singolo passaggio, in questo momento l’importante è cercare di avere una comprensione intuitiva di cosa fa ogni singolo pezzo senza concentrsi sui dettagli. La conoscenza specifica la maturerete con calma negli anni se deciderete di seguire un percorso computazionale.

Comandi Principali

A meno di impostazioni particolari, la cartella di partenza della shell è /home/[username]/ (o alternativamente ~) dove [username] è il vostro nome utente, la slash iniziale / indica la radice del file system (la cartella che contiene tutte le cartelle, su windows questa cartella è indicata con C:\\), home indica la cartella omonima che contiene una cartella per ogni utente del computer, la seconda slash / indica l’operazione di entrare nella sottocartella con il nome indicato a destra della slash, username in questo caso.

Se preferite un approccio alternativo basato sul fare più che sul ricordare, valutate l’opzione di seguire uno di questi tutorial che spiegano gli stessi concetti:

  • Linux Journey - The Shell: tutorial standard che consiste in spiegazioni con annessi quiz.
  • Linux Survival: tutorial più strutturato articolato in una serie di livelli a difficoltà crescente.
  • Terminus: gioco testuale di esplorazione in cui i luoghi sono cartelle mentre le azioni files.

Per sicurezza leggete velocemente anche il resto del documento in modo da essere sulla stessa lunghezza d’onda dei vostri compagni di corso.

man - mostra a schermo il manuale di un comando

Il comando man è manuale di utilizzo dei programmi e, di conseguenza, è molto utile quando dovete capire come funziona un comando. Ogni volta che avete un dubbio sull’utilizzo di un comando potete utilizzare man \[comando\] per ottenere una descrizione dettagliata.
Provate a leggere il manuale del comando man digitando man man. Appena siete soddisfatti delle vostre ricerche premete q (quit) per uscire dal manuale.
È possibile cercare all’interno del manuale digitando /\[parola chiave\] ed usando n (next) per scorrere i risultati.

ls - elenca il contenuto delle directory

ls (list files) è probabilmente il comando più comune. Spesso si lavora in una directory e si ha bisogno di sapere quali file vi si trovano. Il comando ls consente di visualizzare rapidamente tutti i file all’interno della directory specificata. L’opzione -a permette di vedere anche i file nascosti mentre l’opzione -l fornisce informazioni aggiuntive.


Esempio di output del comando ls con le varie opzioni sulla macchina virtuale.

mkdir - creare una directory

mkdir (make dirrectory) è un comando utile per creare cartelle. È possibile creare un numero qualsiasi di directory contemporaneamente, il che può accelerare notevolmente il processo.
Create una cartella esercitazione0 immettendo il comando mkdir esercitazione0. Come potete verificare che l’operazione si stata eseguita correttamente?

cd - Cambiare directory

cd (change directory) cambia la directory in cui ci si trova. È l’equivalente del doppio click su una cartella.
Entrate nella cartella appena creata digitando ‘cd esercitazione0`.

pwd - Stampa la directory di lavoro

pwd (print working directory) serve a stampare la directory corrente in cui ci si trova. Utile nel momento in cui non vi ricordate dove vi trovate o all’interno di uno script per assicurarvi di essere nella posizione giusta.
Controllate di essere entrati nella cartella corretta digitando il comando pwd.

echo - stampa testo nella finestra del terminale

echo stampa del testo nella finestra del terminale ed è tipicamente utilizzato negli script di shell e nei file batch per mostrare del testo o delle informazioni sullo schermo.
Per esempio, la linea echo Hello World stamperà la scritta Hello World a terminale.
Una feature interessante di echo è quella di poter stampare il valore di alcune variabili d’ambiente quali HOME e PATH. La prima contiene il percorso della cartella dedicata dell’utente corente mentre la seconda contiene l’elenco di cartelle in cui il sistema operativo andrà alla ricerca dei comandi e dei file quando scrivete sul terminale. Per espandere il contenuto di una variable in bash è necessario premettere il simbolo del dollaro $. Se si volesse utilizzare il carattere $ autonomamente è necessario premettere un ulteriore simbolo di slash chiamato ‘escape’.
Provate a inserire il seguente comando:
echo “Per visualizzare il contenuto della variable PWD è necessario premettere il simbolo $ (esempio: \\$PWD ) in modo tale da poter visualizzare la cartella corrente. In questo caso il contenuto della variabile è $PWD”

Prova a stampare a schermo il valore delle variabili PATH e HOME.

> - reindirizza lo stdout

Il carattere > è l’operatore di reindirizzamento. Esso prende l’output del comando precedente, che normalmente viene visualizzato nel terminale, e lo invia a un file o un programma indicato dall’utente. A titolo di esempio, si prenda echo "contenuto di file1" > file1. In questo caso, crea un file chiamato file1 e vi inserisce la stringa di echo.
Prova ad inviare ad un file path\_env.txt il contenuto della variabile PATH. Come puoi controllare se effettivamente il file è stato creato?

cat - legge un file, crea un file e concatena i file

cat è uno dei comandi più versatili e svolge tre funzioni principali: visualizzare i file, combinarne delle copie e crearne di nuovi.
Prova a leggere il file path\_env.txt per verificare che abbia il contenuto che ci aspettiamo.

| - Tubo (pipe)

Una pipe prende l’output standard di un comando e lo passa come input a un altro. Ricordate l’esempio cat file1.txt | sort | uniq \> file2.txt? In questo caso stavamo combinando tre programmi ed il loro corrispondente output. cat legge il file ‘file1.txt’ mentre | lo manda in input al programma sort che lo ordina. L’output di sort viene quindi rediretto al comando ‘uniq’ (unique) che si occupa di eliminare tutte le linee doppie ed infine il suo output viene reindirizzato sul file ‘file2.txt’.

grep - ricerca

grep (global regular expression print) viene utilizzato per cercare nel contenuto di un file le righe conenenti una serie particolare di caratteri. Solitamente viene utilizzato in insieme al carattere di pipe: ‘cat path_env.txt | grep [stringa da cercare]’.

mv e cp - spostare, rinominare e copiare file

mv (move) è utilizzato per spostare le cartelle ed i file. Rinominare un file equivale a spostarlo nella stessa cartela ma con un nome diverso. cp (copy), al contrario, permette di copiare un file.
Create una cartella dentro a esercitazione0 e chiamatela “bacup” (sic). Usate il comando mv per rinominare la cartella in “backup”: mv bacup backup. Copiate poi il file path\_env.txt dentro la cartella “backup” con il comando cp: cp path\_env.txt backup/path\_env.txt

clear - pulisce la finestra del terminale

clear (pulisci!) serve a cancellare tutti i comandi e l’output precedenti dalla console e dalla finestre del terminale. In questo modo si mantiene pulito il terminale e si rimuove il disordine, in modo da potersi concentrare sui comandi successivi e sul loro output.
Pulite il terminale usando il comando clear.

history - elenca i comandi più recenti

history (storico) permette di visualizzare gli ultimi comandi immessi. Se dopo clear volete ricordarvi quali comandi avete immesso, potete usare il comando history.

exit - uscire dalla shell

Il comando exit chiude una finestra di terminale, termina l’esecuzione di uno script di shell o interrompe una sessione di accesso remoto SSH (ssh, secure shell).

wget - download di file da internet

wget (word wide web get) permette di scaricare file da terminale a partire dal link e salvarli nella cartella corrente.

curl - carica pagine web

curl (client url) permette di caricare il contenuto di pagine web. Uno dei suoi utilizzi principali è quello di accedere a servizi online pensati per essere integrati nel terminale.

Provate ad esempio ad inserire i seguenti comandi:

  • curl wttr.in/Povo per ottenere le previsioni del tempo per Povo.
  • curl cheat.sh/curl per ottenere un formulario per il comando curl.
  • curl cheat.sh/ls per ottenere un formulario per il comando ls.
  • curl cheat.sh/find per ottenere un formulario per il comando find.
  • curl cheat.sh/[comando] per ottenere un formulario di un comando a vostra scelta.
  • curl parrot.live per vedere un’animazione di un pappagallo felice.

Esercizio - puzzle.sh

Copia ed incolla il seguente codice in un file puzzle.sh ed eseguilo con ./puzzle.sh. Lo script si bloccherà dopo poche righe. Cercate di risolvere l’errore modificando solo le righe permesse. Il vostro scopo ultimo è riuscire a leggere la directory segreta alla fine. Buon lavoro!

#!/bin/bash
## NOTE: - per eseguire lo script serve prima il comando 'chmod +x puzzle.sh'
##       - potrebbe servire l'installazione di alcuni programmi
cd dir1
if [ $? -ne 0 ]; then ### non modificare
	exit ### non modificare
fi ### non modificare 
echo ${PWD}>.path1
PATH1_DIR=$(cat ../dir1/.path)
if [ $? -ne 0 ]; then ### non modificare
	exit ### non modificare
fi ### non modificare 
PARENT_PATH_DIR=${PATH1_DIR}"../"
cd ${PARENT_PATH_DIR}
if [ $? -ne 0 ]; then ### non modificare
	exit ### non modificare
fi ### non modificare 
SECRET_DIR="\x2e\x73\x65\x63\x72\x65\x74"
if [ ! -d $(echo -e ${SECRET_DIR}) ]; then
	mkdir $(echo -e ${SECRET_DIR})
fi
if [ $? -ne 0 ]; then ### non modificare
	exit ### non modificare
fi ### non modificare 
cd .f*
if [ $? -ne 0 ]; then ### non modificare
	exit ### non modificare
fi ### non modificare 
eco "41" > .password
SECRET_KEY="\x34\x32"
PASSWORD_PATH=$(echo -e ${SECRET_DIR})"/.passwod"
cd ${PARENT_PATH_DIR}
PASSWORD=$(cat ${PASSWORD_PATH})
if [ $? -ne 0 ]; then ### non modificare
	rm -r $(echo -e ${SECRET_DIR})
	exit ### non modificare
fi ### non modificare 
if [ ${PASSWORD} -eq $(echo -e ${SECRET_KEY}) ]; then
	sl|lolcat
elif [ ${PASSWOD:-0} -eq "41" ]; then
	sl
else
	cowsay -f turtle "Password sbagliata"
fi
rm -r $(echo -e ${SECRET_DIR})

Per approfondire