Стандартни файлове, конвейери, пренасочване
3. Свързване на програмите с файлове
4. Пренасочване с файлови дескриптори
В момента на стартирането си процесите (програмите) в Unix/Linux са свързани към три предварително отворени комуникационни канали (файлове) :
стандартен входящ поток (Standard input) съкращаван като stdin - подаваните данни към програмата,
стандартен изходящ поток (Standard output) съкращаван като stdout - извежданите от програмата данни (стандартно насочени към терминала) и
стандартен поток за грешки (Standard error) съкращаван като stderr (също стандартно насочен към терминала.
Стандартният вход stdin е поток от данни (често текст), влизащи в дадена програма. По подразбиране той е свързан с клавиатурата но може да бъде свързан и със стандартния изход на друга програма. Програмата ползва тези данни чрез операция за четене. Символите въвеждани в интерактивни програми ( например текстов редактор) влизат в stdin.
Не всички програми изискват използване на stdin. Например, ls и echo могат да вземат аргументи от командния ред, но изпълняват действието си без никакъв вход от стандартния входящ поток.
$ echo
$
$ echo hello
hello
$ ls
Командата cat (без параметри) чете информация от stdin (до срещане на символ край на потока Ctrl+D) и я извежда на стандартния изход.
$ cat
first line
first line
second line
second line
^D
Стандартният изход stdout е поток, където програмата пише нейните изходни данни чрез операция за запис. Не всички програми генерират изходни данни. Например команда за преименуване на файл mv (без подадена опция -v) не извежда никаква информация при успех.
По подразбиране, стандартният изход е насочен към текстов терминал, който инициира програмата, но може да бъде свързан към стандартния вход на друга програма.
$ touch fex
$ mv fex fex1
$ mv -v fex1 fex2
renamed 'fex1' -> 'fex2'
$
Стандартният изход е линейно буфериран. Това означава, че програмата пише в буфер до среща на newline character, или до достигане на определен брой символи, след което информацията се извежда. Извеждането на информацията може да стане и с извикване на функция fflush(stdin) в програмата.
Стандартният поток за грешки stderr е друг изходящ поток от данни, използван обикновено от програмите да извежда съобщение за грешки или симптоми (предупреждения) за такива. Това е поток, който е отделно от stdout и може да бъде пренасочван отделно. Този подход позволява разграничаване на изходящите данни и грешките. Обичайната дестинация е текстовия терминал, който стартира програмата. По този начин осигурява най-добрата възможност да бъде видяна грешката, дори и, ако stdout е пренасочен.
По подразбиране, стандартният изход е насочен към текстов терминал, който инициира програмата. Например- изходящият поток от данни от една програма се пренасочва във входящия на следващата програма, но грешките от всяка от двете програми отиват директно в текстовия терминал.
Съобщенията се появяват в същия ред, в който програмата ги записва, освен ако буферирането на стандартния изходящ поток от данни все още не е завършило. Например, често срещана ситуация е, текст, въведен по-късно към потока от грешки, да се появи по-рано в терминала тъй като стандартният поток от грешки не е буфериран, но стандартният изходящ поток се буферира линейно.
Например нека бъде създаден, компилиран и стартиран файл:
$nano testbuf.c
# include <stdio.h>
int main(){
fprintf(stdout," hello");
fprintf(stderr, "test stderr ");
fprintf(stdout," world\n");
}
$ gcc testbuf.c -o testbuf
$ ./testbuf
test stderr hello world
$
За да бъдат изведени по реда на записването им :
# include <stdio.h>
int main(){
fprintf(stdout," hello");
fflush(stdout);
fprintf(stderr, "test stderr ");
fprintf(stdout," world\n");
}
Конвейерът представлява последователност от процеси които са свързани чрез техните потоци, така че изходът от единия процес stdout зарежда директно входът stdin на следващия процес. Стандартният синтаксис за конвейер е списък от команди разделени с вертикални черти | ( наричани на кратко pipes ).
$Program 1 | Program 2 | Program 3
От програмите не се изисква нищо за да участват в конвейери. Те трябва просто да четат от stdin и да пишат в stdout.
Например за да се изведат само под-директориите в текущата директория (командата egrep ^d пропуска само линиите, които започват с d )
$ls -al |egrep ^d
За да се изведат файловете в директория /bin, като в списъка се включат само файловете в чиито имена има низ "key" (grep) :
$cd /bin
$ls |egrep key
Ако трябва да се изведе само броя на тези файлове могат да се изведат на отделни линии и да се преброят линиите:
$cd /bin
$ls -l | egrep key | wc -l
Програмите в конвейера работят едновременно на конкурентен принцип. Pipes са еднопосочни като посоката на обмена на данни е отляво на дясно.
Например следващият конвейр включва две команди
$cat | grep pijo
Стандартният входен поток на командата cat е клавиатурата, въведените от клавиатурата текстове се подават на командата grep, която подава към стандартния си изход (екрана) сaмо текстовете съдържащи низа pijo.
Стандартните потоци на програмите могат да бъдат пренасочвани към файлове.
Стандартният входен поток stdin се пренасочва с „<“ към файл от където програмата трябва да чете.
$cat <test.txt
Командата ползва файла test.txt като stdin , а като stdout – екрана на текстовия терминал. Командата извежда на екрана на текстовия терминал съдържанието на файла test.txt.
Стандартният изходен поток stdout се пренасочва с „>“ към файл. Ако файлът съществува, се презаписва.
$cat >test1.txt
създава файла test1.txt . Като входен поток се използва клавиатурата на текстовия терминал (завършва с CTRL+D) .
Двете пренасочвания могат да се използват едновременно.
$cat <test.txt >test1.txt
копира файла test.txt като test1.txt.
Пренасочването на stdout с „>>“ добавя информацията към края на съществуващ файл. Ако файлът не съществува, той се създава.
Отворените файлове притежават номера наричани файлови дескриптори, които могат да бъдат използвани за пренасочване.
Трите стандартни файла имат следните дескриптори
файл дескриптор
Standard input 0
Standard output 1
Standard error 2
Дескрипторите 3-9 могат да се свържат с други файлове и се ползват обикновено в скриптове.
Пренасочването обикновено се извършва с stdin и stdout . За да бъде пренасочен друг файл файловият дескриптор трябва да се постави преди символа за пренасочване:
$ mv tst test1 2>err
$ cat err
mv: cannot stat 'tst': No such file or directory
Командата tee прави Т-връзка в конвейер от команди. Тя копира stdin си към stdout както и към файл. Така например за запазване детайлите на всички последни logins в системата (команда last) в един файл, а от изхода на командата да бъдат отделени детайлите за тези на потребителя bob (команда grep) – в друг:
$ last | tee everyone.txt | grep bob > bob.txt