Perché devo inserire "do" nella stessa riga di "for"?


28

1. Riepilogo

Non capisco, perché ho bisogno della regola E010 bashate .


2. Dettagli

Uso bashate per i .shfile di sfilacciatura . Regola E010:

fare non sulla stessa linea per

for bashate:

  • Corretta:

    #!/bin/bash
    for f in bash/*.sh; do
        sashacommand "$f"
    done
    
  • Errore:

    #!/bin/bash
    for f in bash/*.sh
        do sashacommand "$f"
    done
    

C'è qualche argomento valido, perché ho bisogno fore donella stessa linea?


3. Non utile

Non riesco a trovare una risposta alla mia domanda in:

  1. Google
  2. Articoli sulle migliori pratiche di codifica ( esempio )
  3. documentazione di base . Trovo solo :

    Un insieme di regole che aiutano a mantenere le cose coerenti nei blocchi di controllo. Questi sono ignorati su lunghe file che hanno una continuazione, perché srotolarsi è un po '"interessante"


3
Il rientro doè sicuramente un po 'insolito, ma for ... \ndo\n<indent>body...è estremamente comune e lo stimerei anche di più for ... ; do. Si lamenta anche di questo?
Michael Homer,

20
bashateè un controllo di stile . Gli stili sono intrinsecamente soggettivi. Non usarlo se non ti piace lo stile artibrario che impone. Dovresti invece prendere in considerazione una sintassi / un bug checker come shellcheck .
Meuh

@meuh, grazie, utilizzo già ShellCheck. la mia domanda: E010- solo stile regola o , in alcuni casi ho bisogno per e faccio nella stessa linea non solo per ragioni di stile.
Саша Черных

10
Non c'è mai un obbligo sintattica di avere per e fare sulla stessa linea nella shell.
Meuh

1
@ Саша Черных Non è insolito il rientro di per sé, è il rientro di do. È come indentare la parentesi graffa iniziale di un ife aggiungere codice su quella stessa riga in una lingua come C. Un altro esempio, se python lo permettesse, sarebbe quello di inserire :un ifrientro sulla riga successiva e aggiungere codice su quella stessa riga. Lo farà differire con le linee aggiuntive nel corpo.
JoL

Risposte:


60

Sintatticamente, i seguenti due frammenti di codice sono corretti ed equivalenti:

for f in bash/*.sh; do
    sashacommand "$f"
done
for f in bash/*.sh
    do sashacommand "$f"
done

Si potrebbe forse dire che quest'ultimo è più difficile da leggere poiché dooffusca leggermente il comando nel corpo del loop. Se il ciclo contiene più comandi e il comando successivo si trova su una nuova riga, l'offuscamento sarebbe ulteriormente evidenziato:

for f in *
    do cmd1
    cmd2
done

... ma segnalarlo come un "errore" è l'opinione personale di IMHO piuttosto che una verità oggettiva.

In generale, quasi tutti ;possono essere sostituiti da una nuova riga. Entrambi ;e newline sono terminatori di comando. doè una parola chiave che significa "qui segue ciò che deve essere fatto (in questo forciclo)".

for f in *; do ...; done

equivale a

for f in *
do
   ...
done

e come

for f in *; do
   ...
done

Il motivo per utilizzare l'uno sull'altro è la leggibilità e le convenzioni di stile locale / personale.


Opinione personale:

Nelle intestazioni di loop che sono molto lunghe , penso che potrebbe avere senso mettere dosu una nuova linea, come in

for i in animals people houses thoughts basketballs bees
do
    ...
done

o

for i in        \
    animals     \
    people      \
    houses      \
    thoughts    \
    basketballs \
    bees
do
    ...
done

Lo stesso vale per l' thenin un ifcomunicato.

Ma di nuovo, ciò dipende dalle preferenze di stile personali o dallo stile di codifica utilizzato dal proprio team / progetto.


Dici che "Nelle intestazioni in loop che sono molto lunghe, può avere senso mettere su una nuova linea". Potresti fornire una ragione per questo? Dato che l'intestazione deve essere seguita da do, non vedo un motivo per cui inserirla nella riga successiva sarebbe di aiuto per la leggibilità.
Konrad Rudolph,

3
@KonradRudolph Il mio terminale è largo 80 caratteri. Se la lista termina, la trasformerò in un insieme di linee continuate (come nel mio ultimo esempio), se quasi termina, inserirò la do(o then) su una riga da sola (come nel penultimo esempio). Tutto questo deve de con le preferenze personali. Non mi piacciono le righe troppo lunghe, in parte perché il mio terminale è "solo" largo 80 caratteri, e in parte perché penso che sia disordinato. Trovo anche difficile analizzare righe molto lunghe per errori.
Kusalananda

1
Non sembra necessario continuare a sottolineare che questa è opinione. bashate è una guida di stile, quindi è intrinsecamente basata sull'opinione.
Barmar,

4
@Barmar, nota che la domanda qui usa frasi come "bisogno di" e "regola", e il file readme di Bashate chiama il fatto che dosu una linea separata un "errore". Quelli sono piuttosto severe frasi, in modo da non sembrare vale la pena di sottolineare che, del tutto al contrario, la cosiddetta "regola" è in realtà solo un'opinione personale.
ilkkachu,

2
@mtraceur Giusto, non metto in discussione le preferenze personali. Ma tieni presente che il limite della colonna di leggibilità che citi non si applica al codice. Si applica solo alla prosa. Il movimento oculare è sostanzialmente diverso per la lettura del codice, quindi le prove di tali studi non sono applicabili qui. E per quanto riguarda l'uso di ragioni storiche che non si applicano più come fondamento logico, beh, abbiamo anche usato i nomi di file 8.3 precedenti.
Konrad Rudolph,

28

Nota cosa dice nella parte superiore della pagina:

bashate: un equivalente pep8 per gli script bash

PEP8 è la guida di stile per Python Code. Mentre le persone di Python sembrano spesso prendere molto sul serio i loro problemi di stile [citazione necessaria] , è proprio questo, una guida. Potremmo trovare degli aspetti positivi sia per mettere la dostessa linea che per quella fore per metterla su una linea a sé stante.

E 'la stessa discussione come dove mettere il {nel codice C all'avvio di ifo whileblocco (o simili).


Alcune righe di seguito nella documentazione, c'è un'altra regola interessante:

E020: Dichiarazione di funzione non in formato ^function name {$

Suppongo che il punto qui sia che l'autore di quella guida di stile pensi che l'uso della functionparola chiave sia necessario affinché il lettore riconosca una dichiarazione di funzione. Tuttavia, function fooè un modo non standard di definire una funzione: il modo standard è foo(). L'unica differenza tra i due (in Bash) è che l'altro è più difficile da portare su una shell standard, come /bin/shin Debian o Ubuntu.

Quindi, suggerirei di prendere tutte le guide di stile con un granello di sale o tre e decidere di persona quale sia lo stile migliore. Un buon controllo di stile consente di disabilitare alcuni controlli (bashate deve bashate -i E010,E011ignorare quei due controlli.) Un eccellente controllo di stile consentirebbe di modificare i test, ad esempio per verificare il contrario di E020, qui.


12

TL; DR: non è necessario. È solo l'opinione di un tizio.

Come molti altri, ho scritto forcicli come questo per decenni:

for F in arg1 arg2 arg*
do
    somecommand "$F"
done

Questo layout evidenzia il fatto che do ... donecirconda il corpo del loop, come parentesi graffe in linguaggi di tipo C, e consente alle nuove linee di separare i componenti del costrutto loop.

Naturalmente ci sono guerre di religione su dove posizionare anche le parentesi graffe, quindi potresti dire che la giuria è ancora fuori su questo. IMHO, questo è chiaramente il modo in cui è stato progettato per funzionare; Bourne amava i delimitatori abbinati, cfr. if ... fi, case ... esace la necessità di un punto e virgola nella versione più breve rivela che lo stai rendendo più corto di quanto originariamente progettato. Niente di sbagliato in questo; i progressi della tecnologia e un sacco di cose che una volta sembravano una buona idea sono ora disapprovate, come goto. Ma fino a quando l'intera comunità di shell-scripting non adotta le preferenze degli bashateautori, non devi fare nulla.


3
Ciò fiche corrisponde a if, e così esacvia, proviene da Algol 68. L'unico motivo per cui un forciclo donon è terminato odè quello odè il nome di un'utilità standard esistente. Vedi en.wikipedia.org/wiki/ALGOL_68C#Algol_68C_and_Unix
Kusalananda

1
A destra e blocchi delimitati da parole chiave sono stati usati anche in altre lingue della famiglia Algol, incluso Pascal (che usa begin ... endecc.).
alexis,

2
Non avevo mai sentito parlare della storia od, è divertente ... (Anche se, allora, perché non limitarsi a fare dei loop rof, allora?)
alexis,

2
@alexis Bene, come ha detto Kusalananda, viene dall'Algol 68, questo è il punto chiave. Stephen Bourne, il creatore della shell Bourne originale, è stato fortemente influenzato da quella lingua, ed è per questo che si è attaccato a quella sintassi. Anche quando scriveva in C. Vedi il codice sorgente per bourne shell: minnie.tuhs.org//cgi-bin/utree.pl?file=V7/usr/src/cmd/sh/mac.h Oh, e by il modo BEGINe ENDsono definiti anche lì.
Sergiy Kolodyazhnyy

1
Questo intero stile di formattazione viene anche da Algol 68, tra l'altro. È FORe DOsarebbe anche su linee separate, per convenzione, tranne quando l'intero ciclo si adatterebbe facilmente su una singola linea.
reinierpost,

3

Sono sorpreso che nessuno abbia ancora menzionato questa sintassi valida e portatile:

set alfa bravo charlie
for q do
  echo "$q"
done

Notare attentamente che fore dosono sulla stessa riga, senza punto e virgola. Risultato:

alfa
bravo
charlie

Approvo questa risposta per aver inserito una menzione di questa sintassi oscura (ma critica per il codice shell pulito e portatile in alcuni casi), tuttavia vale la pena spiegare esplicitamente alle persone che questo ostacola i parametri posizionali e, inoltre, mi sento costretto a menzionare che l'unica forma "veramente portatile (tm)" è quella in cui si trovano for qe si dotrovano su linee separate (la forma in questo esempio non è stata supportata un paio di decenni fa sulla shell Almquish originale ( ash): in-ulm.de/~mascheck/various/ bourne_args / # endnote )
mtraceur

Mentre l'esempio in questa risposta funziona per me, applicarlo all'esempio nella domanda di OP non funziona.
Scribblemacher

3

Diverse buone risposte qui. Prendi sempre le guide di stile con un pizzico di sale, e IMHO ed esperienza, sii sempre così leggermente o moderatamente preoccupato per qualsiasi comunità che è piena di dogma eccessivo quando si tratta di stile. È quasi come se credessero che quando FINALMENTE avessero ottenuto l'ultimo punto punteggiato e quell'ultima T incrociata, il software funzionerà. A volte ci vuole più dello stile perfetto per rimuovere i bug ...

Quando ho iniziato a studiare shell, la maggior parte degli script e dei tutor disponibili utilizzava il formato punto e virgola in linea

for i in "$@"; do
    stuff
done

ma poiché ero inesperto, ho avuto un po 'di fatica a individuare; e fare - entrambi essenziali per confermare la correttezza sintattica. Quindi ho preferito il do sulla riga successiva da solo. Non lo faccio più (gioco di parole previsto)

Inoltre, il comando 'while' è un ottimo candidato per un piccolo trucco:

while prep1; prep2; condition; do
    stuff
done

ma quando i comandi di preparazione sono un po 'ingombranti e / o la condizione è complessa, è meglio formattata come

while
    prep1
    prep2
    condition
do
    stuff
done

e quindi aggiungere do come "; do" è decisamente fugace.

Puoi anche diventare più intenso di così:

while
    if con1; then
      cond2
    elif cond3; then
      cond4
    elif cond5; then
      cond6
    else
      cond7
    fi
do
    stuff
done

perché ogni affermazione è un'espressione. Notare come entrambi gli stili sono usati opportunisticamente. Tienilo pulito ed è abbastanza leggibile. Compattalo o contorcilo nel nome dello stile o "risparmiando spazio" e diventa un casino orribile.

Così! Dati gli stili piuttosto barocchi degli script di shell in generale, tutto ciò che mira ad aumentare la chiarezza e un facile accesso visivo a simboli significativi è sempre una buona cosa.

La forma in cui 'do' è scritta in linea con il comando è dolce quando hai un piccolo comando - Non trovo il 'do' visivamente nascosto, né il comando interno è davvero oscurato:

for i in whatever
  do stuff
done

Lo trovo abbastanza piacevole da guardare, e ha analoghi con while, if e case:

while condition
  do stuff
end

if condition
  then stuff1
  else stuff2
fi

case $blah in
  a) stuff1;;
  b) stuff2;;
  c) stuff3;;
  *) stuffInfinity;;
esac

Chiarezza e ordine generale sono tutto ciò che Codd * ti chiede.

* Edgar F. Codd, padre della teoria dei database relazionali.


1
Mai visto un whilecon una ifcondizione prima. Freddo!
Joe,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.