UNIX 基礎知識
一、UNIX 系統
- UNIX核心的接口稱之為系統調用。公用函數庫建構在系統調用接口之上。應用程式既可以使用公用函數庫,也可以使用系統調用。
- UNIX shell 是一個特殊的應用程式,它為其他應用程式提供了一個接口。
- 路徑名由斜線分隔的一個或者多個檔案名組成的序列:
- 以斜線開頭的路徑名稱為絕對路徑名
- 以非斜線開頭的路徑名稱為相對路徑名
是一個特殊的絕對路徑名。它不包含任何其他的字元。/
- 檢視UNIX系統
指令的ls
幫助手冊:man
或者man 1 ls
。man -s1 ls
-
表示第一部分。由于很多指令的說明文檔過于龐大,是以 UNIX将說明文檔劃分成九個部分。常用的段有:1
-
: 可執行程式或者1
的說明shell command
-
: 系統調用的說明2
-
: 庫函數的說明3
-
: 特殊檔案(通常位于4
)的說明/dev/
-
: 系統管理者指令的說明(通常隻有8
可用)root
-
-
表示ls
,即待查找的目标shell command
-
ls的簡要實作
#include "apue.h"
#include <dirent.h>
int main(int argc, char *argv[])
{
DIR *dp;
struct dirent *dirp;
if (argc != ) //argument
err_quit("usage:ls directory_name");
if ((dp = opendir(argv[])) == NULL) //if file not exit
err_sys("can't open %s",argv[]);
while((dirp = readdir(dp)) != NULL)
printf("%s\n",dirp->d_name);
closedir(dp);
exit();
}
用法:編譯後可執行檔案myls‘./myls /dev’必須加檔案名
标準輸出
例如:ls >file.list,即将ls顯示的内容标準輸出到檔案file.list上。
同理我們編寫的程式 : ./myls /dev > file.list
不帶緩沖的I/O
mycopy.c
/*
std output from std input
*/
#include "apue.h"
#define BUFFSIZE 4096
int main(void)
{
int n;
char buf[BUFFSIZE];
while((n = read(STDIN_FILENO,buf,BUFFSIZE)) > )
if (write(STDOUT_FILENO,buf,n) != n)
err_sys("write error");
if(n < )
err_sys("read error");
exit();
}
用法:編譯後mycopy ,運作./mycopy >data
則表示從終端接收輸入,存進data檔案中,打開data即是我們從終端出入的内容。ctrl +D,終止輸入。
若要将一個檔案的内容複制到另一檔案,則可使用
./mycopy <data> data1
//将data的内容複制到data1中
标準I/O
/*
std output from std input
*/
#include "apue.h"
int main(void)
{
int c;
/*while input enter key,the function read() begin read data(include "\n")*/
while((c = getc(stdin)) != EOF) //一次擷取一個元素
if (putc(c,stdout) == EOF)
err_sys("output error");
if (ferror(stdin))
err_sys("input error");
exit();
}
- 每個程序都有一個工作目錄,有時稱他為目前工作目錄。所有的相對路徑名都是從工作目錄開始解釋。
可以用
函數更改其工作目錄chdir
- 登入時,
的工作目錄設定為起始目錄shell
- UNIX系統中,每個程序都有一個唯一的數字标志符,稱為程序ID(一個非負整數)。
- 通常一個程序隻有一個線程。但是你也可以建立多個線程。
- 一個程序内的所有線程共享同一個位址空間、檔案描述符、棧、程序相關屬性
- 多線程的程式需要在各線程通路共享資料時采取措施來避免不一緻性
- 線程也用ID辨別,但是線程ID隻有在它所屬的程序内有意義
- 使用者群組:
- 使用者ID:辨別各個不同的使用者;使用者ID為0的使用者為根使用者,其登入名為
,它具有超級使用者權限。root
- 組ID:使用者所屬的組的辨別。
- 附屬組ID: 一個使用者可以屬于多個組,這些組就是附屬組。由附屬組的ID來辨別。
- 使用者ID:辨別各個不同的使用者;使用者ID為0的使用者為根使用者,其登入名為
二、錯誤處理
- 當 UNIX 系統函數出錯時,通常會傳回一個負值,同時整型變量
通常被設定為具有特定資訊的值。errno
- 檔案
定義了<errno.h>
以及賦予它的各種常量,這些常量以errno
字元開頭E
- 在多線程環境中,每個線程都有屬于自己的局部
,以避免一個線程幹擾另一個線程。errno
的使用要注意兩條規則:errno
- 如果沒有出錯,則
的值不會被清除.是以隻有在函數的傳回值指明出錯了時,檢查errno
才有意義errno
- 任何函數都不會将
的值清零,且在errno
中定義的所有常量都不為0<errno.h>
- 檔案
-
函數:用于處理錯誤資訊strerror/perror
#include<string.h> char *strerror(int errnum); #include<stdio.h> void perror(const char*msg);
- strerror: 将
(通常就是errnum
值)映射為一個出錯消息字元串,并且傳回此字元串的指針errno
- 輸入: 一個整數(通常是
的值)errno
- 輸出: 出錯消息字元串的指針(不需要使用者手動配置設定出錯消息字元串的記憶體)
- 輸入: 一個整數(通常是
- perror: 基于
的目前值,在标準錯誤上産生一條出錯消息,然後傳回。這條出錯消息首先是errno
指向的字元串,後面是冒号,後面是一個空格,後面是對應于msg
值的出錯消息,最後是一個換行符。errno
- 輸入:附加的出錯消息
- 輸出:無輸出。但是向标準錯誤上輸出一條出錯消息,這條出錯消息如上所述。
- strerror: 将
- 出錯恢複:可以将
中定義的錯誤分成兩類:<errno.h>
- 緻命性錯誤:此類錯誤無法恢複。最多隻能在螢幕上列印一條出錯消息或者将出錯消息寫入日志,然後退出。
- 非緻命性錯誤:此類錯誤可以妥善處理。大多數非緻命性錯誤時暫時的(比如資源短缺)
.其典型的處理方法是:延遲一段時間,然後重試。EAGAIN、ENFILE、ENOBUFS、ENOLCK、ENOSPC、EWOULDBLOCK
- 有時候
也是非緻命性出錯ENOMEM
- 當
指明 共享資源正在使用是,也可視為非緻命性出錯處理EBUSY
-
中斷一個慢速系統調用時,可以視為非緻命性出錯處理EINTR
三、時間
- UNIX 系統使用兩種時間:
- 月曆時間:自 UTC 1970年1月1日 00:00:00 以來經曆過的秒數累計值。用
資料類型來儲存這種時間值。time_t
- 程序時間:也稱作CPU時間,用于度量程序使用的CPU資源。程序時間以時間滴答來計算,用
資料類型儲存這種時間值。clock_t
- 月曆時間:自 UTC 1970年1月1日 00:00:00 以來經曆過的秒數累計值。用
- 當度量一個程序的執行時間時,UNIX系統為一個程序維護了3個程序時間值:
- 時鐘時間: 又稱作牆上時鐘時間,是程序運作的時間總量,其值與系統中同時運作的程序數有關
- 使用者CPU時間:執行使用者指令所用的時間量
- 系統CPU時間:該程序執行核心程式所經曆的時間。如程序執行一個
系統調用,則核心執行該系統調用的時間計入系統 CPU 時間read
使用者CPU時間和系統CPU時間之和稱作 CPU 時間
- 運作
指令shell
可以擷取程序的時鐘時間、使用者時間和系統時間。time
的參數請參考time
手冊man