Dlaczego dane wejściowe tego skryptu powłoki są drukowane dwukrotnie?
Spodziewałem się, że skrypt zignoruje dane wejściowe po 5.
Scenariusz:
#! /bin/bash
echo "Enter 5 words : "
read a b c d e
printf "> %s %s %s %s %s <" $a $b $c $d $e
Wynik:
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:~$
I następujący skrypt działa bez względu na ustawienie $ IFS. Dlaczego?
#! /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"
Wynik:
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:~$
shell-script
mikeserv
źródło
źródło
printf
w dowolnym momencie dzięki\c
wyjściu związanemu ze%b
specyfikatorem formatu. Jak:printf %s%\ d%b thing 3 "${var+\cquit printing if set}\nelse do a newline" and 0 keep\ going.
Odpowiedzi:
Masz trzy problemy:
read
, jeśli na wejściu jest mniej nazw zmiennych niż pól, ostatni zmienny zostanie powiązany ze wszystkimi pozostałymi polami w linii, z ogranicznikami. Oznacza to, że$e
dostaniesz5 6
się do pierwszego nieoczekiwanego przykładu.$a
...$e
nie są cytowane, ich wartości podlegają podziałowi pól . Jeśli$e
zawiera „5 6
”, to rozwija się do dwóch argumentów polecenia.printf
zużywa wszystkie argumenty, używając tyle argumentów na raz, ile jest%
podstawień, wielokrotnie. Jest to zakopane w dokumentacji jako:Innymi słowy, jeśli są nieużywane argumenty, zaczyna się od nowa i przetwarza je od początku, łącznie z ciągiem całego formatu. Jest to przydatne, gdy chcesz sformatować całą tablicę, powiedz:
Twoje
printf
polecenie pobiera jeden argument z każdego z$a
...$d
, a następnie wiele z nich zostało$e
. Kiedy$e
jest „5 6
”,printf
ma dwa dookoła, drugi właśnie się6
formatuje. Kiedy5 6 7 8 9 10
ma pełny zakres zamienników drugiego wydruku.Możesz tego wszystkiego uniknąć, dodając dodatkowe pole
read
zastępcze i podając swoje podstawienia parametrów (co zawsze jest dobrym pomysłem):To da:
dummy
pobiera wszystkie dodatkowe pola iprintf
otrzymuje tylko pięć oczekiwanych argumentów.Drugie edytowane pytanie ma podobną odpowiedź:
a
otrzymuje wartość tylko wtedy, gdyIFS
nie ma spacji. Oznacza to$b
...$e
rozwinąć do zera, więcprintf
dostaje tylko jeden argument. Spacje z ciągu formatu są drukowane, a między nimi nic nie jest podstawiane („jak gdyby podano argument ciąg pusty”).źródło
a
ma wartość1 2 3 4 5
jako pojedynczy ciąg i zostaje zastąpiony jednocześnie.wydrukuje
odciski
printf
zjada wszystkie argumenty, aby spełnić ciąg formatu, a następnie powtarza się, aż wszystkie argumenty zostaną przetworzone.Drugi skrypt działa, ponieważ tylko
$a
do niego przypisano i dlatego polecenie nie przepełnia się dodatkowymi iteracjami (istnieje tylko jedna iteracja).To zachowanie jest udokumentowane w tekście dostarczonym z
help printf
:i jest upoważniony przez http://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html
źródło