Advanced Bash-Scripting Guide: Искусство программирования на языке сценариев командной оболочки | ||
---|---|---|
Назад | Глава 16. Перенаправление ввода/вывода | Вперед |
Блоки кода, такие как циклы while, until и for, условный оператор if/then, так же могут смешиваться с перенаправлением stdin. Даже функции могут использовать эту форму перенаправления (см. Пример 22-7). Оператор перенаправления <, в таких случаях, ставится в конце блока.
Пример 16-4. Перенаправление в цикл while
#!/bin/bash if [ -z "$1" ] then Filename=names.data # По-умолчанию, если имя файла не задано. else Filename=$1 fi # Конструкцию проверки выше, можно заменить следующей строкой (подстановка параметров): #+ Filename=${1:-names.data} count=0 echo while [ "$name" != Smith ] # Почему переменная $name взята в кавычки? do read name # Чтение из $Filename, не со stdin. echo $name let "count += 1" done <"$Filename" # Перенаправление на ввод из файла $Filename. # ^^^^^^^^^^^^ echo; echo "Имен прочитано: $count"; echo # Обратите внимание: в некоторых старых командных интерпретаторах, #+ перенаправление в циклы приводит к запуску цикла в субоболочке (subshell). # Таким образом, переменная $count, по окончании цикла, будет содержать 0, # значение, записанное в нее до входа в цикл. # Bash и ksh стремятся избежать запуска субоболочки (subshell), если это возможно, #+ так что этот сценарий, в этих оболочках, работает корректно. # # Спасибо Heiner Steven за это примечание. exit 0
Пример 16-5. Альтернативная форма перенаправления в цикле while
#!/bin/bash # Это альтернативный вариант предыдущего сценария. # Предложил: by Heiner Steven #+ для случаев, когда циклы с перенаправлением #+ запускаются в субоболочке, из-за чего переменные, устанавливаемые в цикле, #+ не сохраняют свои значения по завершении цикла. if [ -z "$1" ] then Filename=names.data # По-умолчанию, если имя файла не задано. else Filename=$1 fi exec 3<&0 # Сохранить stdin в дескр. 3. exec 0<"$Filename" # Перенаправить stdin. count=0 echo while [ "$name" != Smith ] do read name # Прочитать с перенаправленного stdin ($Filename). echo $name let "count += 1" done <"$Filename" # Цикл читает из файла $Filename. # ^^^^^^^^^^^^ exec 0<&3 # Восстановить stdin. exec 3<&- # Закрыть временный дескриптор 3. echo; echo "Имен прочитано: $count"; echo exit 0
Пример 16-6. Перенаправление в цикл until
#!/bin/bash # То же самое, что и в предыдущем примере, только для цикла "until". if [ -z "$1" ] then Filename=names.data # По-умолчанию, если файл не задан. else Filename=$1 fi # while [ "$name" != Smith ] until [ "$name" = Smith ] # Проверка != изменена на =. do read name # Чтение из $Filename, не со stdin. echo $name done <"$Filename" # Перенаправление на ввод из файла $Filename. # ^^^^^^^^^^^^ # Результаты получаются теми же, что и в случае с циклом "while", в предыдущем примере. exit 0
Пример 16-7. Перенаправление в цикл for
#!/bin/bash if [ -z "$1" ] then Filename=names.data # По-умолчанию, если файл не задан. else Filename=$1 fi line_count=`wc $Filename | awk '{ print $1 }'` # Число строк в файле. # # Слишком запутано, тем не менее показывает #+ возможность перенаправления stdin внутри цикла "for"... #+ если вы достаточно умны. # # Более короткий вариант line_count=$(wc < "$Filename") for name in `seq $line_count` # "seq" выводит последовательность чисел. # while [ "$name" != Smith ] -- более запутанно, чем в случае с циклом "while" -- do read name # Чтение из файла $Filename, не со stdin. echo $name if [ "$name" = Smith ] then break fi done <"$Filename" # Перенаправление на ввод из файла $Filename. # ^^^^^^^^^^^^ exit 0
Предыдущий пример можно модифицировать так, чтобы перенаправить вывод из цикла.
Пример 16-8. Перенаправление устройств (stdin и stdout) в цикле for
#!/bin/bash if [ -z "$1" ] then Filename=names.data # По-умолчанию, если файл не задан. else Filename=$1 fi Savefile=$Filename.new # Имя файла, в котором сохраняются результаты. FinalName=Jonah # Имя, на котором завершается чтение. line_count=`wc $Filename | awk '{ print $1 }'` # Число строк в заданном файле. for name in `seq $line_count` do read name echo "$name" if [ "$name" = "$FinalName" ] then break fi done < "$Filename" > "$Savefile" # Перенаправление на ввод из файла $Filename, # ^^^^^^^^^^^^^^^^^^^^^^^^^^^ и сохранение результатов в файле. exit 0
Пример 16-9. Перенаправление в конструкции if/then
#!/bin/bash if [ -z "$1" ] then Filename=names.data # По-умолчанию, если файл не задан. else Filename=$1 fi TRUE=1 if [ "$TRUE" ] # конструкции "if true" и "if :" тоже вполне допустимы. then read name echo $name fi <"$Filename" # ^^^^^^^^^^^^ # Читает только первую строку из файла. exit 0
Пример 16-10. Файл с именами "names.data", для примеров выше
Aristotle Belisarius Capablanca Euler Goethe Hamurabi Jonah Laplace Maroczy Purcell Schmidt Semmelweiss Smith Turing Venn Wilson Znosko-Borowski # Это файл с именами для примеров #+ "redir2.sh", "redir3.sh", "redir4.sh", "redir4a.sh", "redir5.sh".
Перенаправление stdout для блока кода, может использоваться для сохранения результатов работы этого блока в файл. См. Пример 3-2.
Встроенный документ -- это особая форма перенаправления для блоков кода.