Описание: Кандидат BSDA должен уметь перенаправлять стандартный вывод, ввод или поток ошибок программы, использовать pipe чтобы послать вывод одной программы в другую программу или в файл. Использовать tee(1) чтобы копировать стандартный ввод на стандартный вывод.
Практика: <, >,
      |, tee(1), >& и |&
        За каждой программой запущенной в UNIX (и не
        только UNIX) закреплено минимум три файловых
        дескриптора: стандартный ввод (STDIN),
        стандартный вывод (STDOUT) и стандартный
        вывод ошибок (STDERR). Хотя мы говорим
        «файловый дескриптор», на самом деле это не
        обязательно именно файлы.  Речь идёт об «обобщённых
        файлах» — некоторых объектах, куда можно писать
        и откуда можно читать. В норме, приложение запущенное в
        терминале направляет STDOUT и
        STDERR на консоль.  Таким образом, мы видим
        результат деятельности программы напечатанным на экране.
        STDIN программы, это поток информации
        читаемый ею с клавиатуры.
      
Напрмер, запустим программу grep следующим образом:
$ grep r
          
        В этом случае программа grep будет искать строки содержащие
        букву r в потоке STDIN (то есть в тексте
        набираемом с клавиатуры), и выводить этот текст на
        STDOUT (то есть на экран). Сразу после
        запуска ничего не происходит: команда grep ожидает ввода с
        клавиатуры т.е. читает STDIN. Мы печатаем
        текст и нажимаем клавишу <Enter>. После этого строка
        попадает в grep и если она содержит букву r она печатается
        второй раз на экране т.е. grep печатает её на
        STDOUT.
      
        Ниже приведён листинг такого примера. Знаком < помечены
        строки котороые набрал пользователь (STDIN),
        а знаком > строки напечатанные в ответ программой
        grep(1).
      
$ grep r
< DragonFly BSD
> DragonFly BSD
< FreeBSD
> FreeBSD
< OpenBSD
< NetBSD
        
        В нашем листинге STDIN и
        STDOUT обозначены значками < и >. В
        жизни этого, конечно, не происходит. Всё вперемешку, что крайне
        неудобно. Да и вообще, трудно представить себе что кто-то будет
        руками набивать текст только для того, чтобы его профильтровал
        grep(1). Гораздо удобнее пользоваться
        символами перенаправления для переопределения стандартного ввода
        и вывода.
      
        Пусть у нас есть файл BSDA содержащий
        названия изучаемых нами BSD систем.
      
$ cat BSDA
DragonFly BSD
FreeBSD
OpenBSD
NetBSD
        
        Применим grep для того, чтобы выяснить какие системы BSD
        содержат в своём названии букву r. Для этого мы переопределим
        STDIN команды grep. Теперь вместо того, чтобы
        читать текст с клавиатуры, grep(1) будет
        читать его из файла BSDA:
      
$ grep r < BSDA
DragonFly BSD
FreeBSD
        
        А что если нам надо сохранить вывод программы grep в файл? Тогда
        мы должны переопределить ещё и STDOUT:
      
$ grep r < BSDA > BSDA-r
        
        Теперь у нас появился файл с названием
        BSDA-r содержащий две строки:
      
$ cat BSDA-r
DragonFly BSD
FreeBSD
        
        Но а что если нам надо узнать сколько систем BSD имеют в своём
        имени букву r? Для этого мы можем воспользоваться программой
        wc(1) с аргументом -l.
        Команда wc -l считает
        строки в своём STDIN и печатает результат на
        STDOUT. Таким образом, мы можем выполнить
        последовательно 2 команды:
      
$grep r < BSDA > BSDA-r$wc -l < BSDA-r 2
        Но это неудобно: мы зачем-то создавали временный файл,
        передавали копеечную информацию и для этого обращались к диску,
        а это медленная операция. А если бы у нас было много информации,
        то наши действия тоже были бы нерациональны: Весь
        STDOUT grep(1)'а мог не
        поместиться на диске (может там миллион строк!), но он и не
        нужен wc(1) для работы,
        wc(1) может каждый отдельный момент работать
        с кусочком файла.
      
        Напрашивается естественный вывод: надо переопределить
        STDOUT grep'а так, чтобы он стал
        STDIN'ом wc(1). Такую
        конструкцию называют pipe или конвейер.
      
$ grep r < BSDA | wc -l
         2
        
Стандартный вывод wc(1) (число 2) тоже можно передать на стандартный ввод другой программы, таким образом длину конвейера или трубы (pile-line) можно сделать сколь угодно длинной. В следующем примере количество систем BSD содержащих в своём названии букву r будет распечатано на принтере:
$ grep r < BSDA | wc -l | lpr
        
        А чтоже делать, если мы хотим и список систем получить и
        посчитать их количество? Можно как и прежде выполнить 2 действия
        поочереди: сперва создать файл BSDA-r,
        полюбоваться на него, а потом скормить его программе wc. А можно
        воспользоваться программой tee(1). tee ничего
        не делает с потоком данных, которые через неё идут, она просто
        копирует STDIN в STDOUT.
        Но если ей в качестве аргумента задать некоторый файл, то она
        будет заодно записывать эту информацию и в него. Таких файлов
        команде tee можно задать много.  Таким образом, tee является
        разветвителем в трубе:
      
$grep r < BSDA | tee BSDA-r | wc -l 2$cat BSDA-r DragonFly BSD FreeBSD
        tee можно использовать как здесь — для сохранения
        промежуточных результатов, а можно использовать для того, чтобы
        протоколировать в файл то, что администратор видит на экране.
        Напрмер, ниже программа make будет писать что-то на экран, но
        впоследствии мы сможем прочитать что она там писала из файла
        make-log:
      
$ make | tee make-log
        
В этом примере мы добились развоения стандартного вывода программы make: этот поток информации одновременно пишется в файл make-log и печатается в окне терминала обычным образом.
        Теперь поговорим про STDERR. Пусть у нас в
        текущем каталоге есть два файла get.sh и
        put.sh, и более ничего нет. Выполним
        следующее действие:
      
$ ls *sh *gz
ls: *gz: No such file or directory
get.sh  put.sh
        
        Мы видим, что на экране присуствует как список файлов с
        расширением sh так и сообщение об ошибке связанное с тем, что в
        текущем каталоге отсутствуют файлы с расширением gz. Обе эти
        строки напечатаны в окне терминала, но это два разных потока.
        Сообщение об ошибке было напечатано в стандартный вывод
        ошибок — STDERR. Убедимся в этом:
      
$ls *sh *gz > /dev/null ls: *gz: No such file or directory$ls *sh *gz 2> /dev/null get.sh put.sh
        В приведённом примере мы в первом случае перенаправили
        STDOUT в файл /dev/null (это уcтройство
        поглащающее байты вроде «чёрной дыры»), а во втором
        случае мы перенаправили STDERR. Поэтому в
        первом случае у нас напечаталось только сообщение об ошибке, а
        во втором только список файлов с расширением sh.
      
        Файловые дескрипторы соответствующие STDIN,
        STDOUT и STDERR имеют
        номера, соответственно 0, 1 и 2. Когда мы пишем знак >, система неявно предполагает, что мы
        перенаправляем дескриптор с номером 1 и перенаправляет
        STDOUT.  Если же мы хотим перенаправить
        STDERR нам надо явно указать его номер: 2>.
      
![]()  | Важно | 
|---|---|
2> пишется слитно без пробела.
       | 
        Вы можете объединить файловые дескрипторы, если вам надо,
        например, писать сообщения выводящиеся на
        STDOUT и STDERR  в один
        файл:
      
$ make > make.log 2>&1
        
        Здесь мы направили стандартный вывод в файл
        make.log (написав > make.log), а затем
        STDERR перенаправили в
        STDOUT (написав 2>&1). Причём порядок действий
        здесь важен.  Команда
      
$ make 2>&1 > make.log
        
        приведёт к тому, что в файл make.log будет
        направлен только STDOUT, так как
        STDERR был перенаправлен тогда, когда
        STDOUT направлялся ещё на консоль.
      
Синтаксис перенаправления в csh(1) отличается от синтакиса в sh(1). Ниже приведены эквивалентные команды на sh(1) и на csh(1):
sh:$make 2>&1 > make.log csh:%make >& make.log sh:$make 2>&1 | less csh:%make |& less sh:$make 2>/dev/null > make.log csh:%(make > make.log) >& /dev/null
        В последней строке продемонстрировано досадное ограничение
        csh(1): для того, чтобы перенаправить
        STDERR и STDOUT в разные
        места приходится заворачиваться в блин: перенаправить
        произвольный файловый дескриптор по его номеру, увы, нельзя.
        Можно лишь пользоваться перенаправлением суммы
        STDERR и STDOUT используя
        символы |& и >&.
      
