Perché l'eco "bar" -n è diverso dall'eco -n "bar"?


10

Confrontare

echo -n "bar"

con

echo "bar" -n

Il primo fa quello che penso dovrebbe fare (stampa "bar" senza una nuova riga), mentre il secondo no. Si tratta di un bug o di progettazione? Perché è diverso da molti programmi di cli in quanto non puoi spostare le opzioni? Ad esempio, tail -f /var/log/messagesè esattamente lo stesso di tail /var/log/messages -f. A volte faccio il secondo quando dimentico di volere il primo, perché internamente le opzioni e gli argomenti sono riorganizzati, di solito da getopt .

Aggiornamento: sì, inizialmente ho annullato la mia domanda. Ho rimosso il nerf che dovrai visualizzare la cronologia per dare un senso ad alcune risposte.


3
Da quello che vedo, la differenza è immediatamente evidente. echo -n "bar"dà "bar", mentre echo "bar" -ndà "bar -n"
phunehehe il

Risposte:


18

Come molti altri hanno osservato, "-n" viene interpretato letteralmente se posizionato ovunque ma immediatamente dopo il echocomando.

Storicamente, le utility UNIX erano tutte così: cercavano opzioni solo immediatamente dopo il nome del comando. Probabilmente era BSD o GNU che ha aperto la strada allo stile più flessibile (anche se potrei sbagliarmi), poiché anche ora POSIX specifica il vecchio modo come corretto (vedere la Linea guida 9 e anche man 3 getoptsu un sistema Linux). Comunque, anche se la maggior parte dei programmi di utilità Linux in questi giorni usa il nuovo stile, ci sono alcuni aspetti positivi echo.

Echoè un disastro, dal punto di vista degli standard, in quanto c'erano almeno due versioni fondamentalmente in conflitto al momento della creazione di POSIX. Da un lato, hai lo stile SYSV, che interpreta i caratteri con escape backslash ma che tratta gli argomenti in modo letterale, senza accettare alcuna opzione. Dall'altro, hai lo stile BSD, che tratta un'iniziale -ncome un caso speciale e produce letteralmente tutto il resto. E poiché echoè così conveniente, hai migliaia di script di shell che dipendono da un comportamento o dall'altro:

echo Usage: my_awesome_script '[-a]' '[-b]' '[-c]' '[-n]'
echo -a does a thing.
echo -b does something else.
echo -c makes sure -a works right.
echo -- DON\'T USE -n -- it\'s not finished! --

A causa della semantica "tratta tutto alla lettera", è impossibile persino aggiungere una nuova opzione echosenza rompere le cose. Se GNU usasse lo schema di opzioni flessibili su di esso, l'inferno si scatenerà.

Per inciso, per la migliore compatibilità tra le implementazioni della shell Bourne, utilizzare printfanzichéecho .

AGGIORNATO per spiegare perché, echoin particolare, non utilizza opzioni flessibili.


voto dato che sei l'unico a menzionare che è il comportamento getopt previsto.
Geoffrey Bachelet,

@jander perché l'eco è un "holdout"? Penso che sia un coreutil gnu?
xenoterracide,

@xeno: ho aggiornato la mia risposta. Fondamentalmente, GNU non voleva rompere le cose.
Jander,

1
Accettare le opzioni dopo il primo non-opzione è specifico per GNU utilities e programmi che utilizzano GNU libc 's getopt strutture. L'utente può sempre ottenere un comportamento compatibile con le versioni precedenti impostando la variabile di ambiente POSIXLY_CORRECT.
Gilles 'SO- smetti di essere cattivo' il

1
Per il caso specifico di echo, ci sono anche implementazioni che riconoscono -eo -Ecome opzioni. Per la portabilità, non iniziare con a -o utilizzare qualcosa di simile printf %s -e.
Gilles 'SO- smetti di essere malvagio' il

9

Le altre risposte arrivano al punto in cui puoi guardare la pagina man per vedere che -n sta diventando parte della stringa da eco. Tuttavia, voglio solo sottolineare che è facile investigare questo senza md5sum e rende ciò che sta succedendo un po 'meno enigmatico.

[11:07:44][dasonk@Chloe:~]: echo -n "bar"
bar[11:07:48][dasonk@Chloe:~]: echo "bar" -n
bar -n

3
+1 esattamente. Se una pipeline non sta facendo ciò che ti aspetti, prova ogni parte separatamente.
Mikel,

6

Caspita, le spiegazioni di tutti sono lunghe.

È così semplice:

-n è un'opzione se appare prima della stringa, altrimenti è solo un'altra stringa da ripetere.

Rimuovi | md5sum e vedrai che l'output è diverso.


5

Dalla semplice ispezione, questo non è un bug di progettazione ...

echo "bar" -n | md5sum

a3f8efa5dd10e90aee0963052e3650a1

Prova questo comando per te:

echo "bar -n" | md5sum

Noterai che l'md5 risultante è

a3f8efa5dd10e90aee0963052e3650a1

Hai appena confuso l'uso di -n in eco.

Nel tuo primo codice di esempio

echo -n "bar" | md5sum

-n è usato per dire NON inserire una nuova riga dopo questa eco.

Il tuo secondo campione

echo "bar" -n | md5sum

sta trattando -n come un testo letterale.

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.