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]$ 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]$ makecc -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]$ makegcc -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就該這麽學》筆記 輸入輸出重定向輸入重定向 指把文件導入到命令中輸出重定向 指把原本要輸出到屏幕的數據信息寫入到指定文件中 輸出重定向 分為標準輸出重定向和錯誤輸出重定向