Attenzione! Questa è una Pagina di prova. Le informazioni riportate potrebbero essere incomplete, errate e potenzialmente pericolose. Per contribuire alla realizzazione di questa pagina consultare la discussione di riferimento.

Problemi in questa pagina? Segnalali in questa discussione

Introduzione

Il parsing è la procedura con cui un comando, uno script o più genericamente un programma, analizza le istruzioni che l'utente fornisce quando lo chiama usando il terminale.

Queste istruzioni sono una opportuna combinazione di opzioni e parametri e modificano il comportamento del programma a cui vengono passate.

A esempio, per lanciare il comando ls da terminale una sinossi comune è la seguente:

ls -a -l --color=auto file

Ul generico comando è composto dal nome del comando stesso seguito da una serie di argomenti detti parametri posizionali.
Questi ultimi possono essere suddivisi in alcune categorie logiche:

Il comando precedente è equivalente al seguente:

ls --color=auto -la file 

In questo caso tutte le opzioni corte sono state riunite ed è stato cambiato l'ordine delle opzioni.

Non tutti i comandi accettano un ordine casuale delle opzioni.

La difficoltà del parsing è proprio nel riconoscimento delle varie opzioni e parametri, a prescindere dalla loro posizione nella sintassi della chiamata.

Per agevolare questa procedura, sono disponibili due utili comandi da usare nel terminale:

getopt

getopt analizza una stringa di parametri e ne restituisce una versione canonica e standardizzata che può essere analizzata più facilmente. Questa analisi successiva viene eseguita in un ciclo while, all'interno del quale le varie scelte sono effettuate in un costrutto case.

Pro

Contro

Sintassi

getopt può essere chiamato con tre diverse sintassi:

Le opzioni e rispettivi parametri che possono essere presenti nella stringa options tra parentesi quadre sono i seguenti:

Opzione

Descrizione

-l|--long|--longoptions longopts

Indica che durante il parsing si potranno incontrare opzioni lunghe, i cui nomi vengono specificati nella stringa longopts. Questa stringa può essere racchiusa tra doppi apici e i nomi al suo interno vanno separati con una virgola. Se il nome che indica l'opzione lunga è seguito dai due punti, questa accetta un parametro obbligatorio; se è seguito da una coppia di doppi punti, accetta un parametro facoltativo.

-a|--alternative

Abilita il riconoscimento delle opzioni lunghe nello stile XF86, quindi con un singolo trattino iniziale.

-n|--name progname

Imposta il nome dello script al contenuto della variabile progname.

-q|--quiet

Disabilita l'output automatico degli errori.

-Q|--quiet-output

Disabilita la produzione della stringa normalizzata dei parametri passati allo script, ma gli errori incontrati nel parsing vengono ancora riportati.

Esempi di chiamate al comando

I seguenti esempi mostrano come utilizzare le tre sintassi viste nel paragrafo precedente:

È importante sottolineare che, negli argomenti passati allo script, le opzioni e i relativi parametri rispettano le seguenti regole:

Esempio d'uso

Lo script che segue accetta l'opzione -a senza parametro, l'opzione -b con parametro obbligatorio e l'opzione -c con parametro facoltativo. Sono accettate anche le rispettive varianti lunghe nello stile Gnu (ovvero precedute da due trattini) --a-lunga, --b-lunga e --c-lunga.

#! /bin/bash

getopt --test > /dev/null
if [[ $? -ne 4 ]]; then
    echo "La versione di getopt non è quella del pacchetto utils-linux"
    exit 1
fi

OPZIONI_CORTE=ab:c::
OPZIONI_LUNGHE=a-lunga,b-lunga:,c-lunga::

TEMP=$(getopt --options="$OPZIONI_CORTE" --longoptions="$OPZIONI_LUNGHE" --name "prova_getopt.sh" -- "$@")
if [[ $? -ne 0 ]]; then
    echo "getopt ha fallito il parsing"
    exit 2
fi

echo "Versione canonica dei parametri prodotta da getopt: "$TEMP""

eval set -- "$TEMP"

while true
do
    case "$1" in
        -a|--a-lunga) 
            echo "Opzione '$1', senza argomento."
            shift
            ;;
        -b|--b-lunga) 
            echo "Opzione '$1', con argomento '$2'."
            shift 2
            ;;
        -c|--c-lunga)
            case "$2" in
                "") 
                    echo "Opzione '$1', senza argomento."
                    shift 2
                    ;;
                *)  
                    echo "Option c, con argomento '$2'."
                    shift 2
                    ;;
            esac
            ;;
        --) 
            shift
            break
            ;;
        *) 
            echo "Errore interno!"
            exit  ;;
    esac
done

if [[ $# != 0 ]]
then
    echo "Argomenti rimanenti:"
    for i in "$@"
    do
        echo "--> '$i'"
    done
fi

Supponendo di aver salvato lo script con il nome prova_getopt.sh, di seguito vengono mostrati due differenti modi di chiamarlo e i rispettivi output prodotti:

Considerazioni sull'esempio d'uso

getopts

Pro

Contro

Funzionamento

La sintassi del comando è:

getopts optstring varname [args]

in cui

Parametro

Descrizione

optstring

È una stringa che istruisce il comando relativamente a quali opzioni aspettarsi e quando siano previsti i relativi parametri.

varname

È una stringa che rappresenta il nome della variabile della shell in cui il comando getopts inserisce il valore delle opzioni lette.

args

È una stringa facoltativa. Di default, il comando fa il parsing dei parametri posizionali, cioè della stringa $@; se è presente una stringa args, farà il parsing dei parametri contenuti in quest'ultima.

getopts viene quindi istruito sulle opzioni e gli eventuali parametri che si può aspettare tramite optstring.
La sintassi di questa stringa è molto semplice.

Quindi, se desideriamo che il comando si aspetti di incontrare nel parsing le opzione 'v' ed 'h' senza parametri associati e l'opzione 'f' con un parametro associato, optstring sarebbe uguale a "vhf:" per la modalità verbosa e uguale a ":vhf:" per quella silenziosa.

Per il suo funzionamento, getopts usa le seguenti variabili:

Variabile

Descrizione

OPTIND

È una variabile della shell, che contiene l'indice del parametro posizionale del prossimo argomento da processare. Viene modificata da getopts, che la usa per tenere traccia del proprio stato. Torna utile anche per poter fare uno shift dei parametri posizionali, dopo averli analizzati con getopts.

OPTARG

Se è previsto un parametro, viene impostata al valore si quest'ultimo. Se l'opzione non prevede un parametro, è lasciato vuoto. Se l'opzione passata è sconosciuta, viene impostato al valore dell'opzione.

OPTERR

È una variabile di bash, che può assumere il valore 1 o 0, a seconda che si desideri o meno che la shell mostri il messaggio d'errore generato automaticamente da getopts. Di default è impostata ad 1 e ha senso modificarla solo nella modalità verbosa. Non è supportata in shell quali ksh93, mksh, zsh, or dash.

La gestione del parametro varname e della variabile OPTARG cambia a seconda della modalità in cui si usa il comando ed è riassunta nella seguente tabella:

Modalità verbosa

opzione
non valida

varname è posto uguale al carattere '?'
OPTARG è lasciato vuoto.

parametro obbligatorio
non fornito

varname è posto uguale al carattere '?'
OPTARG è lasciato vuoto e viene stampato un messaggio d'errore.

Modalità silenziosa

opzione
non valida

varname è posto uguale al carattere '?'
OPTARG è posto uguale all'opzione non valida.

parametro obbligatorio
non fornito

varname è posto uguale al carattere ':'
OPTARG è posto uguale all'opzione

Esempi d'uso

Il comando viene generalmente usato all'interno di un ciclo while: a ogni iterazione, legge dalla stringa dei parametri posizionali (o da args se fornito) un'opzione e il suo eventuale parametro; se tutto è corretto, aggiorna le sue variabili interne, secondo quanto visto al punto precedente, e fornisce questi dati all'utente per la loro analisi, che viene svolta all'interno di un costrutto case. Il comando restituisce un exit status uguale a 1, interrompendo il ciclo while, quando incontra il primo parametro opzionale che non corrisponde a una opzione prevista.

Modalità verbosa

Lo script che segue è un esempio di utilizzo del comando nella modalità verbosa. Lo script accetta le opzioni 'a' e 'c' senza parametro e le opzioni 'b' e 'd' con un parametro. Le opzioni 'b' e 'd' non sono implementate, per simulare una situazione frequente nelle fasi iniziali di sviluppo di uno script.

#!/bin/bash

while getopts "ab:cd:" option
do
    case $option in
        a)
            echo "Opzione -$option, senza argomento"
            echo "OPTIND è $OPTIND"
            echo "*** *** ***"
            ;;
        b)
            echo "Opzione -$option, con argomento '"$OPTARG"'"
            echo "OPTIND è $OPTIND"
            echo "*** *** ***"
            ;;
        \?)
            echo "OPTIND è $OPTIND" >&2
            echo "Termino" >&2
            exit 1
            ;;
        *) 
            echo "Opzione non ancora implementata: -$option"
            echo "OPTIND è $OPTIND"
            echo "*** *** ***"
            ;;
    esac
done

shift $((OPTIND - 1))

if [[ $# -ne 0 ]]
then
    echo "Rimangono da analizzare i parametri:"
    for i in "$@"
    do
        echo "--> '$i'"
    done
fi

Supponendo di aver salvato lo script con il nome prova_getopts_verboso.sh, alcuni esempi dell'output generato da questo script sono:

Modalità sileziosa

Lo script seguente è l'analogo del precedente, ma in modalità silenziosa:

#!/usr/bin/env bash

while getopts ":ab:cd:" option;
do
    case $option in
        a)
            echo "Opzione -$option, senza argomento"
            echo "OPTIND è $OPTIND"
            echo "*** *** ***"
            ;;
        b)
            echo "Opzione -$option, con argomento '"$OPTARG"'"
            echo "OPTIND è $OPTIND"
            echo "*** *** ***"
            ;;
        \?)
            echo "Opzione non valida: -$OPTARG" >&2
            echo "OPTIND è $OPTIND" >&2
            echo "Termino" >&2
            exit 1
            ;;
        : )
            echo "-$OPTARG richede un parametro, che non è stato passato" >&2
            echo "OPTIND è $OPTIND" >&2
            echo "Termino" >&2
            exit 1
            ;;
        *)
            echo "Opzione non ancora implementata: -$option"
            echo "OPTIND è $OPTIND"
            echo "*** *** ***"
    esac
done

shift $((OPTIND -1))

if [[ $# -ne 0 ]]
then
    echo "Rimangono da analizzare i parametri:"
    for i in "$@"
    do
        echo "--> '$i'"
    done
fi

Differenze dallo script precedente ci sono solo per opzioni non valide e parametri obbligatori non passati. Se lo script è stato salvato col nome prova_getopts_silenzioso.sh, si ha rispettivamente:

Considerazioni sugli esempi d'uso

Ulteriori risorse


CategoryNuoviDocumenti

leon-wells/ParsingDellaRigaDiComando (l'ultima modifica è del 10/12/2021 18.57.21, fatta da leon-wells)