递归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
- 复制以下脚本内容并使用
nano
: Shift + Insert进行粘贴; Ctrl + O和Enter进行保存; 按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"; done
, for 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"' {} \;