2013-03-22 19 views
7

Sono un po 'confuso con la stampa di una variabile che contiene un nuovo simbolo di linea in bash.bash printf con nuova riga

var="Age:\n20\ncolor:\nred" 
echo -e $var 
Age: 
20 
color: 
red 

Questo è il lavoro, ma un sacco di gente dice che l'eco con le opzioni è not portable e it is better to use printf.

Non ho mai usato prinf. Secondo i manuali per emettere il comando echo:

printf '%s\n' "$var" 
Age:\n20\ncoloe:\nred 

Ma questo non analizza la variabile all'interno. manuali di solito hanno questo esempio:

printf "Surname: %s\nName: %s\n" "$SURNAME" "$LASTNAME" 

ma non è il mio caso e dal mio punto di vista non comodo da usare. Ho scoperto semplicemente digitando che posso usare questo:

printf "$ var \ n"

E 'portatile? Se poi passo $ var a un comando di posta, salverà le nuove interruzioni di riga?

printf "$var\n" | mail -s subj [email protected] 
+0

Problemi con 'printf' è che è un guscio integrata su alcune shell (bash e ksh93) ma un processo esterno sugli altri (sh, ksh88, csh) . Quindi usare 'printf' su vecchie shell potrebbe rallentare il tuo programma, a seconda di quante volte lo usi. – cdarke

risposta

16

s' %b di formato era destinato specificamente per sostituire echo -e (in realtà, l'estensione XSI a echo che richiede speciale interpretazione degli argomenti di default. -e non è mai stato specificato e non è consentita dalla POSIX.) printf, ed è identico praticamente in ogni modo, incluse alcune differenze da $'...' e l'argomento stringa di formato a printf.

$ (var='Age:\n20\ncolor:\nred'; printf '%b\n' "$var") 
Age: 
20 
color: 
red 

generale dovreste evitare di espandere le variabili nella stringa di formato a meno che il programma controlla il valore esatto ed è destinato specificamente per essere una stringa di formato. Il tuo ultimo esempio in particolare potrebbe essere piuttosto pericoloso in Bash a causa dell'opzione -v di printf.

# Bad! 
var='-v_[$(echo "oops, arbitrary code execution" >&2)0]' 
printf "$var" foo 

Di solito è buona norma evitare %b a meno che non si dispone di un requisito speciale portabilità. La memorizzazione dei codici di escape in una variabile anziché i dati letterali viola i principi di separazione di codice e dati. Ci sono contesti in cui questo è ok, ma di solito è meglio assegnare il valore usando il quoting $'...', che è specificato per la prossima versione di POSIX, ed è stato a lungo disponibile in Bash e nella maggior parte dei sapori ksh.

x=$'foo\nbar'; printf '%s\n' "$x" # Good 
x=(foo bar); printf '%s\n' "${x[@]}" # Also good (depending on the goal) 
x='foo\nbar'; printf '%b\n' "$x"  # Ok, especially for compatibility 
x='foo\nbar'; printf -- "$x"   # Avoid if possible, without specific reason 
+0

Grazie per la risposta dettagliata. – idobr

+0

@ormaaj: ho visto qualcuno (tu?) Menzionare funzionalità che verranno aggiunte alla prossima versione di POSIX prima; c'è una bozza pubblicamente visibile di questo? Solo curioso. – chepner

+0

@chepner Le specifiche della bozza sono disponibili per elencare gli abbonati. Il TC1 2008 è già finalizzato e dovrebbe essere disponibile in qualsiasi momento, anche se [questo] (http://austingroupbugs.net/view.php?id=249) (e altre modifiche di "funzionalità") non arriverà almeno fino a quando problema 7. Chiunque può leggere gli archivi della lista su [gmane] (http: //dir.gmane.org/gmane.comp.standards.posix.austin.general), o cerca il bug tracker. In teoria, se hai gli strumenti giusti, puoi costruire lo stato corrente delle cose dalle diffs dei bug tracker (non ho tentato di farlo). – ormaaj