使用 bash 遍历嵌套文件夹到当前工作目录中的 运行 脚本

Using bash to loop through nested folders to run script in current working directory

我遇到了(感觉上)一个相当简单的问题,但我在 bash 方面完全缺乏经验,这让我很困惑。我花了一整天的时间尝试从许多不同的 SO 线程中合成一个脚本,解释如何使用不直观的命令执行特定的操作,但我无法弄清楚如何让它们在我的生活中一起工作。

这是我的情况:我有一个充满嵌套文件夹的目录,每个文件夹包含一个扩展名为 .7 的文件和另一个扩展名为 .pc 的文件,以及一大堆不相关的东西。它看起来像这样:

Folder A
   Folder 1
      Folder x
        data_01.7
        helper_01.pc
        ...
      Folder y
        data_02.7
        helper_02.pc
        ...
   ...
   Folder 2
      Folder z
        data_03.7
        helper_03.pc
      ...
   ...
Folder B
...

我有一个脚本,我需要 运行 将 .7 文件的名称作为输入的每个文件夹中。

pc_script -f data.7 -flag1 -other_flags

当 运行 运行脚本时,当前工作目录需要是包含 .7 文件的文件夹,并且 helper.pc 文件也需要存在于其中。脚本完成 运行ning 后,会出现大量新文件和目录。但是,我只需要获取其中一个输出文件 result.h5,并将其复制到保持相同文件夹结构但使用新名称的新目录:

Result Folder/Folder A/Folder 1/Folder x/new_result1.h5

然后我需要使用不同的标志 flag2 再次 运行 相同的脚本,并将该输出文件的新版本复制到具有不同名称 new_result2 的相同结果目录。 h5。 尽管没有任何空格或下划线以外的特殊字符,但所有文件夹的名称都非常随意。

这是我尝试过的示例:

#!/bin/bash

DIR=".../project/data"
for d in */ ; do
    for e in */ ; do
        for f in */ ; do
            for PFILE in *.7 ; do
                echo "$d/$e/$f/$PFILE"
                cd "$DIR/$d/$e/$f"
                echo "Performing operation 1"
                pc_script -f "$PFILE" -flag1
                mkdir -p ".../results/$d/$e/$f"
                mv "results.h5" ".../project/results/$d/$e/$f/new_results1.h5"
                echo "Performing operation 2"
                pc_script -f "$PFILE" -flag 2
                mv "results.h5" ".../project/results/$d/$e/$f/new_results2.h5"
            done
        done
    done
done

显然,这没有用。我也尝试过将 find 与 -execdir 一起使用,但后来我不知道如何将文件名插入脚本标志。对于如何执行此操作的任何帮助或建议,我将不胜感激。

另一个可能更灵活的解决问题的方法是使用 find 命令和 -exec 选项 运行 一个简短的“helper-script”在以 ".7" 结尾的目录路径下找到的文件。 -name 选项允许 find 使用简单的 file-globbing(通配符)在给定目录下找到所有以 ".7" 结尾的文件。 helper-script 然后对 find 找到的每个文件执行相同的操作,并处理将 result.h5 移动到正确的目录。

命令的格式为:

find /path/to/search -type f -name "*.7" -exec /path/to/helper-script '{}` \;

其中 -f 选项告诉 find 仅 return 个以 ".7" 结尾的文件(不是目录)。您的 helper-script 需要 可执行 (例如 chmod +x helper-script),除非它在您的 PATH 中,否则您必须提供脚本的完整路径查找命令。 '{}' 将被文件名(包括相对路径)替换并作为参数传递给您的 helper-script\; 只是终止由 -exec 执行的命令。

(请注意 -exec 的另一种形式称为 -execdir 和另一个终止符 '+' 可用于处理给定目录中所有文件的命令 - 即更安全一点,但对 运行 命令有额外的 PATH 要求。因为你只有一个 ".7" 文件 per-directory -- 这里没有太多好处)

helper-script只是在每个目录中做你需要做的。根据您的描述,它可能类似于以下内容:

#!/bin/bash

dir="${1%/*}"     ## trim file.7 from end of path
cd "$dir" || {    ## change to directory or handle error
  printf "unable to change to directory %s\n" "$dir" >&2
  exit 1
}

destdir="/Result_Folder/$dir"   ## set destination dir for result.h5
mkdir -p "$destdir" || {        ## create with all parent dirs or exit
  printf "unable to create directory %s\n" "$dir" >&2
  exit 1
}

ls *.pc 2>/dev/null || exit 1   ## check .pc file exists or exit

file7="${1##*/}"  ## trim path from file.7 name

pc_script -f "$file7" -flags1 -other_flags    ## first run

## check result.h5 exists and non-empty and copy to destdir
[ -s "result.h5" ] && cp -a "result.h5" "$destdir/new_result1.h5"

pc_script -f "$file7" -flags2 -other_flags    ## second run

## check result.h5 exists and non-empty and copy to destdir
[ -s "result.h5" ] && cp -a "result.h5" "$destdir/new_result2.h5"

本质上将 file.7 参数的路径部分存储在 dir 中并更改到该目录。如果无法更改到目录(由于 read-permissions,等等),将处理错误并退出脚本。接下来,完整的目录结构将在您的 Result_Foldermkdir -p 下创建,如果无法创建目录,则使用相同的错误处理。

ls 用作简单检查以验证以 ".pc" 结尾的文件是否存在于该目录中。还有其他方法可以通过将结果通过管道传输到 wc -l 来执行此操作,但最好避免产生额外的子外壳。[=5​​9=]

(另请注意,Linux 和 Mac 的文件以 ".pc" 结尾,供 pkg-config 在从源代码构建程序时使用——它们不应与您的文件 - 但请注意它们存在,以防您开始追查为什么找到奇怪的 ".pc" 文件)

执行完所有测试后,路径将从当前 ".7" 文件名中删除,仅存储 file7 中的文件名。 file7 变量然后用于您的 pc_script 命令(如果不在您的 PATH 中,它还应该包括脚本的完整路径)。在 pc_script 是 运行 之后,[ -s "result.h5" ] 用于验证 result.h5 存在并且是 non-empty,然后再将该文件移动到您的 Result_Folder 位置。

这应该可以帮助您入门。使用 find 查找所有 .7 文件是一种让旨在为您查找文件的工具完成其工作的简单方法,而不是尝试 hand-roll 您自己的解决方案。这样您只需要专注于应该为找到的每个文件做些什么。 (注意:我没有 pc_script 或文件,所以我没有测试这个 end-to-end,但如果没有 right-on-the-money 应该非常接近)

编写您自己的例程没有错,但是使用 find 消除了很多错误可以隐藏在您自己的解决方案中的区域。

如果您还有其他问题,请告诉我。