Perché printf stampa più argomenti del previsto?


9

Perché questo script di shell stampa input due volte?

Mi aspettavo che lo script ignorasse gli input dopo 5.

script:

#! /bin/bash
echo "Enter 5 words : "
read  a b c d e 
printf "> %s %s %s %s %s <" $a $b $c $d $e

Produzione:

user@linux:~$ pico ifs2.sh
user@linux:~$ ./ifs2.sh
Enter 5 words : 
1 2 3 4 5 
> 1 2 3 4 5 <user@linux:~$ ./ifs2.sh
Enter 5 words : 
1 2 3 4 5 6
> 1 2 3 4 5 <> 6     <user@linux:~$ ./ifs2.sh
Enter 5 words : 
1 2 3 4 5 6 7 8 9 0
> 1 2 3 4 5 <> 6 7 8 9 0 <user@linux:~$ 

E, il seguente script funziona indipendentemente da ciò che è impostato su $ IFS. Perché?

#! /bin/bash    
old="$IFS"
IFS=":"
echo "IFS = $IFS"
echo "Enter 5 words : "
read  a b c d e 
printf "> %s %s %s %s %s <" $a $b $c $d $e    
IFS="$old"

Produzione:

user@linux:~$ ./ifs2.sh
IFS = :
Enter 5 words : 
1 2 3 4 5  
> 1 2 3 4 5      <user@linux:~$ ./ifs2.sh
IFS = :
Enter 5 words : 
1 2 3 4 5
> 1 2 3 4 5     <user@linux:~$ ./ifs2.sh
IFS = :
Enter 5 words : 
1:2:3:4:5
> 1 2 3 4 5 <user@linux:~$ 

fermarsi printfin qualsiasi momento con la \cfuga associata a un %bidentificatore di formato. Mi piace:printf %s%\ d%b thing 3 "${var+\cquit printing if set}\nelse do a newline" and 0 keep\ going.
mikeserv,

Risposte:


18

Hai tre problemi:

  1. Con read, se ci sono meno nomi di variabili rispetto ai campi nell'input, l'ultimo var sarà associato a tutti i campi rimanenti sulla linea, con delimitatori. Ciò significa che $eentra 5 6nel tuo primo esempio inaspettato.
  2. Poiché tutti $a... $enon sono quotati, i loro valori sono suddivisi in campi . Se $econtiene " 5 6", si espande in due argomenti al comando.
  3. printfconsuma tutti i suoi argomenti, usando più argomenti contemporaneamente quante sono le %sostituzioni, ripetutamente. Questo è sepolto nella documentazione come:

    L' formatoperando deve essere riutilizzato tutte le volte che è necessario per soddisfare gli operandi dell'argomento. Eventuali specificatori di extra co di sconversione devono essere valutati come se fosse fornito un argomento con stringa null; altre specifiche di conversione extra devono essere valutate come se fosse fornito un argomento zero.

    In altre parole, se ci sono argomenti inutilizzati, ricomincia da capo e li elabora dall'inizio, inclusa l'intera stringa di formato. Ciò è utile quando si desidera formattare un intero array, ad esempio:

    printf '%b ' "${array[@]}"

    Il tuo printfcomando ottiene un argomento da ciascuno di $a.. $d, e comunque ne rimangono molti $e. Quando $eè " 5 6", printfha due giri in giro, il secondo è appena 6in grado di formattare. Quando è, 5 6 7 8 9 10ha l'intera gamma di sostituzioni per la seconda stampa.


Puoi evitare tutto ciò aggiungendo un campo fittizio aggiuntivo reade citando le sostituzioni dei parametri (che è sempre una buona idea):

read  a b c d e dummy
printf "> %s %s %s %s %s <" "$a" "$b" "$c" "$d" "$e"

Questo darà:

Enter 5 words : 
1 2 3 4 5 6 7 8 9 10
> 1 2 3 4 5 <

dummyottiene tutti i campi extra e printfottiene solo i cinque argomenti previsti.


La tua seconda domanda modificata ha una risposta simile: aottiene un valore solo quando IFSnon ha uno spazio. Ciò significa $b... $eespandersi a nulla, quindi printfottiene solo un singolo argomento. I tuoi spazi dalla stringa di formato vengono stampati, senza sostituirli tra loro ("come se fosse fornito un argomento stringa null").


Ho nuovamente testato il 2 ° script usando "$ a" ..... "$ e". Il secondo script restituisce nuovamente lo stesso problema.

3
La citazione non farà la differenza nel secondo script. aha il valore 1 2 3 4 5come singola stringa e viene sostituito tutto in una volta.
Michael Homer,

6
 printf "> %s < " 1 2 3

stamperà

 > 1 <> 2 <> 3 <

  printf "> %s %s <" 1 2 3

stampe

 > 1 2 <> 3  <

printf mangia tutti gli argomenti per soddisfare la sua stringa di formato e quindi si ripete fino a quando tutti gli argomenti non vengono elaborati.

Il secondo script funziona perché $aviene assegnato solo e quindi il comando non trabocca in iterazioni aggiuntive (c'è solo una iterazione).


Questo comportamento è documentato nel testo fornito con help printf:

... Il formato viene riutilizzato se necessario per utilizzare tutti gli argomenti. Se ci sono meno argomenti di quanti ne richieda il formato, le specifiche del formato extra si comportano come se fosse stato fornito un valore zero o una stringa null, come appropriato. ...

ed è richiesto da http://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html


Perché questo comportamento? è documentato?
Shiplu Mokaddim,

1
@Shiplu ha aggiunto un paragrafo su dove è documentato il comportamento e lo standard che richiede il comportamento.
PSkocik,
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.