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

SPo*_*eSS 15 command-line bash scripts

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

pa4*_*080 19

虽然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
Run Code Online (Sandbox Code Playgroud)
  • 复制以下脚本内容并在nano: Shift+ 中Insert用于粘贴;Ctrl+OEnter保存;Ctrl+X退出。

2、脚本内容walk为:

sudo touch /usr/local/bin/walk
sudo chmod +x /usr/local/bin/walk
sudo nano /usr/local/bin/walk
Run Code Online (Sandbox Code Playgroud)

3.说明:

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

  • 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                    
    
    Run Code Online (Sandbox Code Playgroud)

    这意味着对于每个$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)) '' "$( command "${entry}")"

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

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

4.用法示例:

  • walk当前目录运行:

    for entry in "$1"/*; do [[ -f "$entry" ]] && file_specification; done
    
    Run Code Online (Sandbox Code Playgroud)
  • walk为任何子目录运行:

    command "${entry}"
  • walk为任何其他目录运行:

    MY_VAR="$(command "${entry}")"
    printf "%*s\tFile size:\t${YEL}%s${NCL}\n" $((indent+4)) '' "$MY_VAR"
  • 要根据walk输出创建文本文件:

    printf "%*s\tFile size:\t${YEL}%s${NCL}\n" $((indent+4)) '' "$(command "${entry}")"
  • 要创建没有颜色代码的输出文件():

    walk      # You shouldn't use any argument, 
    walk ./   # but you can use also this format
    
    Run Code Online (Sandbox Code Playgroud)

5.使用演示:

在此处输入图片说明


Ser*_*nyy 14

我有点不明白为什么还没有人发布它,但bash如果您启用globstar选项并使用**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
Run Code Online (Sandbox Code Playgroud)

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

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

Path: ./glibc/glibc-2.23/benchtests
Filename: sprintf-source.c
Extension: c
Filesize: 326
Run Code Online (Sandbox Code Playgroud)

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


Raj*_*ran 12

你可以find用来做这项工作

find /path/ -type f -exec ls -alh {} \;
Run Code Online (Sandbox Code Playgroud)

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

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


αғs*_*нιη 6

随着find而已。

find /path/ -type f -printf "path:%h  fileName:%f  size:%kKB Some Text\n" > to_single_file
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

  • 优雅而简单(如果您了解`find -printf`)。+1 (2认同)