我如何通过目录树递归工作并在每个文件上执行特定命令,然后将路径,文件名,扩展名,文件大小和其他一些特定文本输出到bash中的单个文件中。
我如何通过目录树递归工作并在每个文件上执行特定命令,然后将路径,文件名,扩展名,文件大小和其他一些特定文本输出到bash中的单个文件中。
Answers:
尽管find
解决方案既简单又强大,但我还是决定创建一个更复杂的解决方案,该解决方案基于几天前看到的这个有趣的功能。
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.说明:
walk()
Zanna在回答中很好地描述了该功能的主要机制。因此,我将仅描述新部分。
在walk()
函数中,我添加了以下循环:
for entry in "$1"/*; do [[ -f "$entry" ]] && file_specification; done
这意味着将为每个$entry
文件执行该函数file_specification()
。
该功能file_specification()
分为两个部分。第一部分获取与文件相关的数据-名称,路径,大小等。第二部分以格式正确的格式输出数据。要格式化数据,请使用命令printf
。如果要调整脚本,则应阅读有关此命令的信息-例如本文。
该函数file_specification()
是放置每个文件应执行的特定命令的好地方。使用以下格式:
命令 “ $ {entry}”
或者,您可以将命令的输出另存为变量,然后printf
将该变量另存为:
MY_VAR =“ $(命令 ” $ {entry}“)” printf“%* s \ t文件大小:\ t $ {YEL}%s $ {NCL} \ n” $((indent + 4))''“ $ MY_VAR”
或直接printf
输出命令:
printf“%* s \ t文件大小:\ t $ {YEL}%s $ {NCL} \ n” $((indent + 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 <directory name>
walk ./<directory name>
walk <directory name>/<sub directory>
要运行walk
其他目录:
walk /full/path/to/<directory name>
要基于walk
输出创建文本文件:
walk > output.file
要创建没有颜色代码的输出文件(源):
walk | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[mGK]//g" > output.file
5.用法说明:
对于为什么没有人发布它,我有些困惑,但是bash
如果启用globstar
option并使用**
glob ,则确实具有递归功能。这样,您可以编写(几乎)bash
使用该递归globstar的纯脚本,如下所示:
#!/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
run中source ~/.profile
。
"$(file "$i")"
(在上面的脚本中作为printf的第二部分)返回的MIME信息?
output the path, filename, extension, filesize
,因此答案与所要的相匹配。:)
你可以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
find -printf
)。+1
如果您知道树的深度,最简单的方法就是使用通配符 *
。
写出您想作为shell脚本或函数执行的所有操作
function thing() { ... }
然后运行for i in *; do thing "$i"; done
,for i in */*; do thing "$i"; done
...等
在函数/脚本中,您可以使用一些简单的测试来选择要使用的文件,并对它们进行任何处理。
$i
。
for i in */*
运作方式。在这里进行测试:for i in */*; do printf "|%s|\n" "$i"; done