递归bash脚本,用于收集有关目录结构中每个文件的信息

如何递归遍历目录树并对每个文件执行特定命令,并将路径,文件名,扩展名,文件大小和其他特定文本输出到bash中的单个文件。

关于为什么还没有人发布它,我有点困惑,但实际上bash确实有递归function,如果启用globstar选项并使用** glob。 因此,您可以编写(几乎)使用该递归globstar的纯bash脚本,如下所示:

 #!/usr/bin/env bash shopt -s globstar for i in ./**/* do if [ -f "$i" ]; then printf "Path: %s\n" "${i%/*}" # shortest suffix removal printf "Filename: %s\n" "${i##*/}" # longest prefix removal printf "Extension: %s\n" "${i##*.}" printf "Filesize: %s\n" "$(du -b "$i" | awk '{print $1}')" # some other command can go here printf "\n\n" fi done 

请注意,这里我们使用参数扩展来获取我们想要的文件名部分,除了使用du获取文件大小和使用awk清除输出之外,我们不依赖于外部命令。

当它遍历您的目录树时,您的输出应该是这样的:

 Path: ./glibc/glibc-2.23/benchtests Filename: sprintf-source.c Extension: c Filesize: 326 

脚本使用的标准规则适用:确保它可以使用chmod +x ./myscript.sh执行,并通过./myscript.sh从当前目录运行它,或者将它放在~/bin并运行source ~/.profile

虽然find解决方案简单而强大,但我决定创建一个更复杂的解决方案,这是基于这个有趣的function ,我几天前看到过。

  • 此处提供了基于当前的更多解释和另外两个脚本。

1.创建名为walk可执行脚本文件,该文件位于/usr/local/bin ,可作为shell命令访问:

 sudo touch /usr/local/bin/walk sudo chmod +x /usr/local/bin/walk sudo nano /usr/local/bin/walk 
  • 复制以下脚本内容并使用nanoShift + Insert进行粘贴; Ctrl + OEnter进行保存; 按Ctrl + X退出。

2.脚本walk的内容是:

 #!/bin/bash # Colourise the output RED='\033[0;31m' # Red GRE='\033[0;32m' # Green YEL='\033[1;33m' # Yellow NCL='\033[0m' # No Color file_specification() { FILE_NAME="$(basename "${entry}")" DIR="$(dirname "${entry}")" NAME="${FILE_NAME%.*}" EXT="${FILE_NAME##*.}" SIZE="$(du -sh "${entry}" | cut -f1)" printf "%*s${GRE}%s${NCL}\n" $((indent+4)) '' "${entry}" printf "%*s\tFile name:\t${YEL}%s${NCL}\n" $((indent+4)) '' "$FILE_NAME" printf "%*s\tDirectory:\t${YEL}%s${NCL}\n" $((indent+4)) '' "$DIR" printf "%*s\tName only:\t${YEL}%s${NCL}\n" $((indent+4)) '' "$NAME" printf "%*s\tExtension:\t${YEL}%s${NCL}\n" $((indent+4)) '' "$EXT" printf "%*s\tFile size:\t${YEL}%s${NCL}\n" $((indent+4)) '' "$SIZE" } walk() { local indent="${2:-0}" printf "\n%*s${RED}%s${NCL}\n\n" "$indent" '' "$1" # If the entry is a file do some operations for entry in "$1"/*; do [[ -f "$entry" ]] && file_specification; done # If the entry is a directory call walk() == create recursion for entry in "$1"/*; do [[ -d "$entry" ]] && walk "$entry" $((indent+4)); done } # If the path is empty use the current, otherwise convert relative to absolute; Exec walk() [[ -z "${1}" ]] && ABS_PATH="${PWD}" || cd "${1}" && ABS_PATH="${PWD}" walk "${ABS_PATH}" echo 

3.说明:

  • Zanna在她的回答中很好地描述了walk()函数的主要机制。 所以我只会描述新的部分。

  • walk()函数中我添加了这个循环:

     for entry in "$1"/*; do [[ -f "$entry" ]] && file_specification; done 

    这意味着对于每个$entry ,一个文件将执行函数file_specification()

  • 函数file_specification()包含两部分。 第一部分获取与文件相关的数据 – 名称,路径,大小等。第二部分以格式良好的forms输出数据。 要使用printf命令格式化数据。 如果你想调整脚本,你应该阅读这个命令 – 例如本文 。

  • 函数file_specification()是一个很好的地方,你可以在其中放置应该为每个文件执行的特定命令 。 使用以下格式:

      命令 “$ {entry}” 

    或者你可以将命令的输出保存为变量,然后printf这个变量等:

      MY_VAR =“$( 命令 ”$ {entry}“)”
     printf“%* s \ t文件大小:\ t $ {YEL}%s $ {NCL} \ n”$((缩进+4))''“$ MY_VAR” 

    或直接printf命令的输出:

      printf“%* s \ t文件大小:\ t $ {YEL}%s $ {NCL} \ n”$((缩进+4))''“$( 命令 ”$ {entry}“)” 

  • 乞讨部分称为Colourise the output ,初始化了printf命令中用于对输出进行着色的几个变量。 你可以在这里找到更多相关信息。

  • 在脚本的底部添加了处理绝对路径和相对路径的附加条件。

4.用法示例:

  • 要为当前目录运行walk

     walk # You shouldn't use any argument, walk ./ # but you can use also this format 
  • 要为任何子目录运行walk

     walk  walk ./ walk / 
  • 要为任何其他目录运行walk

     walk /full/path/to/ 
  • 要创建基于walk输出的文本文件:

     walk > output.file 
  • 要创建没有颜色代码的输出文件( 源 ):

     walk | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[mGK]//g" > output.file 

5.使用certificate:

在此处输入图像描述

您可以使用find来完成工作

 find /path/ -type f -exec ls -alh {} \; 

如果您只想列出所有文件大小,这将对您有所帮助。

-exec允许您为每个文件执行自定义命令或脚本\; 用于逐个解析文件,可以使用+; 如果你想连接它们(意思是文件名)。

只有find

 find /path/ -type f -printf "path:%h fileName:%f size:%kKB Some Text\n" > to_single_file 

或者,您可以使用以下代替:

 find -type f -not -name "to_single_file" -execdir sh -c ' printf "%s %s %s %s Some Text\n" "$PWD" "${1#./}" "${1##*.}" $(stat -c %s "$1") ' _ {} \; > to_single_file 

如果您知道树的深度,最简单的方法是使用通配符*

将您想要做的所有内容写为shell脚本或函数

 function thing() { ... } 

然后for i in *; do thing "$i"; done运行for i in *; do thing "$i"; done for i in *; do thing "$i"; done for i in *; do thing "$i"; donefor i in */*; do thing "$i"; done for i in */*; do thing "$i"; done for i in */*; do thing "$i"; done ,等等

在您的函数/脚本中,您可以使用一些简单的测试来挑出您想要使用的文件,并使用它们执行您需要的任何操作。

find可以做到这一点:

 find ./ -type f -printf 'Size:%s\nPath:%H\nName:%f\n' 

看看man find其他文件属性。

如果您确实需要扩展程序,可以添加以下内容:

 find ./ -type f -printf 'Size:%s\nPath:%H\nName:%f\nExtension:' -exec sh -c 'echo "${0##*.}\n"' {} \;