1. 程式人生 > >linux i/o重定向與管道程式設計

linux i/o重定向與管道程式設計

1.Linux 使用三種流:

0:stdin           標準輸入

1:stdout        標準輸出

2:stderr         標準錯誤輸出

2.預設的連線是tty

如果輸入sort,按回車鍵,終端將會連線到sort工具上。隨便輸入幾行文字,當按下Ctrl-D來結束文字輸入的時候,sort程式對輸入進行排序並將結果寫到stdout.

3.重要概念

(1).shell並不將重定向標記和檔名傳遞給程式。

(2).重定向可以出現在命令列中的任何地方,且不需要空格來區分。

(3).shell提供對重定向向其他檔案描述符的支援。例如,2>filename即將重定向描述符2,也就是將標準錯誤輸出到給定的檔案中。

(4).是shell,而非程式將輸入和輸出重定向的。

// io1.c
// 
#include<stdio.h>
int main(int ac,char *av[]){
    int i;
    printf("number of args:%d\n",ac);
    printf("args are:\n");
    for(i=0;i<ac;i++)
        printf("args[%d]=%s\n",i,av[i]);
    fprintf(stderr,"This message is sent to stderr.\n");
    return 0;
}

[[email protected] io1]$ ./io1 a b es sad  ddd
Number of args:6
args are:
args[0]=./io1
args[1]=a
args[2]=b
args[3]=es
args[4]=sad
args[5]=ddd
This Message is sent to stderr.


[[email protected] io1]$ ./io1 a b c d ef g > test
This Message is sent to stderr.
[[email protected] io1]$ cat test
Number of args:7
args are:
args[0]=./io1
args[1]=a
args[2]=b
args[3]=c
args[4]=d
args[5]=ef
args[6]=g

[

[email protected] io1]$ ./io1 a b c d e f g >xyz one two 2>opps
[[email protected] io1]$ ls
io1  io1.c  io1.o  makefile  opps  test  xyz
[[email protected] io1]$ cat xyz
Number of args:10
args are:
args[0]=./io1
args[1]=a
args[2]=b
args[3]=c
args[4]=d
args[5]=e
args[6]=f
args[7]=g
args[8]=one
args[9]=two
[[email protected] io1]$ cat opps
This Message is sent to stderr.

一.將stdin定向到檔案

1.close-then-open

#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>

int main(){
	int fd;
	char line[100];

	fgets(line,100,stdin); printf("%s\n",line);
	fgets(line,100,stdin); printf("%s\n",line);
	fgets(line,100,stdin); printf("%s\n",line);

	close(0);                          // 關閉標準輸入流
	fd = open("/etc/passwd",O_RDONLY); // 開啟檔案,重定向
	if(fd != 0){
		fprintf(stderr,"Cound not open data as fd 0\n");
		exit(1);
	}

	fgets(line,100,stdin); printf("%s\n",line);
	fgets(line,100,stdin); printf("%s\n",line);
	fgets(line,100,stdin); printf("%s\n",line);
	fgets(line,100,stdin); printf("%s\n",line);

	return 0;
}


[[email protected] io2]$ make
gcc -o io2 io2.o
[[email protected] io2]$ ./io2
line1
line1

line2
line2

line3
line3

root:x:0:0:root:/root:/bin/bash

bin:x:1:1:bin:/bin:/sbin/nologin

daemon:x:2:2:daemon:/sbin:/sbin/nologin

adm:x:3:4:adm:/var/adm:/sbin/nologin



2.open .. close .. dup ..close

(1)open(file) 開啟stdin將要重定向的檔案。這個呼叫返回一個檔案描述符,這個檔案描述符不是0,因為0在當前已經被打開了。

(2)close(0) 將檔案描述符0關閉。檔案描述符0現在已經空閒來。

(3)dup(fd) 系統將檔案描述符fd做來一個複製。此次複製使用了最低可用檔案描述符號,即0.這樣就將磁碟檔案與檔案描述符0連結在了一起。

(4)close(fd) 最後使用close(fd)來關閉檔案的原始連線,只留下檔案描述符0的連線。

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

int main(){
	int fd;
	char line[128];
	
	fd = open("/etc/passwd",O_RDONLY); // 首先開啟檔案fd,得到3
	
	close(0);                          // 關閉檔案標誌符0,即stdin
	
	dup(fd);                           // 複製,fd',得到最低檔案描述符0
	
	close(fd);                         // 關閉fd
	
	fgets(line,100,stdin);             // 從stdin=0獲取字串,此時0標記的是
					   // fd'
	printf(line);                      // 輸出line
	
	return 0;
}


[[email protected] pipe4]$ make
cc    -c -o pipe4.o pipe4.c
gcc -o pipe4 pipe4.o
[[email protected] pipe4]$ ./pipe4
root:x:0:0:root:/root:/bin/bash




3.open..dup2..close

與2相似,只是dup2(fd,0)將close(0),dup(fd)合在一起

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>


int main(){
	int fd;
	int newfd;
	char line[100];

	fgets(line,100,stdin); printf("%s\n",line);
	fgets(line,100,stdin); printf("%s\n",line);
	fgets(line,100,stdin); printf("%s\n",line);

	fd = open("/etc/passwd",O_RDONLY);
	newfd = dup2(fd,0);
	if(newfd != 0){
		fprintf(stderr,"Cound not duplicated fd to 0\n");
		exit(1);
	}
	close(fd);
	
	fgets(line,100,stdin); printf("%s\n",line);
	fgets(line,100,stdin); printf("%s\n",line);
	fgets(line,100,stdin); printf("%s\n",line);
	
	return 0;
}


[[email protected] io3]$ make
cc    -c -o io3.o io3.c
gcc -o io3 io3.o
[[email protected] io3]$ ./io3
line1
line1

line2
line2

line3
line3

root:x:0:0:root:/root:/bin/bash

bin:x:1:1:bin:/bin:/sbin/nologin

daemon:x:2:2:daemon:/sbin:/sbin/nologin

[[email protected] io3]$



二.為其他程式重定向i/o

who>userlist

close(1);

creat("f");

exec();

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main(){
	int pid;
	int fd;
	printf("About to run who into a file\n");
	
	if((pid = fork()) == -1){
		perror("fork");
		exit(1);
	}
	
	if(pid == 0){
		close(1);
		fd = creat("userlist",0644);	
		execlp("who","who",NULL);
		perror("execlp");
		exit(1);
	}
	
	if(pid!=0){
		wait(0);
		printf("Done runing who. result in userlist.\n");
	}
	
	return 0;
}
[[email protected] io4]$ make
gcc -o io4 io4.o
[[email protected] io4]$ ./io4
About to run who into a file
Done runing who. result in userlist.
[[email protected] io4]$ cat userlist
war      tty1         2015-10-04 14:08 (:0)
war      pts/0        2015-10-04 14:22 (:0.0)



重定向到檔案的小結:

(1)標準輸入,輸出以及錯誤輸出分別對應檔案描述符0,1,2;

(2)核心總是使用最低可用檔案描述符;

(3)檔案描述符集合通過exec呼叫傳遞,且不會被改變

shell 使用程序通過fork()產生子程序與子程序呼叫exec之間的時間間隔來重定向標準輸入,輸出到檔案

三,管道程式設計

管道是核心中一個單向的資料通道。管道有一個讀取端和寫入端。

pipe呼叫由使用來最低可用檔案描述符。

pipe    建立管道

標頭檔案: #include<unistd.h>

原型:result = pipe(int array[2]);

引數:array 包含兩個int型別的陣列

返回值:-1錯誤,0成功

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(){
	int apipe[2],i,len;
	char buf[BUFSIZ];
	
	if(pipe(apipe) == -1){  // 建立一個管道:apipe[0]讀,apipe[1]寫
				// 資料流向:讀 <---  寫, 即apipe[1]流向apipe[0]
		perror("pipe"); // 如果建立失敗,輸出錯誤原因,退出
		exit(0);
	}

	fgets(buf,BUFSIZ,stdin);   // 從輸入端讀取資料
	
	len = strlen(buf);         // 獲取讀入的字串長度	

	write(apipe[1],buf,len);   // 將資料寫入到apipe[1],寫-->讀

	for(i=0;i<len;i++)
		 buf[i]='-';       // 將buf裡面的資料全部變為'-'
	
	read(apipe[0],buf,len);    // 從apipe[0]中讀取資料,apipe[1]和apipe[0]
				   // 是連線在一起的apipe[1] ---> apipe[0]	
				   // 而前面已經在apipe[1]中寫入了資料buf,buf的
				   // 資料來自stdin.
	write(1,buf,len);          // 1即代表stdout,向stdout寫資料,則輸出到螢幕
                                   // 所以整個一圈下來,輸入的資料將會輸出到螢幕
	return 0;
}

[[email protected] pipe2]$ make
gcc -o pipe2 pipe2.o
[[email protected] pipe2]$ ./pipe2
abc
abc


使用管道向自己傳送資料:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define CHILD_MESS  "I want a cookie\n"
#define PAR_MESS    "Testing...\n"
#define oops(m,x)   {perror(m);exit(x);}

int main(){
	int pipefd[2];
	int len;
	char buf[BUFSIZ];
	int read_len;
	
	if(pipe(pipefd) == -1){
		oops("can not get a pipe",1);
	}
	else{
		printf("pipefd[0]=%d,pipefd[1]=%d\n",pipefd[0],pipefd[1]);
	}
	switch(fork()){
	case -1:oops("cannot fork",2);
	case  0:
		len = strlen(CHILD_MESS);
		while(1){
			if(write(pipefd[1],CHILD_MESS,len) == -1){
				oops("Write",3);
			}
			sleep(5);
		}
	break;
	default:
		len = strlen(PAR_MESS);
		while(1){
			if(write(pipefd[1],PAR_MESS,len)!=len)
				oops("write",4);
			sleep(4);
			read_len=read(pipefd[0],buf,BUFSIZ);
			if(read_len<=0)
				break;
			write(1,buf,read_len);
		}
	break;
	}
	return 0;
}

[[email protected] pipedemo]$ make
cc    -c -o pipedemo.o pipedemo.c
gcc -o pipedemo pipedemo.o
[[email protected] pipedemo]$ ./pipedemo
pipefd[0]=3,pipefd[1]=4
Testing...
I want a cookie
Testing...
I want a cookie
Testing...
I want a cookie
Testing...
I want a cookie
Testing...
Testing...
I want a cookie
Testing...
I want a cookie
^C

在程式中。顯示來從鍵盤到程序,從程序到管道,再從管道到程序以及從程序回到終端的資料傳輸流。

使用fork來共享管道

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#define SON_STR  "sub process string...\n"    // 子程序字串

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#define SON_STR  "sub process string...\n"    // 子程序字串

int main(){
	int pid;
	int apipe[2];
	char buf[128];
				// 首先建立一個管道
	if(pipe(apipe) == -1){  // 如果建立失敗,則輸出錯誤原因,並退出
		perror("pipe");
		exit(1);
	}
	
	pid = fork();          // 建立一個子程序
	
	switch(pid){
	case -1:               // 如果建立失敗 
		perror("fork");// 輸出錯誤原因
		exit(1);       // 並退出
	break;
	case 0:                // 建立成功,0說明是子程序
		write(apipe[1],SON_STR,strlen(SON_STR)); // 向子程序的寫入管道
							 // 寫入資料
	break;                                
	default:                          // 非0則是父程序
		read(apipe[0],buf,128);   // 從父程序的讀管道介面讀取資料
		write(1,buf,strlen(buf)); // 將讀取的資料輸出到螢幕      
	break;
	}
	return 0;
}


[[email protected] pipe3]$ ./pipe3
sub process string...




在這個程式中,shell首先建立管道,然後呼叫fork建立兩個新程序,再將標準輸入和輸出重定向到建立的管道,最後通過exec來執行兩個程式。當父程序呼叫fork的時候,管道的兩端都被複制到子程序當中。只有由共同父程序的程序之間才可以用管道連線。

四,管道並非檔案

    管道在很多方面都類似於普通檔案。程序使用write將資料寫入到管道,又通過read把資料讀出來。像檔案一樣,管道是不帶由任何結構的位元組序列。另一方面,管道又與檔案不同,例如檔案的結尾也是否適用於管道呢?

1.從管道中讀取資料

(1)管道讀取阻塞

    當程序試圖從管道中讀取資料時,程序被掛起直到資料被寫進程序。那麼如何避免程序無止境地等待下去呢?

(2)管道的讀取結束標誌

    當所有的寫者關閉來管道的寫資料端時,試圖從管道讀取資料的呼叫返回0,這意味著檔案的結束。

(3)多個讀者可能引起麻煩

    管道是一個佇列。當程序從管道中讀取資料之後,資料已經不存在了。如果兩個程序都試圖對同一個管道進行讀操作,在一個程序讀取一些之後,另一個程序讀到的將是後面的內容。他們讀到的資料必然是不完整的,除非兩個程序使用某種放法來協調他們對管道的訪問。

2.向管道中西資料

(1)寫入資料阻塞直到管道有空間去容納新的資料

    管道的容納資料的能力要比磁碟檔案差得多。當程序試圖對管道進行寫操作時,此呼叫將掛起直到管道中有足夠的空間去容納新的資料。如果程序想寫入1000個位元組,而管道中現在只能容納500個位元組,那麼這個寫入呼叫就只好等待直到管道中再有500個位元組空出來。如果某程序試圖寫100萬字節,那結果會怎麼樣呢?呼叫會不會永遠等待下去呢?

(2)寫入必需保證一個最小的塊大小

    POSIX標準規定核心不會拆分小於512位元組的塊。而Linux則保證管道中可以存在4096位元組的連續記憶體。如果兩個程序向管道寫資料,並且每一個程序都限制其訊息不大於512位元組,那麼這些訊息都不會被核心拆分。

(3)若無讀者存在讀取資料,則寫操作執行失敗

    如果所有的讀者都已將管道的讀取端關閉,那麼對管道的寫入呼叫將會執行失敗。如果在這種情況下,資料還可以被接受的話,他們會到哪裡去呢?為了避免資料丟失,核心採用了兩種方法來通知程序:“此時的寫操作是無意義的”。首先,核心傳送SIGPIPE訊息給程序。若程序被終止,則無任何事情發生。否則write呼叫返回-1,並且將errno置為EPIPE。(這一節摘自《Unix/Linux程式設計實踐教程》)


相關推薦

linux i/o定向管道程式設計

1.Linux 使用三種流: 0:stdin           標準輸入 1:stdout        標準輸出 2:stderr         標準錯誤輸出 2.預設的連線是tty 如果輸入sort,按回車鍵,終端將會連線到sort工具上。隨便輸入幾行文字,當按下

06 I/O定向管道

文件中 輸入輸出 行數據 cat 命令 負載 結構 系統默認 總線 .com   首先,我們知道我們的計算機結構,在第一節的時候已經介紹過了,CPU進行數據運算,同時控制器負責指令的發送,而內存則是數據存儲的地方,CPU讀取的數據均從內存中調取。電腦除了CPU和內存外,

9.I/O定向管道

標準輸入重定向(STDIN,檔案描述符為0):預設從鍵盤輸入。 標準輸出重定向(STDOUT,檔案描述符為1):預設輸出到螢幕。 錯誤輸出重定向(STDERR,檔案描述符為2):預設輸出到螢幕。 1.IO重定向 IO重定向:就是把一些預設輸入輸出

Shell I/O定向exec的使用介紹

注:該文章例子來自於網路的收集和整理,附帶本人註解。 ①I/O重定向的常用用法 符號 意義 cmd1 | cmd2 管道符,將cmd1的標準輸出作為cmd2的標準輸入。 > filename 將標準輸出

第十章 I/O定向管道

0.摘要 概念與技巧 -I/O重定向:概念與原因 -標準輸入,輸出和標準錯誤的定義 -重定向標準I/O到檔案 -使用fork來為其他程式重定向 -管道(Pipe) -建立管道後呼叫fork 相關的系統呼叫與函式 -dup,dup2 -pipe

linux學習第一周;標準輸入、輸出和錯誤定向管道

例子 OS clas 管道 text 默認 post 錯誤 gpo 標準輸入 標準輸出 標準錯誤 重定向: < #標準輸入重定向,默認為鍵盤輸入,利用<可以將文件代替鍵盤輸入 > #標準輸出重定向(會覆蓋1.text裏面的內容);例子:ls > /d

linux下的IO定向管道相關的知識簡析

io操作 簡單的 先來 兩個 整數 指令 cpu director 文件描述 一、bash重定向部分簡單翻譯 1.1、bash手冊關於重定向短短的註解(因為過於經典,所以摘錄出來) 我的翻譯要開始毀經典啦... 參考:https://blog.csdn.net/spch2

Liunx學習筆記之文件權限I/O定向

ima 所有 讀取 區別 命令執行 com ror 重定向 cd 命令 一、文件權限 1. 文件權限 在 Linux 中有四種訪問權限,列舉如下 可讀取:r,Readable 可寫入:w,Writable 可執行:x,Execute 無權限:- 我們可以使用 ls -l

Linux Bash Shell學習 十七 I/O定向

                  本文也即《Learning the bash Shell》3rd Edition的第七章Input/Output and Command-Line Processing之讀書筆記之一。我們曾經學習過shell的基本IO重定向操作:>、<和|。基本上能滿足95%的

Linux學習——資料流定向管道

一、資料流重定向 上圖包含3種資料流: 1、標準輸入流(stdin):程式碼為0,符號為<或<<; 2、標準輸出流(stdout):程式碼為1,符號為>或>>; 3、標準錯誤流(stderr):程式碼為2,符號為2

定向管道

概念 join 分隔 附加 操作 awk err 數據管道 inf 1.Bash 實際上使用三種標準輸入輸出流: ? 標準輸出流(stdout),顯示來自命令的輸出,文件描述符是 1。? 標準錯誤輸出流(stderr),顯示來自命令的錯誤輸出,文件描述符是 2。? 標準輸入

20181205 I/O 定向

I/O 重定向 一.標準輸入、標準輸出、標準錯誤file descriptors (FD,檔案描述符 或 Process I/O channels):程序使用檔案描述符來管理開啟的檔案[[email protected] ~]# ls /proc/$$/fd0 1 2 3 40, 1, and 2

20181205 I/O 定向

esc 輸出 ext src -c channels vim nag proc I/O 重定向 一.標準輸入、標準輸出、標準錯誤file descriptors (FD,文件描述符 或 Process I/O channels):進程使用文件描述符來管理打開的文件[roo

管理及I/O定向

顯示屏 寄存器 標準輸入 stdin 系統 存在 輸出 設備 block 程序 :指令和數據控制器:指令運算器:數據存儲器:RAM地址總線:內存尋址數據總線:傳輸數據控制總線:控制指令寄存器:CPU暫時存儲器I/O :硬盤 Input Output系統設定:默認輸出設備

C++ I/O 定向方法(定向到串列埠或Socket)

C++ 標準輸入輸出模組,為字元流操作提供了便捷的途徑,軟體開發當中,尤其是嵌入式系統開發當中,有時候需要把流資訊重新定向到特定的埠,如串列埠,乙太網,USB等。如標準輸入輸出cout, cin預設將字元流定向到螢幕或控制檯。本文介紹瞭如何過載streambuf使得使用

Shell I/O定向的原理解釋

在Unix系統中,每個程序都有STDIN、STDOUT和STDERR這3種標準I/O,它們是程式最通用的輸入輸出方式。幾乎所有語言都有相應的 標準I/O函式 ,比如,C語言可以通過scanf從終端輸入字元,通過printf向終端輸出字元。熟悉Shell的朋友都知

linux資料流定向管道以及搭配grep等命令

資料流重定向 基礎概念: 華麗分割 stdin(輸入) stdout(正確輸出) stderr(錯誤輸出) 對應資料值 0 1 2 可以將原本打到螢幕上的資料輸出到指定的地方,比如可以

linux初級學習筆記九:linux I/O管理,定向管道!(視頻序號:04_3)

font 運算 bsp 輸出 指令 所有 inittab tput bin 本節學習的命令:tr,tee,wc 本節學習的技能:       計算機的組成       I/O管理及重定向      管道的使用   知識點九:管理及IO重定向(4_3) 計算機組成:  

Linux學習筆記之管道定向正則表達式

linux管道與重定向 linux學習筆記 linux 正則表達式 管道:前一個命令的輸出,作為後一個命令的輸入命令1 | 命令2 | 命令3| 命令4 #tee 即在顯示器顯示,又在文件在保存文件例#echo “hello ,word” | tee /tmp/ hello.out例#wc -l

Linux管道符、定向環境變量

相對路徑 pat 直接 類型 別名 分組 查看 lin 絕對路徑 ——《Linux就該這麽學》筆記 輸入輸出重定向輸入重定向   指把文件導入到命令中輸出重定向   指把原本要輸出到屏幕的數據信息寫入到指定文件中 輸出重定向   分為標準輸出重定向和錯誤輸出重定向