Ⅰ Linux文件系統中硬鏈接和軟鏈接的區別
鏈接和軟鏈接的區別
1.原理上:
硬鏈接(hard link):文件A是文件B的硬鏈接,則A的目錄項中的inode節點號與B的目錄項中的inode節點號相同,即一個inode節點對應兩個不同的文件名,兩個文件名指向同一個文件,A和B對文件系統來說是完全平等的。如果刪除了其中一個,對另外一個沒有影響。每增加一個文件名,inode節點上的鏈接數增加一,每刪除一個對應的文件名,inode節點上的鏈接數減一,直到為0,inode節點和對應的數據塊被回收。註:文件和文件名是不同的東西,rm A刪除的只是A這個文件名,而A對應的數據塊(文件)只有在inode節點鏈接數減少為0的時候才會被系統回收。
軟鏈接(soft link):A是B的軟鏈接(A和B都是文件名),A的目錄項中的inode節點號與B的目錄項中的inode節點號不相同,A和B指向的是兩個不同的inode,繼而指向兩塊不同的數據塊。但是A的數據塊中存放的只是B的路徑名(可以根據這個找到B的目錄項)。A和B之間是「主從」關系,如果B被刪除了,A仍然存在(因為兩個是不同的文件),但指向的是一個無效的鏈接。
2.使用限制上:
硬鏈接:
a:不能對目錄創建硬鏈接,原因有幾種,最重要的是:文件系統不能存在鏈接環(目錄創建時的」..」除外,這個系統可以識別出來),存在環的後果會導致例如文件遍歷等操作的混亂(,pwd等命令的運作原理就是基於文件硬鏈接,順便一提,ls -l結果的第二列也是文件的硬鏈接數,即inode節點的鏈接數)
b:不能對不同的文件系統創建硬鏈接,即兩個文件名要在相同的文件系統下。
c:不能對不存在的文件創建硬鏈接,由原理即可知原因。
軟鏈接:
a.可以對目錄創建軟鏈接,遍歷操作會忽略目錄的軟鏈接。
b:可以跨文件系統
c:可以對不存在的文件創建軟鏈接,因為放的只是一個字元串,至於這個字元串是不是對於一個實際的文件,就是另外一回事了
3.命令
硬鏈接:ln 源文件名 鏈接名
軟鏈接:ln -s 源文件名 鏈接名
硬鏈接和軟鏈接的作用
硬鏈接:
硬連接的作用是允許一個文件擁有多個有效路徑名,這樣用戶就可以建立硬連接到重要文件,以防止「誤刪」的功能。只刪除一個連接並不影響節點本身和其它的連接,只有當最後一個連接被刪除後,文件的數據塊及目錄的連接才會被釋放。也就是說,文件真正刪除的條件是與之相關的所有硬連接文件均被刪除。
還有如果把鏈接名創建為一個以.開頭的隱藏文件,還能很好的隱藏自己的隱私(你們懂的..呵呵呵)。
軟鏈接:
軟鏈接又稱之為符號連接(Symbolic Link)。軟鏈接文件類似於Windows的快捷方式。它實際上是一個特殊的文件。在符號連接中,文件實際上是一個文本文件,其中包含的有另一文件的位置信息。
Ⅱ c語言指令有哪些啊
第一章:緒論?
內核版本號格式:x.y.zz-www/x為主版本號,y為次版本號,zz為次次版本號,www為發行號/次版本號改變說明內核有重大變革,其偶數為穩定版本,奇數為尚在開發中的版本
第二章:基礎?
文件種類:-:txt,二進制/d:目錄/l:鏈接文件(link)/b:區塊設備文件/c:字元設備文件/p:管道
目錄結構:bin:可執行/boot:開機引導/dev:設備文件/etc:系統配置文件/lib:庫文件/mnt:設備掛載點/var:系統日誌/
命令:rmdir:刪除空目錄/find [path] [expression]/touch命令還可以修改指定文件的最近一次訪問時間/tar -czvf usr.tar.gz path/tar –zxvf usr.tar.gz/tar –cjvf usr.tar.bz2 path/tar –jxvf usr.tar.bz2
gcc:預處理:-g/I在頭文件搜索路徑中添加目錄,L在庫文件搜索路徑中
gdb:設置斷點:b/查看斷點信息:info
Makefile:make –f other_makefile/<:第一個依賴文件的名稱/@:目標文件的完整名稱/^:所有不重復的依賴文件/+:所有依賴文件(可能重復)
第三章:文件IO
read:read(fd, temp, size); /讀fd中長度為size的值到temp/返回0表示file為NULL
write:write(fd, buf, buf_size); /寫長度為buf_size的buf內容到fd中
lseek:lseek(fd, offset, SEEK_SET); /從文件開頭向後增加offset個位移量
unlink:從文件系統中刪除一個名字
open1:int open(const char * pathname, int flags, mode_t mode);/flags為讀寫方式/mode為許可權設置/O_EXCL:測試文件是否存在/O_TRUNC:若存在同名文件則刪除之並新建
open2:注意O_NONBLOCK
mmap.1:void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offsize);
mmap.2:mmap(start_addr, flength, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
fcntl:上鎖/int fcntl(int fd, int cmd, struct flock * lock);/對誰;做什麼;設置所做內容
select:fd_max+1,回傳讀狀況,回傳寫狀況,回傳異常,select等待的時間/NULL為永遠等待/0為從不等待/凡需某狀況則用之,反則(fd_set *)NULL之
FD_*那幾個函數……
一般出錯則返回-1
第四章:文件與目錄
硬鏈接與符號鏈接?
chdir改變目錄
0:in/1:out/2:err
第五章:內存管理
可執行文件存儲時:代碼區、數據區和未初始化區
棧:by編譯器,向低址擴展,連續,效率高/堆:by程序員
/etc/syslog.conf,系統log記錄文件/優先順序為-20時最高
第六章:進程和信號
程序代碼、數據、變數、文件描述符和環境/init的pid為1
execl族:int execl(const char * path, const char * arg, ....);/path即可執行文件的路徑,一般為./最後一個參數以NULL結束
waitpid:waitpid(pid_t pid,int * status,int options);/option:一般用WNOHANG,沒有已經結束的子進程則馬上返回,不等待
kill:int kill(pid_t pid,int sig);/發送信號sig給pid
void (*signal(int signum, void(* handler)(int)))(int);/第一個參數被滿足時,執行handler/第一個參數常用:SIG_IGN:忽略信號/SIG_DFL:恢復默認信號
第七章:線程
sem_init(sem_t *sem, int pshared, unsigned int value)/pshared為0/value即初始值
第八章:管道
1:write/0:read
第九章:信號量、共享內存和消息隊列
臨界資源:操作系統中只允許一個進程訪問的資源/臨界區:訪問臨界資源的那段代碼
信號量:建立聯系(semget),然後初始化,PV操作,最後destroy
共享內存沒有提供同步機制
第十章:套接字
UDP:無連接協議,無主客端的區分/實時性
TCP:位元組流/數據可靠性/網路可靠性
數據報:SOCK_STREAM/SOCK_DGRAM
其它
管道一章的both_pipe即父子進程間的全雙工管道通訊
關繫到信號和互斥的伺服器-客戶端程序
線程一章的class的multi_thread文件夾下的thread8.c
int main(void)
{
int data_processed;
int file_pipes_1[2];
int file_pipes_2[2];
char buffer[BUFSIZ + 1];
const char some_data[] = "123";
const char ch2p[] = "this is the string from child to the parent!";
const char p2ch[] = "this is the string from parent to the child!";
pid_t fork_result;
memset(buffer,'\0',sizeof(buffer));
if(pipe(file_pipes_1) == 0){
if(pipe(file_pipes_2) == 0){
fork_result = fork();
switch(fork_result){
case -1:
perror("fork error");
exit(EXIT_FAILURE);
case 0://child
close(file_pipes_1[1]);
close(file_pipes_2[0]);
printf("in the child!\n");
read(file_pipes_1[0],buffer, BUFSIZ);
printf("in the child, read_result is \"%s\"\n",buffer);
write(file_pipes_2[1],ch2p, sizeof(ch2p));
printf("in the child, write_result is \"%s\"\n",ch2p);
exit(EXIT_SUCCESS);
default://parent
close(file_pipes_1[0]);
close(file_pipes_2[1]);
printf("in the parent!\n");
write(file_pipes_1[1], p2ch, sizeof(p2ch));
printf("in the parent, write_result is \"%s\"\n",p2ch);
read(file_pipes_2[0],buffer, BUFSIZ);
printf("in the parent, read_result is \"%s\"\n",buffer);
exit(EXIT_SUCCESS);
}
}
}
}
#ifndef DBG
#define DBG
#endif
#undef DBG
#ifdef DBG
#define PRINTF(fmt, args...) printf("file->%s line->%d: " \
fmt, __FILE__, __LINE__, ##args)
#else
#define PRINTF(fmt, args...) do{}while(0);
#endif
int main(void)
{
PRINTF("%s\n", "hello!");
fprintf(stdout, "hello hust!\n");
return 0;
}
#define N 5
#define MAX 5
int nput = 0;
char buf[MAX][50];
char *buffer = "";
char buf_r[100];
sem_t mutex,full,avail;
void *proctor(void *arg);
void *consumer(void *arg);
int i = 0;
int main(int argc, char **argv)
{
int cnt = -1;
int ret;
int nput = 0;
pthread_t id_proce[10];
pthread_t id_consume;
ret = sem_init(&mutex, 0, 1);
ret = sem_init(&avail, 0, N);
ret = sem_init(&full, 0, 0);
for(cnt = 0; cnt < 6; cnt ++ ){
//pthread_create(&id_proce[cnt], NULL, (void *)proctor, &cnt);
pthread_create(&id_proce[cnt], NULL, (void *)proctor, (void *)cnt);
}
pthread_create(&id_consume, NULL, (void *)consumer, NULL);
for(cnt = 0; cnt < 6; cnt ++){
pthread_join(id_proce[cnt], NULL);
}
pthread_join(id_consume,NULL);
sem_destroy(&mutex);
sem_destroy(&avail);
sem_destroy(&full);
exit(EXIT_SUCCESS);
}
void *proctor(void *arg)
{
while(1){
sem_wait(&avail);
sem_wait(&mutex);
if(nput >= MAX * 3){
sem_post(&avail);
//sem_post(&full);
sem_post(&mutex);
return NULL;
}
sscanf(buffer + nput, "%s", buf[nput % MAX]);
//printf("write[%d] \"%s\" to the buffer[%d]\n", (*(int*)arg), buf[nput % MAX],nput % MAX);
printf("write[%d] \"%s\" to the buffer[%d]\n", (int)arg, buf[nput % MAX],nput % MAX);
nput ++;
printf("nput = %d\n", nput);
sem_post(&mutex);
sem_post(&full);
}
return NULL;
}
void *consumer(void *arg)
{
int nolock = 0;
int ret, nread, i;
for(i = 0; i < MAX * 3; i++)
{
sem_wait(&full);
sem_wait(&mutex);
memset(buf_r, 0, sizeof(buf_r));
strncpy(buf_r, buf[i % MAX], sizeof(buf[i % MAX]));
printf("read \"%s\" from the buffer[%d]\n\n",buf_r, i % MAX);
sem_post(&mutex);
sem_post(&avail);
//sleep(1);
}
return NULL;
}
Ⅲ C++問題(指針&引用)
指針存放的是地址,可以指向任一內存地址,然後修改地址指向的內存里的內容,所以如果操作不當,指向一個未知的內存,容易導致系統崩潰。故有了引用的概念,變數的引用可以理解為別名,也是為了用戶可以直接操作變數原本的內存地址的內容,類似Linux中的硬鏈接。但是這樣的思想讓用戶聲明的引用實際操作的地址一定是實際存在的地址,不會發生錯誤。
而C++的引用完全是為了兼容C,C語言一般用在嵌入式行業,需要指向任一地址才可以操作不同地址的外設,面向過程也能封裝成面向對象的思想來編程,所以嵌入式開發基本上都是用C語言而不是C++。你會發現Java、Python、PHP等語言都已經拋棄了指針的概念,都只有引用。所以C++里沒必要再用指針了,會引用就行。
至於你的第二個問題,那是引用的基本定義,如果直接int r=i,和最基礎的變數定義一樣,怎麼可能是引用。
Ⅳ linux下c語言編程
實在點,給你些命令操作操作,不過好象有點多,哈哈
Linux/Unix常用命令
1、目錄操作
和DOS相似,UNIX採用樹型目錄管理結構,由根目錄(/)開始一層層將子目錄建下去,各子目錄以 / 隔開。用戶login後,工作目錄的位置稱為 home directory,由系統管理員設定。『~』符號代表自己的home directory,例如 ~/myfile 是指自己home目錄下myfile這個文件。
(1)顯示目錄文件 ls
執行格式: ls [-atFlgR] [name] (name可為文件或目錄名稱)
例: ls 顯示出當前目錄下的文件
ls -a 顯示出包含隱藏文件的所有文件
ls -t 按照文件最後修改時間顯示文件
ls -F 顯示出當前目錄下的文件及其類型
ls -l 顯示目錄下所有文件的許可權、擁有者、文件大小、修改時間及名稱
ls -lg 同上
ls -R 顯示出該目錄及其子目錄下的文件
注:ls與其它命令搭配使用可以生出很多技巧(最簡單的如"ls -l | more"),更多用法請輸入ls --help查看,其它命令的更多用法請輸入 命令名 --help 查看.
(2)建新目錄 mkdir
執行格式: mkdir directory-name
例: mkdir dir1 (新建一名為dir1的目錄)
(3)刪除目錄 rmdir
執行格式: rmdir directory-name 或 rm directory-name
例:rmdir dir1 刪除目錄dir1,但它必須是空目錄,否則無法刪除
rm -r dir1 刪除目錄dir1及其下所有文件及子目錄
rm -rf dir1 不管是否空目錄,統統刪除,而且不給出提示,使用時要小心
(4) 改變工作目錄位置 cd
執行格式: cd [name]
例: cd 改變目錄位置至用戶login時的working directory
cd dir1 改變目錄位置,至dir1目錄
cd ~user 改變目錄位置,至用戶的working directory
cd .. 改變目錄位置,至當前目錄的上層目錄
cd ../user 改變目錄位置,至上一級目錄下的user目錄
cd /dir-name1/dir-name2 改變目錄位置,至絕對路徑(Full path)
cd - 回到進入當前目錄前的上一個目錄
(5)顯示當前所在目錄pwd
執行格式: pwd
(6)查看目錄大小
執行格式: [-s] directory
例: dir1 顯示目錄dir1及其子目錄容量(以kb為單位)
-s dir1 顯示目錄dir1的總容量
(7)顯示環境變數
echo $HOME 顯示家目錄
echo $PATH 顯示可執行文件搜索路徑
env 顯示所有環境變數(可能很多,最好用"env | more","env | grep PATH"等)
(8)修改環境變數,在bash下用export,如:
export PATH=$PATH:/usr/local/bin
想知道export的具體用法,可以用shell的help命令:help export
2、文件操作
(1)查看文件(可以是二進制的)內容 cat
執行格式:cat filename或more filename 或cat filename|more
例: cat file1 以連續顯示方式,查看文件file1的內容
more file1
或 cat file1|more 以分頁方式查看文件的內容
(2)刪除文件 rm
執行格式: rm filename
例: rm file?
rm f*
(3)復制文件 cp
執行格式: cp [-r] source destination
例: cp file1 file2 將file1復製成file2
cp file1 dir1 將file1復制到目錄dir1
cp /tmp/file1 將file1復制到當前目錄
cp /tmp/file1 file2 將file1 復制到當前目錄名為file2
cp -r dir1 dir2 (recursive )復制整個目錄。
(4)移動或更改文件、目錄名稱mv
執行格式: mv source destination
例: mv file1 file2 將文件file1,更名為file2
mv file1 dir1 將文件file1,移到目錄dir1下
mv dir1 dir2
(5)比較文件(可以是二進制的)或目錄的內容 diff
執行格式: diff [-r] name1 name2 (name1、name2同為文件或目錄)
例: diff file1 file2 比較file1與file2的不同處
diff -r dir1 dir2 比較dir1與dir2的不同處
(6)文件中字元串的查找 grep
執行格式: grep string file
例: grep abc file1 查找並列出串abc所在的整行文字
(7)文件或命令的路徑尋找
執行格式一:whereis command 顯示命令的路徑
執行格式二:which command 顯示路徑及使用者所定義的別名
執行格式三:whatis command 顯示命令的功能摘要
(8)建立文件或目錄的鏈接 ln
例: ln source target1 建立source文件(已存在)的硬鏈接,命名為target1
ln -s source target2 建立source文件的符號鏈接,命名為target2
文件編輯器vi
vi是在UNIX 上被廣泛使用的中英文編輯軟體。vi是visual editor的縮寫,是UNIX提供給用戶的一個窗口化編輯環境。
進入vi,直接執行vi編輯程序即可。
例:$vi test.c
顯示器出現vi的編輯窗口,同時vi會將文件復制一份至緩沖區(buffer)。vi先對緩沖區的文件進行編輯,保留在磁碟中的文件則不變。編輯完成後,使用者可決定是否要取代原來舊有的文件。
1、vi的工作模式
vi提供二種工作模式:輸入模式(insert mode)和命令模式(command mode)。使用者進入vi後,即處在命令模式下,此刻鍵入的任何字元皆被視為命令,可進行刪除、修改、存檔等操作。要輸入信息,應轉換到輸入模式。
(1)命令模式
在輸入模式下,按ESC可切換到命令模式。命令模式下,可選用下列指令離開vi:
:q! 離開vi,並放棄剛在緩沖區內編輯的內容
:wq 將緩沖區內的資料寫入磁碟中,並離開vi
:ZZ 同wq
:x 同wq
:w 將緩沖區內的資料寫入磁碟中,但並不離開vi
:q 離開vi,若文件被修改過,則要被要求確認是否放棄修改的內容,此指令可與:w配合使用
(2)命令模式下游標的移動
H 左移一個字元
J 下移一個字元
K 上移一個字元
L 右移一個字元
0 移至該行的首
$ 移至該行的末
^ 移至該行的第一個字元處
H 移至窗口的第一列
M 移至窗口中間那一列
L 移至窗口的最後一列
G 移至該文件的最後一列
W, W 下一個單詞 (W 忽略標點)
B, B 上一個單詞 (B 忽略標點)
+ 移至下一列的第一個字元處
- 移至上一列的第一個字元處
( 移至該句首
) 移至該句末
{ 移至該段首
} 移至該段末
NG 移至該文件的第n列
N+ 移至游標所在位置之後第n列
n- 移至游標所在位置之前第n列
(3)輸入模式
輸入以下命令即可進入vi輸入模式:
a(append) 在游標之後加入資料
A 在該行之末加入資料
i(insert) 在游標之前加入資料
I 在該行之首加入資料
o(open) 新增一行於該行之下,供輸入資料用
O 新增一行於該行之上,供輸入資料用
dd 刪除當前游標所在行
X 刪除當前游標字元
x 刪除當前游標之前字元
U 撤消
• 重做
F 查找
ESC鍵 離開輸入模式
GNU C編譯器
LINUX上可用的C編譯器是GNU C編譯器,它建立在自由軟體基金會編程許可證的基礎上,因此可以自由發布。
LINUX 上的GNU C編譯器(GCC)是一個全功能的ANCI C兼容編譯器。下面介紹GCC和一些GCC編譯器最常用的選項。
1、使用GCC
通常後跟一些選項和文件名來使用GCC編譯器。GCC命令的基本用法如下:
gcc [options] [filenames]
命令行選項指定的編譯過程中的具體操作
2、GCC常用選項
GCC有超過100個的編譯選項可用,這些選項中的許多可能永遠都不會用到,但一些主要的選項將會頻繁使用。很多的GCC選項包括一個以上的字元,因此必須為每個選項指定各自的連字元,並且就像大多數LINUX 命令一樣不能在一個單獨的連字元後跟一組選項。例如:
gcc test.c
編譯成功後,當前目錄下就產生了一個可執行文件a.out。
也可用-o選項來為即將產生的可執行文件指定一個文件名來代替a.out。例如:
gcc -o count count.c
此時得到的可執行文件就不再是a.out,而是count。
3、執行文件
格式: ./可執行文件名
例:./a.out
./count
Ⅳ 關於c語言中變數有外部鏈接內部鏈接和無 鏈接怎麼理解
這部分內容是在程序的編譯和link層面談的。
一個大一些的工程往往不是只有一個程序文件,經常由好多C程序文件構成,有的時候裡面個別程序可能還用的其他語言,編碼完成後常常分別編譯,編譯完成再link到一起。某個C程序需要用到其他程序中定義過的變數,一般都加extern前綴,編譯時編譯器會預留訪問鏈接的空位,等到link階段再在整個工程的其他C編譯結果中去對號,把訪問鏈接填上。這就是外部鏈接。如果你程序全寫在一個文件里,那永遠都不會有外部鏈接。
內部鏈接常指一個程序文件中全局變數,可以被程序文件內各個子程序訪問,這在編譯過程中處理,和link階段不發生關系。如果變數前加了static,那麼它永遠不會被外部程序訪問,它不會被編譯程序寫入目標代碼的鏈接區。
無鏈接,就是在一個單體程序里,比如一個子程序,定義一個變數只給這個程序段用,那就是無鏈接。編譯器和link都不需要對這樣的變數做跨程序段的地址鏈接,這樣的變數都是直接分配寄存器或者近堆中的直接地址(每個子程序都有自己的基本存儲空間,被調用時得到分配,返回時被釋放,我習慣叫它近堆,標准叫啥早不記得了)。
變數是這樣,程序代碼段也大體差不多。每次在程序文件中調用一個文件內部的子程序,就產生一個內部鏈接;如果調用外部文件中的子程序,就產生一個外部鏈接。只有沒有任何子程序,所有代碼都寫在一個文件里的程序,才是無鏈接程序。
鏈接是個編譯和link層面的概念,所以不僅限於變數層面討論。
對了,再延伸,可以把一些子程序文件歸類,程序執行某部分任務才訪問,其他時間不訪問時,可以生成DLL。在程序執行那部分功能時,通過操作系統和DLL建立動態鏈接,當然這是外部鏈接,這也是程序設計中常用到的。這可以避免生成一個巨大的EXE,運行時吃掉過多的系統資源,還可以實現這個DLL中包含的子程序在操作系統級和其他程序共用。
Ⅵ 計算機二級C語言一道選擇題,求詳細解法!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
/*
* 此程序可以ls 多個文件
* 範例: ./myls file1 file2 dt1 dt2 後面參數可以多個,
*
*/
#include <pwd.h>
#include <grp.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <limits.h>
#include <time.h>
#include <stdio.h>
/*
* 讀取不是目錄的文件
* argv : 文件名
* 返回值: 出錯1, 正確0
*/
int lsregfile(char *argv) //讀取不是目錄的文件
{
struct stat buf;
if (lstat(argv, &buf) < 0) //讀取文件信息。
{
printf("%s:stat error\n",argv);
return 1;
}
char str[10] = "";
/******************判斷文件的類型***********************/
if (S_ISREG(buf.st_mode)) str[0] = '-';
else if (S_ISDIR(buf.st_mode)) str[0] = 'd';
else if (S_ISCHR(buf.st_mode)) str[0] = 'c';
else if (S_ISBLK(buf.st_mode)) str[0] = 'b';
else if (S_ISFIFO(buf.st_mode)) str[0] = 'p';
#ifdef S_ISLNK
else if (S_ISLNK(buf.st_mode)) str[0] = 'l';
#endif
#ifdef S_ISSOCK
else if (S_ISSOCK(buf.st_mode)) str[0] = 's';
#endif
else str[0] = 'U'; //表示未知文件類型
/************************* 輸出許可權 ************************/
str[1] = ((buf.st_mode & S_IRUSR) != 0) ? 'r' : '-';
str[2] = ((buf.st_mode & S_IWUSR) != 0) ? 'w' : '-';
str[3] = ((buf.st_mode & S_IXUSR) != 0) ? 'x' : '-';
//判斷設置-用戶-ID
str[3] = ((buf.st_mode & S_ISUID) != 0) ? 's' : str[3];
str[4] = ((buf.st_mode & S_IRGRP) != 0) ? 'r' : '-';
str[5] = ((buf.st_mode & S_IWGRP) != 0) ? 'w' : '-';
str[6] = ((buf.st_mode & S_IXGRP) != 0) ? 'x' : '-';
//判斷設置-用戶組-ID
str[6] = ((buf.st_mode & S_ISGID) != 0) ? 'x' : str[6];
str[7] = ((buf.st_mode & S_IROTH) != 0) ? 'r' : '-';
str[8] = ((buf.st_mode & S_IWOTH) != 0) ? 'w' : '-';
str[9] = ((buf.st_mode & S_IXOTH) != 0) ? 'x' : '-';
printf("%s ", str);
// 輸出硬鏈接數
printf("%3ld ", (long) buf.st_nlink);
// 輸出文件所有者。
struct passwd *ppd;
ppd = getpwuid(buf.st_uid);
printf("%-5s ", ppd->pw_name);
// 輸出文件所有者的組名
struct group *pgroup;
pgroup = getgrgid(buf.st_gid);
printf("%-5s ", pgroup->gr_name);
// 輸出文件大小
printf("%5lld ", (long long) buf.st_size);
// 輸出最近修改時間
struct tm *ptime = NULL;
ptime = gmtime(&buf.st_mtime);
printf("%.4d-%.2d-%.2d %.2d:%.2d ",
(1900 + ptime->tm_year),
(1 + ptime->tm_mon),
ptime->tm_mday,
ptime->tm_hour,
ptime->tm_min);
// 輸出文件名
printf("%s", argv);
if (str[0] == 'l') //如果是鏈接文件,獲取鏈接對象名
{
printf(" -> ");
char linkbuf[100] = "";
if (readlink(argv, linkbuf, sizeof(buf)) < 0 )
{
printf("%s: readlink error\n",argv);
return 1;
}
printf("%s", linkbuf);
}
printf("\n");
return 0;
}
/*
* 讀取目錄裡面不帶.和..的所有文件的信息.
* argv : 文件名
* 返回值: 出錯1, 正確0
*/
int lsdir(char *argv) //讀取目錄
{
printf("%s:\n", argv);
DIR *pread;
pread = opendir(argv);// 打開目錄
if (pread == NULL)
{
printf("%s: opendir error\n",argv);
return 1;
}
if (chdir(argv) < 0) //修改工作目錄 使下面的stat能成功.
{
printf("%s chdir error\n", argv);
return 1;
}
struct dirent *pd = NULL;
long long ssize = 0;
while ((pd = readdir(pread)) != NULL)
{
if ((!strcmp(pd->d_name, ".")) || (!strcmp(pd->d_name, "..")))
continue; //當文件為.或..時跳過。
struct stat buf;
if (lstat(pd->d_name, &buf) < 0) //讀取文件信息。
{
printf("%s: stat error\n", argv);
return 1;
}
char str[10] = "";
/******************判斷文件的類型***********************/
if (S_ISREG(buf.st_mode)) str[0] = '-';
else if (S_ISDIR(buf.st_mode)) str[0] = 'd';
else if (S_ISCHR(buf.st_mode)) str[0] = 'c';
else if (S_ISBLK(buf.st_mode)) str[0] = 'b';
else if (S_ISFIFO(buf.st_mode)) str[0] = 'p';
#ifdef S_ISLNK
else if (S_ISLNK(buf.st_mode)) str[0] = 'l';
#endif
#ifdef S_ISSOCK
else if (S_ISSOCK(buf.st_mode)) str[0] = 's';
#endif
else str[0] = 'U'; //表示未知文件類型
/************************* 輸出許可權 ************************/
str[1] = ((buf.st_mode & S_IRUSR) != 0) ? 'r' : '-';
str[2] = ((buf.st_mode & S_IWUSR) != 0) ? 'w' : '-';
str[3] = ((buf.st_mode & S_IXUSR) != 0) ? 'x' : '-';
//判斷設置-用戶-ID
str[3] = ((buf.st_mode & S_ISUID) != 0) ? 's' : str[3];
str[4] = ((buf.st_mode & S_IRGRP) != 0) ? 'r' : '-';
str[5] = ((buf.st_mode & S_IWGRP) != 0) ? 'w' : '-';
str[6] = ((buf.st_mode & S_IXGRP) != 0) ? 'x' : '-';
//判斷設置-用戶組-ID
str[6] = ((buf.st_mode & S_ISGID) != 0) ? 'x' : str[6];
str[7] = ((buf.st_mode & S_IROTH) != 0) ? 'r' : '-';
str[8] = ((buf.st_mode & S_IWOTH) != 0) ? 'w' : '-';
str[9] = ((buf.st_mode & S_IXOTH) != 0) ? 'x' : '-';
printf("%s ", str);
// 輸出硬鏈接數
printf("%3ld ", (long) buf.st_nlink);
// 輸出文件所有者。
struct passwd *ppd;
ppd = getpwuid(buf.st_uid);
printf("%-5s ", ppd->pw_name);
// 輸出文件所有者的組名
struct group *pgroup;
pgroup = getgrgid(buf.st_gid);
printf("%-5s ", pgroup->gr_name);
// 輸出文件大小
printf("%5lld ", (long long) buf.st_size);
ssize += buf.st_size;
// 輸出最近修改時間
struct tm *ptime = NULL;
ptime = gmtime(&buf.st_ctime);
printf("%.4d-%.2d-%.2d %.2d:%.2d ",
(1900 + ptime->tm_year),
(1 + ptime->tm_mon),
ptime->tm_mday,
ptime->tm_hour,
ptime->tm_min);
// 輸出文件名
printf("%s", pd->d_name);
if (str[0] == 'l') //如果是鏈接文件,獲取鏈接對象名
{
printf(" -> ");
char linkbuf[100] = "";
if (readlink(pd->d_name, linkbuf, sizeof(buf)) < 0 )
{
printf("%s: readlink error\n", argv);
return 1;
}
printf("%s", linkbuf);
}
printf("\n");
}
// 輸出總用量
printf("總用量 %lld\n", ssize/1024);
///////////////////////////////////////////////////////
if (closedir(pread) < 0) //關閉目錄
{
printf("%s: closedir error\n", argv);
return 1;
}
}
/*
*
* 這個程序,把非目錄文件和目錄分開讀。
*
*/
int main(int argc, char *argv[])
{
if (argc == 1)
{
printf("the argument is wrong\n");
exit(1);
}
int i;
for (i = 1; i < argc; ++i)
{
// 保存當前的工作目錄。以便返回當前工作目錄
char bufpwd[80];
char *getp =NULL;
getp = getcwd(bufpwd, sizeof(bufpwd));
if (getp == NULL)
{
printf("%s : getcwd error\n",argv[i]);
return 1;
}
struct stat buf0; //獲取文件信息
if (stat(argv[i], &buf0) < 0)
{
printf("%s: stat error\n", argv[i]);
continue; //出錯跳過
}
if (!S_ISDIR(buf0.st_mode)) //如果讀取的不是目錄。就直接去讀文件。
lsregfile(argv[i]); //讀文件
else
lsdir(argv[i]); //讀目錄
// 改變工作目錄回原來的工作目錄,以便讀取相對路徑的文件
if (chdir(bufpwd) < 0)
{
printf("%s : chdir error\n", argv[i]);
return 1;
}
}
return 0;
}
Ⅶ Unix系統中的link和ln命令有什麼區別
可以從man中找到答案。man link 然後 man ln。
前面是方法,這里是結論,
man中清楚看到,link功能簡單,只能製作硬鏈接,而ln有很多參數可以選。