Книга: Искусство программирования на языке сценариев командной оболочки
16.2. Перенаправление для блоков кода
Блоки кода, такие как циклы 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.
Встроенный документ -- это особая форма перенаправления для блоков кода.
- Пример 16-4. Перенаправление в цикл while
- Пример 16-5. Альтернативная форма перенаправления в цикле while
- Пример 16-6. Перенаправление в цикл until
- Пример 16-7. Перенаправление в цикл for
- Пример 16-8. Перенаправление устройств (stdin и stdout) в цикле for
- Пример 16-9. Перенаправление в конструкции if/then
- Пример 16-10. Файл с именами "names.data", для примеров выше
- Глава 5 Агрессивные формы кода и борьба с ними
- Стиль написания исходного кода
- Анализ CIL-кода
- 4.11.7. Перенаправление
- Исправление ранее написанного кода
- 14.12.7. Перенаправление сервисов
- Листинг 5.8. (dup2.c) Перенаправление выходного потока канала с помощью функции dup2()
- Преобразование WSDL-кода в программный код агента для клиента
- Вызов окна программного кода
- Строки кода и комментарии
- 3.4 ЧТЕНИЕ И ЗАПИСЬ ДИСКОВЫХ БЛОКОВ
- 2.4.3. Генерация кода в Power Builder