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:
#include <stdio.h>
#include <glob.h>
int main(int argc, const char *argv[])
{
glob_t buf;
int i;
glob("/dev/*",GLOB_NOSORT, NULL, &buf);
for(i=0; i < buf.gl_pathc; i++)
{
printf("buf.gl_pathv[%d]= %s \n", i, (buf.gl_pathv[i]));
}
globfree(&buf);
return 0;
}
实例2:
在linux编程中,有时候会用到批量处理文件。比如写一个上传工具,用户输入文件名,如果此时用户使用的是匹配的文件名,那么程序应该做到根据匹配字符串自动搜索符合要求的文件名的功能。
linux有一个glob函数,可以做到这一点,该函数位于头文件glob.h中
#include <iostream>
#include <string>
#include <glob.h>
using namespace std;
void print_gl(glob_t &gl)
{
for(int i=0;i<gl.gl_pathc;i++)
{
cout<<gl.gl_pathv[i]<<endl;
}
}
void test_glob(int argc , char **argv)
{
glob_t gl;
for(int i=1;i<argc;i++)
{
gl.gl_offs=0;
glob(argv[i],GLOB_TILDE,0,&gl);
print_gl(gl);
globfree(&gl);
}
}
int main(int argc,char **argv)
{
if(argc<2)
{
cout<<"<file name>"<<endl;
return 0;
}
test_glob(argc,argv);
return 0;
}
实例3:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <glob.h>
static int test_fun(int, char *[]);
static void print_gl(glob_t *);
int main(int argc, char *argv[])
{
if(argc > 1)
test_fun(argc, argv);
else
printf("./mytest {/"path list/"}/n");
return 0;
}
static int test_fun(int argc, char *argv[])
{
glob_t gl;
for(int i = 1; i < argc; ++i) {
gl.gl_offs = 0;
glob(argv[i], GLOB_TILDE, 0, &gl);
print_gl(&gl);
globfree(&gl);
}
return 0;
}
static void print_gl(glob_t *gl)
{
for(unsigned int i = 0; i < gl->gl_pathc; ++i)
printf("%s/n", gl->gl_pathv[i]);
printf("++++++++++++++++++++++/n");
}
编译:
gcc -std=c99 -g -W -Wall -Wextra -o mytest main.c
执行示例:
./mytest "./*.cpp" "./*.h" "./make*" "~/p*/p?ng"
注意:上诉命令中引号是必需的,否则shell会将模式展开!
实例4:
用glob的递归调用可以找到系统任意路径的所有文件。如下例子:
#include <stdio.h>
#include <glob.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
static int OpenDir(const char *buf)
{
int ret;
char path[50] = {0};
char temp[50] = {0};
char *tp = NULL;
glob_t globbuf;
struct stat fileinfo;
int i;
char *ptr = NULL,*last_ptr = NULL;
strcpy(path,buf);
if(buf[strlen(buf)- 1] == '/')
strcat(path,"*");
else
strcat(path,"/*");
if((ret = glob(path,GLOB_NOSORT,NULL,&globbuf)) != 0){
if(GLOB_NOMATCH == ret)
return 0;
else
return -1;
}
strcpy(path,buf);
if(buf[strlen(buf)- 1] == '/')
strcat(path,".*");
else
strcat(path,"/.*");
if((ret = glob(path,GLOB_APPEND,NULL,&globbuf)) != 0){
if(GLOB_NOMATCH == ret)
return 0;
else
return -1;
}
for(i = 0;i < globbuf.gl_pathc;i++){
ret = lstat(globbuf.gl_pathv[i],&fileinfo);
if(ret != 0){
perror("lstat()");
return -1;
}
if(1 == S_ISDIR(fileinfo.st_mode)){
printf("\n%s is directory!\n",globbuf.gl_pathv[i]);
strcpy(temp,globbuf.gl_pathv[i]);
tp = temp;
while((last_ptr = strsep(&tp,"/")) != NULL){
ptr = last_ptr;
}
if((strcmp(ptr,".") == 0) || (strcmp(ptr,"..") == 0))
continue;
ret = OpenDir(globbuf.gl_pathv[i]);
if(ret != 0){
printf("*****opendir() error!\n");
}
}
else
{
printf("%s\n",globbuf.gl_pathv[i]);
}
}
return 0;
}
int main(int argc, char *argv[])
{
glob_t globbuf;
int ret ;
struct stat fileinfo;
int i;
if(argc != 2){
printf("argument error!\n");
}
ret = OpenDir(argv[1]);
if(ret != 0){
printf("opendir() error!\n");
return -1;
}
return 0;
}
执行如下命令获取当前路径中所有文件:
[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% {
...S2nS2n 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; _HH ~
让我们仔细看文档, 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()/ iN! j# YN! 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。