首页 > 解决方案 > 在当前目录中的所有目录和子目录中搜索与文件扩展名列表匹配的文件。将这些文件复制到维护文件结构的新目录

问题描述

我有一个包含一长串文件扩展名的文本文件:

.sln
.csproj
.cs
.xaml
.cshtml
.javasln
.project
.java
... (etc)

我有三个项目目录,每个目录都有许多子目录。

我可以通过以下方式获取所有文件和路径的列表:find . -type f -printf "%p\n"

./DirectoryA/src/main/resources/static/resources/build/home.ini
./DirectoryA/src/main/resources/static/resources/images/spring-pivotal-logo.png
./DirectoryB/src/main/resources/db/hsqldb/data.sql
./DirectoryC/src/main/resources/project/schema.project

我想遍历这些,如果文件扩展名与我列表中的一个匹配,请将其复制到myCopyDirectory同时保持其目录结构。

也就是说,如果./DirectoryC/src/main/resources/project/schema.project文件扩展名匹配.project(就像它一样)作为我的文本文件中的扩展名之一......将它复制到一个新目录,./myCopyDirectory如:./myCopyDirectory/DirectoryC/src/main/resources/project/schema.project.

所以我需要一个 for 或 while 循环,请原谅我可怕的伪代码,但这是我的愿景

场景 1:动态复制文件

for FILE in `find . -type f -printf "%p\n"`; do if [ ${FILE##*.} in extensions.txt ]; then mkdir -p ./myCopyDirectory/DirectoryC/src/main/resources/project/ && cp ./DirectoryC/src/main/resources/project/schema.project ./myCopyDirectory/DirectoryC/src/main/resources/project/schema.project

场景 2:构建匹配的文件列表并复制它们

for FILE in `find . -type f -printf "%p\n"`; do if [ ${FILE##*.} in extensions.txt ]; then echo $FILE >> listOfFiles.txt

for FILE in `cat listOfFiles.txt`; do filename="${FILE##*/}" && dir="${FILE:0:${#FILE} - ${#filename}}" && if [ -e ./myCopyDirectory/$dir ]; then mkdir -p ./myCopyDirectory/$dir && cp $FILE ./myCopyDirectory

场景 3:只有cp -R所有三个目录,./myCopyDirectory并撕掉所有与 extensions.txt 文件中的扩展名不匹配的文件

请原谅我糟糕的伪代码。我只是想完成这项工作,而且有点超出我的深度。我可以创建一个 PERL 或 Python 脚本来执行此操作,但这似乎没有必要。

标签: linuxbashshellawksed

解决方案


您实际上不需要 for 循环;事实上,您可以利用find's-exec选项将复杂的 shell 命令传递给它来处理“目录保留”复制过程。

以下单行应该可以工作(解释如下)。

find root1 -regex '.*\.\(ext1\|ext2\)$' -exec sh -c 'dir=${1%/*}; dir=${dir/root1/root2}; file=${1##*/}; mkdir -p $dir && cp $1 $dir/$file' _ {} \;

我通过创建以下示例目录树对其进行了测试,

$ mkdir root1
$ mkdir root1/sub
$ mkdir root1/sub/dir
$ touch root1/a.ext1 root1/a.ext2 root1/a.ext3 root1/sub/a.ext1 root1/sub/a.ext2 root1/sub/a.ext3 root1/sub/dir/a.ext1 root1/sub/dir/a.ext2 root1/sub/dir/a.ext3
$ tree root1/
root1/
├── a.ext1
├── a.ext2
├── a.ext3
└── sub
    ├── a.ext1
    ├── a.ext2
    ├── a.ext3
    └── dir
        ├── a.ext1
        ├── a.ext2
        └── a.ext3

2 directories, 9 files

然后在其上执行命令并检查结果

$ find root1 -regex '.*\.\(ext1\|ext2\)$' -exec sh -c 'dir=${1%/*}; dir=${dir/root1/root2}; file=${1##*/}; mkdir -p $dir && cp $1 $dir/$file' _ {} \;
$ tree root2
root2
├── a.ext1
├── a.ext2
└── sub
    ├── a.ext1
    ├── a.ext2
    └── dir
        ├── a.ext1
        └── a.ext2

2 directories, 6 files
  • -regex选项用于查找具有扩展名ext1或的文件ext2
  • -exec选项用于对sh找到的每个文件执行以下 ell 命令;
  • 该命令通过-c选项传递命令字符串,然后是参数的虚拟占位符,_参数是由 找到的文件的名称;0{}find1
  • shell 命令字符串
    • dir通过删除最后一个文件/及其后面的任何内容$1(已通过{})来提取每个文件的目录,
    • 然后通过替换root2来改变它root1
    • 同样,它提取文件名file
    • 最后,它创建新的目录结构mkdir,并复制其中的文件。

我没有包含该-type f选项,但如果您确实有扩展名等于您正在寻找的文件夹名称之一的文件夹名称,则可以。


推荐阅读