使用 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_Folder
和 mkdir -p
下创建,如果无法创建目录,则使用相同的错误处理。
ls
用作简单检查以验证以 ".pc"
结尾的文件是否存在于该目录中。还有其他方法可以通过将结果通过管道传输到 wc -l
来执行此操作,但最好避免产生额外的子外壳。[=59=]
(另请注意,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
消除了很多错误可以隐藏在您自己的解决方案中的区域。
如果您还有其他问题,请告诉我。
我遇到了(感觉上)一个相当简单的问题,但我在 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_Folder
和 mkdir -p
下创建,如果无法创建目录,则使用相同的错误处理。
ls
用作简单检查以验证以 ".pc"
结尾的文件是否存在于该目录中。还有其他方法可以通过将结果通过管道传输到 wc -l
来执行此操作,但最好避免产生额外的子外壳。[=59=]
(另请注意,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
消除了很多错误可以隐藏在您自己的解决方案中的区域。
如果您还有其他问题,请告诉我。