Самые интересные сведения о перенаправлении, изложенные ниже, взяты из "csh.whynot". Этот документ слишком интересен и информативен для того, чтобы полностью пересказывать его здесь, поэтому ниже приводятся лишь некоторые сведения.
Можно запретить перенаправление вывода ">" в уже существующий файл (см. про переменную noglobber ), но ">|" работает всегда.
При нескольких перенаправлениях существенен порядок:
command 2>&1 1>a.txt
перенаправит sdderr на stdout , а stdout на a.txt, а вот
command 1>a.txt 2>&1
не перенаправит оба потока в файл a.txt.
Мощные возможности для «динамического» перенаправления внутри скрипта дает команда exec (см.). Собственно запуск процесса exec при данном применении не осуществляется, поэтому опишем его применение здесь.
Перенаправление «здесь документы». Рассмотрим пример из news://comp.unix.shell:
#!/bin/bash
ftp -n << EOF
open somehost.somedomain
user Anonymous aaa@bbb.com
cd /pub/upload
put /home/me/myfile.txt
quit
EOF
Опция -n в этом скрипте заставляет ftp не спрашивать имя пользователя и пароль, предоставляя возможность воспользоваться командой user в следующей форме:
user USER_NAME PASSWORD
Динамическое перенаправление. Если аргумент для команды exec не указан, но указаны символы перенаправления, exec устанавливает эти перенаправления, и выполнение текущего скрипта продолжается. Таким образом достигается «динамическое» перенаправление:
#!/bin/bash
echo .
Эта строка выводится на экран
exec >file.txt
echo
А эта строка в файл
echo И эта в файл
выведет на экран только одну строку, а две других запишет в file.txt
Дескрипторы. Открытие новых дескрипторов.Кроме возможности дублировать существующие дескрипторы (0, 1, 2) другими, также уже существующими, (напр. 2 >&1) или перенаправлять существующие дескрипторы в файл (напр. 1>log.txt), имеется возможность открывать новые, прежде закрытые дескрипторы с номерами 3 и более.
В следующем примере сначала создается (с применением перенаправления here documents]]) файл os.txt, затем с этим файлом связывается дескриптор 4, из файла читается одна строка и записывается в файл, связанный с дескриптором 3 ( docname.txt):
#!/bin/bash
#создать файл-пример для последующего чтения
cat << EOF >os.txt
ОПЕРАЦИОННЫЕ СИСТЕМЫ
UNIX
DOS
OS/2
Windows NT
EOF
echo Открываем дескрипторы 3 и 4
exec 3>docname.txt
exec 4<os.txt
echo Читаем одну строку через дескриптор 4
read d <&4
echo Записываем строку через дескриптор 3
echo $d >&3
запишет в файл docname.txt строку "ОПЕРАЦИОННЫЕ СИСТЕМЫ".
Восстановление перенаправленных дескрипторов. Если требуется перенаправить ввод или вывод временно, а затем отменить это перенаправление, информацию, ассоциируемую с перенаправляемым дескриптором, можно запомнить в одном из неиспользуемых дескрипторов, а затем восстановить его. Следующий пример представляет собой усовершенствование одного из примеров, данных выше:
#!/bin/bash
echo Эта строка выводится на экран
# запомнить дескриптор 1 в дескрипторе 3, а 1 перенапавить в file.txt:
exec 3>&1 1>file.txt
echo А эта строка в файл
echo И эта в файл
# восстановить предыдущее значение дескриптора 1:
exec 1>&3
echo Эта строка опять на экран
выведет:
Эта строка выводится на экран
Эта строка опять на экран ,
а две другие строки запишет в файл file.txt.
Известно, как передать через pipe и stdout, и stderr:
command1 2>&1 | command2.
А вот как можно передать информацию со stderr программы через pipe другой программе, оставив при этом stdout:
command1 3>&1 2>&1 1>&3 | command2.
Здесь stdout(1) запоминается в дескрипторе 3, затем stderr(2) перенаправляется в stdout(1), а сам stdout перенаправляется в 3(запомненное значение дескриптора 1). Поскольку через pipe передается только информация, выводимая через дескриптор 1, дескриптор 3 (которому ранее было присвоено значение stdout ) останется нетронутым.
Рассмотрим пример, иллюстрирующий этот прием.
Конструкция:
grep yyy xxx 3>&1 2>&1 1>&3 3>&- | sed s/file/foobar/
выведет:
grep: xxx: No such foobar or directory (ENOENT)
Закрытие дескриптора. Осуществляется дублированием его псевдодескриптором " &-":