递归遍历某一路径下的所有文件

博客介绍了递归遍历某一路径下所有文件的方法,分别给出了Windows和Linux系统的实现方式。Windows下使用FindFirstFile和FindNextFile,Linux下使用opendir和readdir,并给出了具体的函数代码,且代码均通过编译和正常执行。

递归遍历某一路径下的所有文件


    在windows下,可以使用FindFirstFile和FindNextFile来实现。
    而在Linux下,则可以使用opendir和readdir来实现。

    具体实现见下面两个函数,分别实现了打印某一路径下的所有
文件,包括子目录下的文件。在具体实现的时候需要注意设置路径。

注:
    下面两个程序都通过编译通过,且正常执行。
    windows下使用VC6.0编译;
    Linux下使用gcc 3.4.3编译。

//for windows
void findAllFile(char * pFilePath)
{
 
 WIN32_FIND_DATA FindFileData;
 HANDLE hFind = INVALID_HANDLE_VALUE;
 char DirSpec[MAX_PATH + 1];  // directory specification
 DWORD dwError;
 
 strncpy (DirSpec, pFilePath, strlen(pFilePath) + 1);
 SetCurrentDirectory(pFilePath);
 strncat (DirSpec, "//*", 3);
 
 hFind = FindFirstFile(DirSpec, &FindFileData);
 
 if (hFind == INVALID_HANDLE_VALUE)
 {
  printf ("Invalid file handle. Error is %u/n", GetLastError());
  return ;
 }
 else
 {
  if (FindFileData.dwFileAttributes != FILE_ATTRIBUTE_DIRECTORY )
  {
   printf ("    %s/n", FindFileData.cFileName);
  }
  else if(FindFileData.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY
   && strcmp(FindFileData.cFileName, ".") != 0
   && strcmp(FindFileData.cFileName, "..") != 0)
  {
   char Dir[MAX_PATH + 1];
   strcpy(Dir, pFilePath);
   strncat(Dir, "//", 2);
   strcat(Dir, FindFileData.cFileName);
   
   findAllFile(Dir);
  }
  
  while (FindNextFile(hFind, &FindFileData) != 0)
  {
   if (FindFileData.dwFileAttributes != FILE_ATTRIBUTE_DIRECTORY)
   {
    printf ("    %s/n", FindFileData.cFileName);
   }
   else if(FindFileData.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY
    && strcmp(FindFileData.cFileName, ".") != 0
    && strcmp(FindFileData.cFileName, "..") != 0)
   {
    char Dir[MAX_PATH + 1];
    strcpy(Dir, pFilePath);
    strncat(Dir, "//", 2);
    strcat(Dir, FindFileData.cFileName);
    findAllFile(Dir);
   }
   
  }
  
  dwError = GetLastError();
  FindClose(hFind);
  if (dwError != ERROR_NO_MORE_FILES)
  {
   printf ("FindNextFile error. Error is %u/n", dwError);
   return;
  }
 }
}


//for linux
void findAllFile(char * pFilePath)
{
 DIR * dir;
 dirent * ptr;
 struct stat stStatBuf;
 chdir(pFilePath);
        dir = opendir(pFilePath);
 while ((ptr = readdir(dir)) != NULL)
     {
  if (stat(ptr->d_name, &stStatBuf) == -1)
  {
   printf("Get the stat error on file:%s/n", ptr->d_name);
   continue;
  }
  if ((stStatBuf.st_mode & S_IFDIR) && strcmp(ptr->d_name, ".") != 0
    && strcmp(ptr->d_name, "..") != 0)
  {
   char Path[MAX_PATH];
   strcpy(Path, pFilePath);
   strncat(Path, "/", 1);
   strcat(Path, ptr->d_name);
   findAllFile(Path);
  }
  if (stStatBuf.st_mode & S_IFREG)
  {
   printf("  %s/n", ptr->d_name);
  }
  //this must change the directory , for maybe changed in the recured

function 
  chdir(pFilePath);
 }
     closedir(dir);
}

<think>我们有一个用户问题:“我想查找在Shell脚本中遍历指定下所有文件的方法请问如何在Shell脚本中遍历一路下的所有文件”根据提供的引用,我们有几种方法可以实现遍历指定下的所有文件。引用[3]提供了一个递归遍历目录及其子目录的脚本,使用函数递归的方法。引用[2]则展示了遍历指定目录下特定类型文件(例如.h文件)的方法,并检查文件内容。用户需求是遍历指定下的所有文件(包括子目录),我们可以提供两种常见方法:1.使用find命令:这是最常用的方法,可以递归列出所有文件。2.使用递归函数:如引用[3]所示,通过函数递归遍历每个目录。另外,如果只需要当前目录下的文件(不包括子目录),可以使用简单的for循环。根据用户问题,我们需要遍历所有文件(包括子目录),所以重点在递归遍历。下面我们提供两种方法,并给出示例脚本。方法一:使用find命令在脚本中,我们可以使用find命令来递归查找指定下的所有文件,然后对每个文件进行操作。方法二:使用递归函数(如引用[3]的方法)我们将分别展示这两种方法。注意:用户问题中并没有要求对文件做什么操作,所以示例中我们只是打印文件名。另外,我们还需要考虑路中可能包含空格等特殊字符的情况,因此要正确处理。在方法一中,使用find的-print0和xargs-0可以处理空格,或者使用whileread循环。方法二中使用`ls`可能会遇到空格问题,因此我们改为使用`find`或者使用`for`循环配合通配符(但通配符在递归中不好用),所以递归函数中我们使用`find`命令或者改变内部字段分隔符(IFS)来避免空格问题。但为了简单和健壮性,方法一更推荐。这里我们提供两个版本的示例:版本1:使用find命令(推荐)版本2:递归函数(注意:递归函数在处理大量文件时可能效率较低,且需要小心处理空格)我们先写版本1(使用find)的脚本:示例脚本1(使用find):```bash#!/bin/bash#检查是否提供了路参数if[$#-ne1];thenecho"Usage:$0<directory>"exit1fidir="$1"#使用find命令遍历所有文件find"$dir"-typef-print0|whileIFS=read-r-d''file;doecho"处理文件:$file"#这里可以添加其他操作,比如删除、复制等done```这个脚本使用`find`命令查找指定目录下的所有普通文件(不包括目录),并使用`print0`以null字符分隔文件名,然后通过`whileread`循环读取每个文件。这样可以安全处理文件名中的空格、换行等特殊字符。版本2:递归函数(类似引用[3]的方法,但改进处理空格)引用[3]的脚本使用`ls`来列出文件,这会导致空格问题。我们可以改为使用`find`或者使用`IFS`和通配符。但是,在递归函数中,我们可以通过设置IFS和使用`-printf`来避免,但这里我们使用更安全的方法:用`find`命令来实现递归,或者使用`while`循环和`find`命令。不过,为了展示递归函数,我们采用设置IFS的方法。注意:在递归函数中,使用通配符`*`会忽略隐藏文件(以.开头的文件)。如果需要包含隐藏文件,可以设置`shopt-sdotglob`(在bash中)。示例脚本2(递归函数,包含隐藏文件):```bash#!/bin/bash#递归遍历函数traverse(){localdir="$1"#设置支持隐藏文件shopt-sdotglobforfilein"$dir"/*;doif[-f"$file"];thenecho"文件:$file"elif[-d"$file"];thenecho"进入目录:$file"traverse"$file"fidoneshopt-udotglob}#检查参数if[$#-ne1];thenecho"Usage:$0<directory>"exit1fi#调用函数traverse"$1"```但是,这个脚本仍然不能处理文件名中包含空格的情况,因为`forfilein"$dir"/*`中,每个文件都被正确引用,所以可以处理空格。因为我们在循环中使用了`"$dir"/*`,并且循环变量`file`被双引号引用(在[-f"$file"]中),所以可以处理空格。但是,这个脚本不会列出隐藏文件(因为`*`不包括以`.`开头的文件),尽管我们设置了`dotglob`,但是`"$dir"/*`还是不会匹配隐藏文件。实际上,`dotglob`设置后,`*`会匹配隐藏文件。所以这个脚本可以包含隐藏文件。然而,需要注意的是,在递归遍历中,我们可能会遇到符号链接指向目录的情况,上面的函数会递归进入符号链接指向的目录,这可能会导致无限循环(如果存在循环链接)。为了避免这种情况,我们可以使用`find`或者跳过符号链接。因此,对于生产环境,我们更推荐使用`find`命令,因为它更健壮且功能强大。根据用户需求,我们提供了两种方法。接下来,我们生成相关问题。注意:用户的问题是关于遍历文件,所以相关问题可以围绕遍历文件时的其他需求(如查找特定文件、执行操作等)以及注意事项(如处理空格、大量文件等)来提问。生成问题:1.如何只遍历当前目录下的文件(不包括子目录)?2.如何在遍历文件时忽略隐藏文件?3.如何处理文件名中的特殊字符(如空格、换行符)?4.如何避免递归进入符号链接目录?5.如何查找特定类型的文件(如.txt文件)并进行操作?我们将按照要求回答用户问题,并附上相关问题。</think>### Shell脚本中遍历指定下所有文件的方法 在Shell脚本中遍历指定下的所有文件(包括子目录),主要有以下两种常用方法: #### 方法一:使用 `find` 命令(推荐) ```bash #!/bin/bash # 检查参数 if [ $# -ne 1 ]; then echo "Usage: $0 <directory>" exit 1 fi target_dir="$1" # 递归遍历所有文件 find "$target_dir" -type f | while read -r file; do echo "找到文件: $file" # 这里可添加文件操作(如删除、复制等) # rm -f "$file" done ``` **说明**: 1. `find "$target_dir" -type f`:递归查找所有普通文件(排除目录) 2. `while read -r file`:逐行读取结果,安全处理文件名中的空格 3. 支持隐藏文件(以`.`开头的文件) #### 方法二:递归函数遍历(参考引用[3]) ```bash #!/bin/bash traverse_files() { local dir="$1" for item in "$dir"/*; do if [ -f "$item" ]; then echo "文件: $item" elif [ -d "$item" ]; then echo "进入目录: $item" traverse_files "$item" # 递归遍历目录 fi done } # 检查参数 if [ $# -ne 1 ]; then echo "Usage: $0 <directory>" exit 1 fi traverse_files "$1" ``` **注意事项**: 1. **空格处理**:使用双引号包裹变量(如 `"$item"`) 2. **隐藏文件**:默认不包含,若需要可添加 `shopt -s dotglob` 3. **符号链接**:`find` 默认跟随链接,添加 `-P` 参数禁用(如 `find -P ...`) 4. **性能**:对于大型目录,`find` 比递归函数效率更高 ### 应用示例 删除指定目录下所有 `.tmp` 文件: ```bash find "/path/to/dir" -type f -name "*.tmp" -exec rm -f {} \; ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值