Почему этот сценарий оболочки печатает входные данные дважды?
Я ожидал, что скрипт будет игнорировать ввод после 5.
Автор сценария:
#! /bin/bash
echo "Enter 5 words : "
read a b c d e
printf "> %s %s %s %s %s <" $a $b $c $d $e
Вывод:
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:~$
И следующий скрипт работает независимо от того, что установлено в $ IFS. Почему?
#! /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"
Вывод:
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
источник
источник
printf
в любое время с\c
экранированием, связанным со%b
спецификатором формата. Как:printf %s%\ d%b thing 3 "${var+\cquit printing if set}\nelse do a newline" and 0 keep\ going.
Ответы:
У вас есть три проблемы:
read
условии, что если во входных данных меньше имен переменных, чем полей, последняя переменная будет привязана ко всем оставшимся полям строки с разделителями. Это означает, что$e
попадает5 6
в ваш первый неожиданный пример.$a
...$e
не заключены в кавычки, их значения подвергаются разделению поля . Если$e
содержит "5 6
", то он расширяется до двух аргументов команды.printf
потребляет все свои аргументы, используя столько же аргументов одновременно, сколько есть%
подстановок, многократно. Это похоронено в документации как:Другими словами, если есть неиспользуемые аргументы, он начинается заново и обрабатывает их с самого начала, включая всю строку формата. Это полезно, когда вы хотите отформатировать весь массив, скажем:
Ваша
printf
команда получает по одному аргументу от каждого из$a
...$d
, а затем многие остаются от$e
. Когда$e
есть "5 6
",printf
два раза, второй просто6
форматируется. Когда это5 6 7 8 9 10
имеет полный спектр замен для второй печати.Вы можете избежать всего этого, добавив дополнительное фиктивное поле
read
и заключив в кавычки замену параметров (что всегда является хорошей идеей):Это даст:
dummy
получает все дополнительные поля иprintf
получает только пять ожидаемых аргументов.Ваш второй отредактированный вопрос имеет аналогичный ответ:
a
получает значение только тогда, когдаIFS
нет пробела. Это значит$b
...$e
расширяться до нуля, поэтомуprintf
получает только один аргумент. Ваши пробелы из строки формата печатаются, между ними ничего не подставляется («как если бы был задан аргумент пустой строки»).источник
a
имеет значение1 2 3 4 5
в виде одной строки и заменяется сразу.распечатает
печать
printf
съедает все аргументы для удовлетворения его строки формата и затем повторяется, пока все аргументы не будут обработаны.Второй сценарий работает, потому что только
$a
назначен, и поэтому команда не переполняется дополнительными итерациями (есть только одна итерация).Это поведение задокументировано в тексте, поставляемом с
help printf
:и поручено http://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html
источник