glob庫函數用於Linux文件系統中路徑名稱的模式匹配,即查找文件系統中指定模式的路徑。注意,這不是正則表達式匹配,雖然有些相似,但還是有點差別。
glob函數原型
#include <glob.h>
int glob(const char *pattern, int flags,
int errfunc(const char *epath, int eerrno),
glob_t *pglob);
glob函數搜索匹配 函數pattern中的參數,如/*是匹配根文件下的所有文件(不包括隱藏文件,要找的隱藏文件需要從新匹配),然后會將匹配出的結果存放到 pglob,即第4個參數中,第二個參數能選擇匹配模式,如是否排序,或者在函數第二次調用時,是否將匹配的內容追加到pglob中,等,第3個參數是查看錯誤信息用,一般置為NULL;
具體可以在終端下輸入 man glob
實例1:
1 #include <stdio.h>
2 #include <glob.h>
3
4 int main(int argc, const char *argv[]) 5 { 6 glob_t buf; 7 int i; 8 glob("/dev/*",GLOB_NOSORT, NULL, &buf); 9
10 for(i=0; i < buf.gl_pathc; i++) 11 { 12 printf("buf.gl_pathv[%d]= %s \n", i, (buf.gl_pathv[i])); 13 } 14
15 globfree(&buf); 16 return 0; 17 } 18
實例2:
在linux編程中,有時候會用到批量處理文件。比如寫一個上傳工具,用戶輸入文件名,如果此時用戶使用的是匹配的文件名,那么程序應該做到根據匹配字符串自動搜索符合要求的文件名的功能。
linux有一個glob函數,可以做到這一點,該函數位於頭文件glob.h中
事例:
1 #include <iostream>
2
3 #include <string>
4
5 #include <glob.h>
6
7 using namespace std; 8
9
10
11 void print_gl(glob_t &gl) 12
13 { 14
15 for(int i=0;i<gl.gl_pathc;i++) 16
17 { 18
19 cout<<gl.gl_pathv[i]<<endl; 20
21 } 22
23 } 24
25
26
27 void test_glob(int argc , char **argv) 28
29 { 30
31 glob_t gl; 32
33 for(int i=1;i<argc;i++) 34
35 { 36
37 gl.gl_offs=0; 38
39 glob(argv[i],GLOB_TILDE,0,&gl); 40
41 print_gl(gl); 42
43 globfree(&gl); 44
45 } 46
47 } 48
49
50
51 int main(int argc,char **argv) 52
53 { 54
55 if(argc<2) 56
57 { 58
59 cout<<"<file name>"<<endl; 60
61 return 0; 62
63 } 64
65
66
67 test_glob(argc,argv); 68
69 return 0; 70
71 }
實例3:
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4
5 #include <glob.h>
6
7 static int test_fun(int, char *[]); 8 static void print_gl(glob_t *); 9
10 int main(int argc, char *argv[]) 11 { 12 if(argc > 1) 13 test_fun(argc, argv); 14 else
15 printf("./mytest {/"path list/"}/n"); 16 return 0; 17 } 18
19 static int test_fun(int argc, char *argv[]) 20 { 21 glob_t gl; 22 for(int i = 1; i < argc; ++i) { 23 gl.gl_offs = 0; 24 glob(argv[i], GLOB_TILDE, 0, &gl); 25 print_gl(&gl); 26 globfree(&gl); 27 } 28 return 0; 29 } 30
31 static void print_gl(glob_t *gl) 32 { 33 for(unsigned int i = 0; i < gl->gl_pathc; ++i) 34 printf("%s/n", gl->gl_pathv[i]); 35 printf("++++++++++++++++++++++/n"); 36 }
編譯:
gcc -std=c99 -g -W -Wall -Wextra -o mytest main.c
執行示例:
./mytest "./*.cpp" "./*.h" "./make*" "~/p*/p?ng"
注意:上訴命令中引號是必需的,否則shell會將模式展開!
實例4:
用glob的遞歸調用可以找到系統任意路徑的所有文件。如下例子:
1 #include <stdio.h>
2 #include <glob.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <sys/types.h>
6 #include <sys/stat.h>
7 #include <unistd.h>
8
9 static int OpenDir(const char *buf) 10 { 11 int ret; 12 char path[50] = {0}; 13 char temp[50] = {0}; 14 char *tp = NULL; 15 glob_t globbuf; 16 struct stat fileinfo; 17 int i; 18 char *ptr = NULL,*last_ptr = NULL; 19 strcpy(path,buf); 20 if(buf[strlen(buf)- 1] == '/') 21 strcat(path,"*"); 22 else
23 strcat(path,"/*"); 24 if((ret = glob(path,GLOB_NOSORT,NULL,&globbuf)) != 0){ 25 if(GLOB_NOMATCH == ret) 26 return 0; 27 else
28 return -1; 29 } 30 strcpy(path,buf); 31 if(buf[strlen(buf)- 1] == '/') 32 strcat(path,".*"); 33 else
34 strcat(path,"/.*"); 35
36 if((ret = glob(path,GLOB_APPEND,NULL,&globbuf)) != 0){ 37 if(GLOB_NOMATCH == ret) 38 return 0; 39 else
40 return -1; 41 } 42 for(i = 0;i < globbuf.gl_pathc;i++){ 43 ret = lstat(globbuf.gl_pathv[i],&fileinfo); 44 if(ret != 0){ 45 perror("lstat()"); 46 return -1; 47 } 48 if(1 == S_ISDIR(fileinfo.st_mode)){ 49 printf("\n%s is directory!\n",globbuf.gl_pathv[i]); 50 strcpy(temp,globbuf.gl_pathv[i]); 51 tp = temp; 52 while((last_ptr = strsep(&tp,"/")) != NULL){ 53 ptr = last_ptr; 54 } 55 if((strcmp(ptr,".") == 0) || (strcmp(ptr,"..") == 0)) 56 continue; 57 ret = OpenDir(globbuf.gl_pathv[i]); 58 if(ret != 0){ 59 printf("*****opendir() error!\n"); 60 } 61 } 62 else
63 { 64 printf("%s\n",globbuf.gl_pathv[i]); 65 } 66 } 67 return 0; 68 } 69 int main(int argc, char *argv[]) 70 { 71 glob_t globbuf; 72 int ret ; 73 struct stat fileinfo; 74 int i; 75 if(argc != 2){ 76 printf("argument error!\n"); 77 } 78 ret = OpenDir(argv[1]); 79 if(ret != 0){ 80 printf("opendir() error!\n"); 81 return -1; 82 } 83 return 0; 84 }
執行如下命令獲取當前路徑中所有文件:
[tom@localhost glob]$ ./glob ./
./dir2 is directory!
./glob.c
./glob
./dir1 is directory!
./dir1/file2
./dir1/file1
./dir1/. is directory!
./dir1/.. is directory!
./. is directory!
./.. is directory!
可以看到 當前路徑下有dir1 和dir2 兩個目錄,其中dir2為空目錄,dir1中有file1和file2兩個文件,.和..兩個隱藏文件以及程序源碼glob.c和可執行程序文件glob。
注意:
假設你有一個文件夾,你要刪除里面類似這樣命名的文件 :; ?1 t& z j3 M9 N9 r' D- t; g
/path/to/dir/000000 - Smooth Faker
/path/to/dir/000000 - Rubber Hocker8 w/ C( r5 S. v" P! w- N+ e% {
...$ S2 n$ q0 t2 w
, F/ r" _! \* ~: V6 k/ x( _
在 perl 里你可以用很多方法得到這樣的文件列表(TIMTOWTDI),諸如opendir后grep, find函數,當然還有更容易讓shell迷想起的glob函數。 不過關於glob函數,這里有個很大的陷阱,如果不注意他將可能導致災難后果,比如:. i K" a. T% t ^
, s5 z. J8 R* t8 C
unlink glob("/path/to/dir/000000 - *");1 u' F2 |! P! P
看上去似乎沒問題,但這個危險的操作可以刪除你當前文件下的的所有文件。
; t; _$ H% u4 f7 ^5 A/ F- a$ ~
讓我們仔細看文檔, perldoc File::Glob :
Since v5.6.0, Perl’s CORE::glob() is implemented in terms of' Y3 R$ R- ^0 b9 |* h. j
bsd_glob(). Note that they don’t share the same
prototype--CORE::glob() only accepts a single argument. Due to
historical reasons, CORE::glob() will also split its argument on% e% t6 u- ] q' b9 \( q6 j7 W& O$ J0 N; U
whitespace, treating it as multiple patterns, whereas bsd_glob()/ i$ N! j# Y$ }# g
considers them as one pattern.
也就是說,這里的 glob 操作變成了, File::Glob::bsd_glob("/path/to/dir/00000", "-", "*"), 你將會刪掉'*'匹配的所有文件。解決辦法是用雙引號括起整個部分,或者使用File::Glob::bsd_glob。
- r- J" O9 \7 ?3 i( H
按理這個是已經在文檔中說明了,不應該算是陷阱,不過如果你僅僅用 perldoc -f glob 查看,那么並沒有類似的說明和警告而是讓你轉而看 File::Glob 的說明。(常常的)偷懶和想當然的結果就是,忽視了這里最大的一個可能引爆的漏洞。所以這里的建議是不使用glob而是使用File::Glob::bsd_glob。