A che cosa serve il colon?


45

Ho hackerato molti script di shell e talvolta le cose più semplici mi sconcertano. Oggi mi sono imbattuto in una sceneggiatura che ha fatto ampio uso del :builtin bash (due punti).

La documenazione sembra abbastanza semplice:

: (a colon)  
     : [arguments]  

Non fare altro che espandere gli argomenti ed eseguire reindirizzamenti. Lo stato di ritorno è zero.

Tuttavia, in precedenza l'ho visto solo usato nelle dimostrazioni di espansione della shell. Il caso d'uso nello script che ho incontrato ha fatto ampio uso di questa struttura:

if [ -f ${file} ]; then
    grep some_string ${file} >> otherfile || :
    grep other_string ${file} >> otherfile || :
fi

In realtà c'erano centinaia di greps, ma sono più o meno le stesse. Non sono presenti reindirizzamenti di input / output diversi dalla semplice struttura sopra. Nessun valore restituito viene verificato successivamente nello script.

Sto leggendo questo come un costrutto inutile che dice "o non fare nulla". A quale scopo potrebbe finire questa greps con "o non fare nulla"? In che caso questo costrutto causerebbe un risultato diverso rispetto alla semplice esclusione || :da tutte le istanze?


10
Un possibile scopo che posso vedere è quello di utilizzare :come alternativa a true. Forse errexitè impostato e all'autore non interessa lo stato di uscita di alcuni comandi.
jw013,


la pagina collegata StackOverflow è IMO un po 'più completa (quindi buona lettura sia questa pagina che la pagina collegata).
Trevor Boyd Smith, il

Risposte:


29

Sembra che le :s nella tua sceneggiatura vengano utilizzate al posto di true. Se grepnon trova una corrispondenza nel file, verrà restituito un codice di uscita diverso da zero; come menziona jw013 in un commento, se errexitimpostato, probabilmente -esulla riga di shebang, lo script uscirà se qualcuno dei due grepnon riesce a trovare una corrispondenza. Chiaramente, non è quello che l'autore voleva, quindi ha aggiunto || :per rendere lo stato di uscita di quel particolare comando composto sempre zero, come il più comune (nella mia esperienza) || true/ || /bin/true.


Duh. Questo era nel concetto di uno script di build RPM e, sebbene non vedessi alcun controllo del codice di uscita all'interno dello script, ho dimenticato di considerare che il processo padre potrebbe essere in fase di monitoraggio.
Caleb,

8
In tal caso, la definirei una cattiva pratica di scripting. Funzionalmente equivale a utilizzare trueinvece, ma l'intento semantico è molto più chiaro true. :è più adatto quando si desidera un NOP esplicito.
jw013,

Nella mia esperienza, questa è una pratica comune negli script RPM. Probabilmente non dovrebbe essere, ma ci siamo.
Mattdm,

alcuni puristi preferiscono :invece che trueperché :è un bashbuilt-in dove come al truesolito è un binario compilato con più overhead. di solito uso trueperché il codice è più leggibile (allo stesso modo preferisco usare sourceinvece di .).
Trevor Boyd Smith, il

36

L' :integrato è utile anche con l'espansione shell "Assegna valori predefiniti" di Bash, dove l'espansione viene spesso utilizzata esclusivamente per l'effetto collaterale e il valore espanso viene eliminato:

# assign FOO=bar iff FOO is unset
: ${FOO:=bar}

2
È venuto qui alla ricerca di questo, è stato sconcertato quando ho visto questo modello in uno script per dichiarare i valori predefiniti.
Sfogliando il

21

Mi vengono in mente due posti che ho usato :in passato.

while :
do
     shell commands
     some exit condition
done

Questo è un ciclo infinito.

function doSomethingStub {
    :
}

Inserire una funzione di stub, solo per ottenere il flusso di controllo di livello superiore corretto.

Un uso che ho visto nei vecchi tempi: invece di una #!/bin/sh(o qualunque altra) linea, vedresti una :linea. Alcuni dei vecchi kernel Real Unix o shell Real Unix userebbero questo per significare "Sono uno script di shell, fammi correre". Ricordo che era proprio quando csh si stava facendo strada come una shell interattiva comune.


@BruceEdiger: hai un riferimento alla linea "shecolon"?
l0b0

7
Alla fine ho
Bruce Ediger

1
il comportamento all'inizio :è molto strano. ho scoperto che effettivamente causa l'esecuzione dello script sh. dove come quando avvii lo script senza shebang ... prova a eseguire lo script con qualunque shell sia in esecuzione (quindi se lo stai eseguendo bashcerca di eseguirlo come bashse lo avessi csh, cerca di eseguirlo come csh).
Trevor Boyd Smith, il

19

Il :built-in era già nella shell Thompson - è documentato per Unix V6 nel 1975. Nella shell Thompson, :indicava un'etichetta per il gotocomando. Se non hai mai provato a chiamare gotosu una linea che inizia con , quella linea era effettivamente un commento.

La shell Bourne , l'antenata delle shell Bourne / POSIX come le conosciamo, non ha mai avuto una gotomia conoscenza, ma mantenuta :come comando no-op (era già presente in Unix V7 ).


Punto per sfondo storico informativo.
Tony Barganski,

12

Ho scoperto un vecchio riferimento: "L'ambiente di programmazione UNIX" (c) 1984 di Kernighan e Pike.

Pagina 147 (Shell Programming) dice questo:

":" è un comando incorporato della shell che non fa altro che valutare i suoi argomenti e restituire "vero". Invece [facendo riferimento a un esempio di script], avremmo potuto usare true , che restituisce semplicemente un vero stato di uscita. (Esiste anche un comando falso .) Ma ':' è più efficiente di vero perché non esegue un comando dal file system . [Il corsivo / l'enfasi è mia.]


2
Naturalmente, trueora è incorporato anche in molti sistemi.
tripla il

8

Mi sembra di ricordare che le prime versioni della shell non avevano una sintassi di commento. Una linea che inizia con :(che probabilmente sarebbe stata un vero eseguibile, simile a /bin/true) sarebbe stata la migliore alternativa.

Ecco una pagina man per l'antica shell Thompson (nessuna relazione); non si fa menzione di alcuna sintassi di commento.


4
L'origine di :era in effetti un indicatore di etichetta per il gotocomando, in alcune antiche shell (non so quale). Un'etichetta : somethingpotrebbe davvero essere usata come commento, se non ci fosse corrispondenza goto. La pratica si è bloccata anche dopo essere gotoscomparsa.
Gilles 'SO- smetti di essere malvagio' il

8

":" è utile per il debug.

DEBUGLOG=": debugfunction"

statement
statement
$DEBUGLOG arg1 arg2 ...
statement
statement

L'esecuzione normale della funzione di debug non viene mai eseguita, quindi basta fare un passo sopra il noop (variabili e caratteri jolly sono comunque espansi). Se è richiesto un debug più approfondito, rimuovere il noop dalla variabile e la funzione di debug viene chiamata con qualsiasi argomento richiesto.

Un altro uso utile è come un commento a blocchi, che è una caratteristica mancante della sintassi della shell.

: << COMMENT
all --statements --in --here
are now -a here document which are
passed to --the noop
COMMENT
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.