Discussione:
parametri per sotto comando
(troppo vecchio per rispondere)
alex
2018-05-03 10:07:02 UTC
Permalink
$ cat test.sh
#!/bin/bash
function sub_command {
# parsing locale
local options
options=$(getopt -o s --long "sub-test" -- "$@") \
|| exit 1
eval set -- "$options"
while true; do
case "$1" in
-s|--sub-test)
SUB_TEST=0
shift
;;
--)
shift
break
;;
esac
done

# FAI QUALCOSA...
}

# parsing globale
options=$(getopt -o t --long "test" -- "$@") \
|| exit 1
eval set -- "$options"
while true; do
case "$1" in
-t|--test)
TEST=0
shift
;;
--)
shift
break
;;
esac
done

# esecuzione sotto-comando
$1 "$@"

Come vedete abbiamo un parsing globale per parsare le opzioni relative
all'intero script, e un parsing locale per parsare le opzioni relative
solo alla function sub_command.

Proviamo quindi se tutto funziona

$ ./test.sh --test sub_command --sub-test
getopt: opzione non riconosciuta "--sub-test"

Qualcosa non va, e intuisco che il problema è che il parsing globale,
tenta di parsare anche l'opzione --sub-test, che giustamente non riconosce.
Tale opzione infatti se la dovrebbe parsare la function sub_command per
conto suo.

Come fare?
Piergiorgio Sartor
2018-05-03 17:17:21 UTC
Permalink
On 2018-05-03 12:07, alex wrote:
[...]
Post by alex
Come fare?
Evitare certe porcherie.

Il parsing si fa in un unico posto, si creano poi
i parametri per le varie funzioni, come risultato
di suddetto parsing.

bye,
--
piergiorgio
alex
2018-05-05 11:51:28 UTC
Permalink
Post by Piergiorgio Sartor
Il parsing si fa in un unico posto, si creano poi
Ne sei sicuro?
Post by Piergiorgio Sartor
i parametri per le varie funzioni, come risultato
di suddetto parsing.
Leggi gli altri post e, quindi, proponi la tua soluzione.
Piergiorgio Sartor
2018-05-05 13:48:22 UTC
Permalink
Post by alex
Post by Piergiorgio Sartor
Il parsing si fa in un unico posto, si creano poi
Ne sei sicuro?
Cosa vuol dire "sicuro"?

Di solito, a meno di problemi particolari, conviene
avere un architettura gerarchica del SW.

Cioe` ci sono livelli diversi, che fanno cose diverse,
partendo da un livello di astrazione elevato per poi
raffinare strada facendo.

Avere il parsing in piu` posti e` sicuramente una
violazione di tale principio.
Ripeto, a meno di casi particolari, sarebbe da evitare.

Quindi, conviene avere un solo punto in cui controllare
i parametri e poi da li procedere.
Post by alex
Post by Piergiorgio Sartor
i parametri per le varie funzioni, come risultato
di suddetto parsing.
Leggi gli altri post e, quindi, proponi la tua soluzione.
La soluzione e` evitare di fare il parsing locale,
anche perche`, in shell, locale e globale sono cose
non troppo ben definite.

Nel tuo esempio di "composer", come e` scritto tale SW?

Hai guardato i sorgenti?
C'e` la soluzione che cerchi, direi.

Ad ogni modo, si puo` sempre fare una funzione che fa il
parsing e che riceve, come parametro, quale tipo di
parsing fare, se e` del programma o di un sotto-modulo.

bye,
--
piergiorgio
alex
2018-05-05 16:40:11 UTC
Permalink
Post by Piergiorgio Sartor
Ad ogni modo, si puo` sempre fare una funzione che fa il
parsing e che riceve, come parametro, quale tipo di
parsing fare, se e` del programma o di un sotto-modulo.
In pratica tu proponi questa struttura:

main-parsing
command1-parsing
command2-parsing
...
command1
fai-qualcosa
command2
fai-qualcosa

Invece l'amico enoquick propone:

main-parsing
command1
parsing
fai-qualcosa
command2
parsing
fai-qualcosa
...

Non so cosa scegliere :D
Piergiorgio Sartor
2018-05-05 16:46:35 UTC
Permalink
Post by alex
Post by Piergiorgio Sartor
Ad ogni modo, si puo` sempre fare una funzione che fa il
parsing e che riceve, come parametro, quale tipo di
parsing fare, se e` del programma o di un sotto-modulo.
main-parsing
    command1-parsing
    command2-parsing
    ...
command1
    fai-qualcosa
command2
    fai-qualcosa
main-parsing
command1
    parsing
    fai-qualcosa
command2
    parsing
    fai-qualcosa
...
Non so cosa scegliere :D
Ma e` lo stesso, poiche` e` fatto nella stessa funzione.

Sarebbe diverso, se fosse fatto in posti diversi.

Il che, ripeto, potrebbe avere senso, ma immagina solo i
problemi che possono nascere durante testing / debugging.

Una delle cose che bisogna *sempre* tenere presente e`:
come si fa a sapere dove e` il problema, in caso di problemi?

Se si sparpaglia il codice in "n" funzioni, diventa complicato
fare il debugging in caso di problemi.

Quindi la risposta la hai gia`: se non vi sono altre ragioni,
metti assieme tutto quello che deve stare assieme.

bye,
--
piergiorgio
alex
2018-05-06 09:46:57 UTC
Permalink
Post by Piergiorgio Sartor
Post by alex
Post by Piergiorgio Sartor
Ad ogni modo, si puo` sempre fare una funzione che fa il
parsing e che riceve, come parametro, quale tipo di
parsing fare, se e` del programma o di un sotto-modulo.
main-parsing
    command1-parsing
    command2-parsing
    ...
command1
    fai-qualcosa
command2
    fai-qualcosa
main-parsing
command1
    parsing
    fai-qualcosa
command2
    parsing
    fai-qualcosa
...
Non so cosa scegliere :D
Ma e` lo stesso, poiche` e` fatto nella stessa funzione.
Sarebbe diverso, se fosse fatto in posti diversi.
Però si avrà un unico modulo di parsing super affollato :D
Se ad es. vuoi disimplementare un comando, devi ricordarti anche di
disimplementare le rispettive istruzioni di parsing dal modulo di
parsing generale.
La struttura portante di un'app, andrebbe toccata il meno possibile.
Post by Piergiorgio Sartor
Il che, ripeto, potrebbe avere senso, ma immagina solo i
problemi che possono nascere durante testing / debugging.
come si fa a sapere dove e` il problema, in caso di problemi?
Un po' di analisi bisogna farla sempre, soprattutto se stai lavorando su
un progetto a cui non metti mano da diverso tempo.
E' cmq bisogna saper usare in modo efficiente i vari strumenti di debug.
Post by Piergiorgio Sartor
Se si sparpaglia il codice in "n" funzioni, diventa complicato
fare il debugging in caso di problemi.
Anche sparpagliare gli snippet di codice che usa ogni singolo comando,
non mi pare una buona idea.

Non è meglio avere tutto raggruppato?
mkdir my-command
touch my-command/main.sh
touch my-command/config-loading.sh
touch my-command/params-parsing.sh
Post by Piergiorgio Sartor
Quindi la risposta la hai gia`: se non vi sono altre ragioni,
metti assieme tutto quello che deve stare assieme.
Il fatto è che abbiamo due concetti diversi :D
Io tendo a raggruppare per moduli.
Tu tendi a raggruppare per funzionalità.
Piergiorgio Sartor
2018-05-06 10:02:43 UTC
Permalink
On 2018-05-06 11:46, alex wrote:
[...]
Post by alex
Però si avrà un unico modulo di parsing super affollato :D
Quanti comandi avrai? 1000?

Se hai cosi` tanti comandi, stai gia` sbagliando
qualcosa, prima ancora di iniziare.
Post by alex
Se ad es. vuoi disimplementare un comando, devi ricordarti anche di
disimplementare le rispettive istruzioni di parsing dal modulo di
parsing generale.
Esattamente, cosi` la prossima volta si ragiona
meglio su cosa implementare.
D'altro canto, se hai scritto il codice in maniera
decente, non sara` certo un problema.

Inoltre, se rimuovi un modulo, devi anche prenderti
cura di rimuovere *tutti* i riferimenti che possono
esservi da altre parti del programma.

Quindi il parsing e` l'ultimo dei tuoi problemi.
Post by alex
La struttura portante di un'app, andrebbe toccata il meno possibile.
In base a quale criterio?

[...]
Post by alex
Un po' di analisi bisogna farla sempre, soprattutto se stai lavorando su
un progetto a cui non metti mano da diverso tempo.
Bisogna sempre scrivere il codice in maniera che
sia facilmente leggibile.
Senza stranezze o complicazioni.
Post by alex
E' cmq bisogna saper usare in modo efficiente i vari strumenti di debug.
Non e` un buon motivo per farsi male sin dall'inizio.
Post by alex
Post by Piergiorgio Sartor
Se si sparpaglia il codice in "n" funzioni, diventa complicato
fare il debugging in caso di problemi.
Anche sparpagliare gli snippet di codice che usa ogni singolo comando,
non mi pare una buona idea.
Eh? Questo e` quello che stai facendo tu.
Post by alex
Non è meglio avere tutto raggruppato?
mkdir my-command
touch my-command/main.sh
touch my-command/config-loading.sh
touch my-command/params-parsing.sh
Non capisco cosa questo esempio voglia dire.
Cosa e` raggruppato qui?
Post by alex
Post by Piergiorgio Sartor
Quindi la risposta la hai gia`: se non vi sono altre ragioni,
metti assieme tutto quello che deve stare assieme.
Il fatto è che abbiamo due concetti diversi :D
Io tendo a raggruppare per moduli.
Tu tendi a raggruppare per funzionalità.
E tu hai moduli diversi con funzionalita` uguali?

Mi pare chiaro che ogni modulo avra` la sua funzionalita`,
altrimenti hai duplicazione di codice.

Non sono due concetti diversi, sono lo stesso.

Si deve solo chiarire cosa sia "funzionalita`".

Nel tuo concetto, avrai semplicemente un "modulo"
per fare il parsing, non mi sembra cosi` diverso.

Ripeto, a meno che non vi siano ragioni speciali
per fare altrimenti.

bye,
--
piergiorgio
alex
2018-05-06 12:45:35 UTC
Permalink
Post by Piergiorgio Sartor
[...]
Post by alex
Però si avrà un unico modulo di parsing super affollato :D
Quanti comandi avrai? 1000?
Se hai cosi` tanti comandi, stai gia` sbagliando
qualcosa, prima ancora di iniziare.
composer, apt-get, ecc. hanno in genere un set di comandi abbastanza
corposo, e cmq anche con 5-6 comandi ti ritroverai con parser centrale
piuttosto affollato.
Post by Piergiorgio Sartor
Post by alex
Se ad es. vuoi disimplementare un comando, devi ricordarti anche di
disimplementare le rispettive istruzioni di parsing dal modulo di
parsing generale.
Esattamente, cosi` la prossima volta si ragiona
meglio su cosa implementare.
E che le cose cambiano nel tempo, già vent'anni fa non c'erano i
paradigmi di programmazione attuali.
Post by Piergiorgio Sartor
Post by alex
La struttura portante di un'app, andrebbe toccata il meno possibile.
In base a quale criterio?
Se ogni volta che bisogna fare una modifica, devi mettere mano (mano
pesante) al core, sicuramente c'è qualcosa che non va (poca flessibilità).
Post by Piergiorgio Sartor
Post by alex
Anche sparpagliare gli snippet di codice che usa ogni singolo comando,
non mi pare una buona idea.
Eh? Questo e` quello che stai facendo tu.
Post by alex
Non è meglio avere tutto raggruppato?
mkdir my-command
touch my-command/main.sh
touch my-command/config-loading.sh
touch my-command/params-parsing.sh
Non capisco cosa questo esempio voglia dire.
Cosa e` raggruppato qui?
Raggruppare tutti i sorgenti ce servono per un comando, in una dir.,
come se fosse una micro app.
Post by Piergiorgio Sartor
Post by alex
Post by Piergiorgio Sartor
Quindi la risposta la hai gia`: se non vi sono altre ragioni,
metti assieme tutto quello che deve stare assieme.
Il fatto è che abbiamo due concetti diversi :D
Io tendo a raggruppare per moduli.
Tu tendi a raggruppare per funzionalità.
E tu hai moduli diversi con funzionalita` uguali?
Mi pare chiaro che ogni modulo avra` la sua funzionalita`,
altrimenti hai duplicazione di codice.
Non sono due concetti diversi, sono lo stesso.
Si deve solo chiarire cosa sia "funzionalita`".
Nel tuo concetto, avrai semplicemente un "modulo"
per fare il parsing, non mi sembra cosi` diverso.
Ripeto, a meno che non vi siano ragioni speciali
per fare altrimenti.
OK, ad ogni modo valuterò anche il tuo punto di vista :D
Piergiorgio Sartor
2018-05-06 13:07:32 UTC
Permalink
On 2018-05-06 14:45, alex wrote:
[...]
Post by alex
composer, apt-get, ecc. hanno in genere un set di comandi abbastanza
corposo, e cmq anche con 5-6 comandi ti ritroverai con parser centrale
piuttosto affollato.
E tu stai scrivendo "composer" o "apt-get"?

Ogni problema ha la sua soluzione, se hai poche
opzioni, si usa una soluzione da poche opzioni.
C'e` persino gente che dice che "getopt" e` troppo
complessa per alcuni casi.
D'altro canto "getopt" e` sufficientemente generica
da essere usabile in moltissimi casi.

[...]
Post by alex
E che le cose cambiano nel tempo, già vent'anni fa non c'erano i
paradigmi di programmazione attuali.
I concetti base sull'architettura del SW c'erano
20 anni fa, come adesso, non e` cambiato niente,
da quel punto di vista.

[...]
Post by alex
Se ogni volta che bisogna fare una modifica, devi mettere mano (mano
pesante) al core, sicuramente c'è qualcosa che non va (poca flessibilità).
Basta spostare le parti da modificare *fuori*
dal core.
E` sempre una questione di architettura, che
dipende da cosa si vuole fare e da come il SW
evolva nel tempo.
E comunque, refactoring non e` una brutta parola... :-)

[...]
Post by alex
Raggruppare tutti i sorgenti ce servono per un comando, in una dir.,
come se fosse una micro app.
Se non fosse shell script, *forse* andrebbe bene.
Dato che e` un shell script, non va bene.

Il linguaggio shell non e` pensato per fare tali
cose, se hai necessita` di SW complessi, al punto
da richiedere piu` moduli, forse conviene guardare
a linguaggi diversi, tipo Python, per esempio.

[...]
Post by alex
OK, ad ogni modo valuterò anche il tuo punto di vista :D
In generale, se hai moduli, questi dovranno essere,
per definizione, isolati gli uni dagli altri (senno`
non sono moduli).

In questo caso, ovviamente, il parsing puo` essere
fatto in ogni modulo indipendentemente.

Questo perche` non c'e` niente di globale, ma e`
tutto locale, ed eventuali parametri sono passati
*esplicitamente* da una parte del SW all'altra.

E` lo stesso concetto di un shell script.

Nello script, ogni comando e` indipendente (come
codice) dagli altri ed ha un suo parsing degli
argomenti interno, sempre indipendente dal resto.

In uno stesso shell script, pero`, dato che la
distinzione tra locale e globale diventa vaga, non
conviene avere un parsing per funzione, perche`
c'e` il rischio di perdere il controllo di cosa
succeda, quindi conviene usare un parsing centrale.

In pratica, di nuovo, bisogna aver ben chiara quale
sia l'architettura piu` adatta al problema che si
vuole affrontare, e poi decidere di conseguenza quali
siano le soluzioni migliori.

bye,
--
piergiorgio
alex
2018-05-08 11:24:23 UTC
Permalink
Post by Piergiorgio Sartor
In pratica, di nuovo, bisogna aver ben chiara quale
sia l'architettura piu` adatta al problema che si
vuole affrontare, e poi decidere di conseguenza quali
siano le soluzioni migliori.
Valuterò, grazie :D
enoquick
2018-05-04 02:52:40 UTC
Permalink
Post by alex
$ cat test.sh
#!/bin/bash
function sub_command {
    # parsing locale
    local options
        || exit 1
    eval set -- "$options"
    while true; do
        case "$1" in
            -s|--sub-test)
                SUB_TEST=0
                shift
                ;;
            --)
                shift
                break
                ;;
        esac
    done
    # FAI QUALCOSA...
}
# parsing globale
    || exit 1
eval set -- "$options"
while true; do
    case "$1" in
        -t|--test)
            TEST=0
            shift
            ;;
        --)
            shift
            break
            ;;
    esac
done
# esecuzione sotto-comando
Come vedete abbiamo un parsing globale per parsare le opzioni relative
all'intero script, e un parsing locale per parsare le opzioni relative
solo alla function sub_command.
Proviamo quindi se tutto funziona
$ ./test.sh --test sub_command --sub-test
getopt: opzione non riconosciuta "--sub-test"
Qualcosa non va, e intuisco che il problema è che il parsing globale,
tenta di parsare anche l'opzione --sub-test, che giustamente non riconosce.
Tale opzione infatti se la dovrebbe parsare la function sub_command per
conto suo.
Come fare?
io farei una cosa di questo genere:

./test.sh <sub_comand> <args>

cosi la getopt non la fai nel main ma per ogni sub_command
alex
2018-05-04 07:39:57 UTC
Permalink
Post by enoquick
./test.sh <sub_comand> <args>
cosi la getopt non la fai nel main ma per ogni sub_command
Ascolta, prendiamo come esempio composer:

$ composer -h
Usage:
help [options] [--] [<command_name>]
...

$ composer update -h
Usage:
update [options] [--] [<packages>]...
...

Come vedi i due comandi danno risultati diversi, e si dovrebbe intuire
(IHMO) che viene usato proprio il concetto di cui avevo parlato (*global
scope* e *local scope*).
Possibile che non si può ottenere un risultato simile?
enoquick
2018-05-04 10:24:18 UTC
Permalink
Post by alex
Post by enoquick
./test.sh <sub_comand> <args>
cosi la getopt non la fai nel main ma per ogni sub_command
$ composer -h
  help [options] [--] [<command_name>]
...
$ composer update -h
  update [options] [--] [<packages>]...
...
Come vedi i due comandi danno risultati diversi, e si dovrebbe intuire
(IHMO) che viene usato proprio il concetto di cui avevo parlato (*global
scope* e *local scope*).
Possibile che non si può ottenere un risultato simile?
$file $(which composer)
/usr/bin/composer: a /usr/bin/php script, ASCII text executable

non e' uno script di shell


Comunque,come scritto da me nel post precedente:


cmd=shift
case "$cmd" in
cmd1)
#fa la getopt di cmd1 e la esegue
;;
cmd2)
#fa la getopt di cmd2 e la esegue
;;
-h)
usage()
exit 0
;;
-*)
echo "$cmd - opzione errata" >&2
exit 1
;;

*)
echo "$cmd - comando errato" >&2
exit 1
esac
alex
2018-05-05 11:54:17 UTC
Permalink
Post by enoquick
$file $(which composer)
/usr/bin/composer: a /usr/bin/php script, ASCII text executable
non e' uno script di shell
Cioè?
Post by enoquick
cmd=shift
????
Post by enoquick
case "$cmd" in
    cmd1)
        #fa la getopt di cmd1 e la esegue
        ;;
    cmd2)
        #fa la getopt di cmd2 e la esegue
         ;;
    -h)
        usage()
        exit 0
        ;;
    -*)
        echo "$cmd - opzione errata" >&2
        exit 1
        ;;
    *)
        echo "$cmd - comando errato" >&2
        exit 1
esac
In pratica *getopt* bisogna usarlo solo per i comandi.
enoquick
2018-05-06 01:48:21 UTC
Permalink
Post by alex
Post by enoquick
$file $(which composer)
/usr/bin/composer: a /usr/bin/php script, ASCII text executable
non e' uno script di shell
Cioè?
E' php
Post by alex
Post by enoquick
cmd=shift
mette $1 in cmd ed elimina $1
$2 divenda $1
$3 diventa $2
ecc..
Post by alex
????
Post by enoquick
case "$cmd" in
     cmd1)
         #fa la getopt di cmd1 e la esegue
         ;;
     cmd2)
         #fa la getopt di cmd2 e la esegue
          ;;
     -h)
         usage()
         exit 0
         ;;
     -*)
         echo "$cmd - opzione errata" >&2
         exit 1
         ;;
     *)
         echo "$cmd - comando errato" >&2
         exit 1
esac
In pratica *getopt* bisogna usarlo solo per i comandi.
Esatto
non si puo fare una getopt globale se ogni cmd ha le sue opzioni
alex
2018-05-06 09:52:30 UTC
Permalink
Post by enoquick
Post by enoquick
cmd=shift
mette $1 in cmd ed elimina $1
$2 divenda $1
$3 diventa $2
ecc..
$ cmd=shift; echo $cmd
shift

????
enoquick
2018-05-07 01:46:27 UTC
Permalink
Post by alex
Post by enoquick
Post by enoquick
cmd=shift
mette $1 in cmd ed elimina $1
$2 divenda $1
$3 diventa $2
ecc..
$ cmd=shift; echo $cmd
shift
????
cat > pippo.sh <<!
#!/bin/sh

echo $@

cmd=$1
shift

echo $cmd
echo $@
!

$chmod +x pippo.sh

$./pippo.sh aaa bbb ccc
aaa bbb ccc
aaa
bbb ccc

piccola confusione - shift non ritorna un valore

piccola confusione
shift non ritorna
alex
2018-05-08 11:31:00 UTC
Permalink
Post by enoquick
cat > pippo.sh <<!
#!/bin/sh
cmd=$1
shift
echo $cmd
!
$chmod +x pippo.sh
$./pippo.sh aaa bbb ccc
aaa bbb ccc
aaa
bbb ccc
piccola confusione - shift non ritorna un valore
Adesso ci capiamo, cmq in bash le funzioni possono restituire solo
valori numerici.
enoquick
2018-05-09 02:00:26 UTC
Permalink
Post by alex
Post by enoquick
cat > pippo.sh <<!
#!/bin/sh
cmd=$1
shift
echo $cmd
!
$chmod +x pippo.sh
$./pippo.sh aaa bbb ccc
aaa bbb ccc
aaa
bbb ccc
piccola confusione - shift non ritorna un valore
Adesso ci capiamo, cmq in bash le funzioni possono restituire solo
valori numerici.
e' un exit code,come quello di un normale comando:

$cat > pippo.sh <<!
#!/bin/bash

function f {
echo "ddd"
return 5;
}


x=$(f);
echo $?
echo $x
!
$ chmod +x ṕippo.sh
$ ./pippo.sh
5
ddd
alex
2018-05-09 07:24:52 UTC
Permalink
si si

Continua a leggere su narkive:
Loading...