仅递归复制与文件中列出的模式匹配的某些目录

仅递归复制与文件中列出的模式匹配的某些目录

我有一个具有以下结构的目录:

-- 201893208
   └── 8Z12
          └── ko_8Z12_Full
          └── wp_we_8Z12_FullDAT
          └── 8Z12_DATFull
   └── P011
          └── P011_Full
          └── 8Z12_FullDAT
          └── P011_DATFull
   └── 9FZA
          └── kl_wt-we-w_kl9-9FZA_Full
          └── ffd-9FZA_FullDAT
          └── 8fdZ12232_9FZA_DATFull
-- 903240920
   └── P0fsa
          └── P0fsa_Full
          └── P0fsa_FullDAT
          └── P0fsa_DATFull
   └── Paaaf
          └── we-Paaaf_ww_fl_Full
          └── Paaaf_FullDAT
          └── Paaaf_DATFull
   └── 9FZATYYY
          └── 9FZATYYY_Full
          └── 9FZATYYY_FullDAT
-- wt0340291
   └── OPF1121
          └── OPF1121_Full
          └── 8Z12_DATFull
   └── KLOFJ9
          └── lop_KLOFJ9_ffj_Full
          └── powt_KLOFJ9_DATFull
   └── LP02323
          └── wr_we_LP02323_Full
          └── wr_we_LP02323_FullDAT

上面列出的每个文件夹中都有数千个文件。然后每个里面还有很多子目录。例如8Z12不仅包含上面列出的三个文件夹,而且还包含数千个文件。

仅有的想要复制名称_Full末尾带有 (完整数据目录不应该被复制并且包含下面列表中的模式

LP02323
KLOFJ9
Paaaf
9FZA

换句话说,包含上面列表中的字符串的目录 Full应以他们的名义(但不是 DAT)复制。

因此,在上面的示例中,仅应复制以下目录(及其所有内容和子目录):

wr_we_LP02323_Full
lop_KLOFJ9_ffj_Full
we-Paaaf_ww_fl_Full
kl_wt-we-w_kl9-9FZA_Full

据我了解,rsync不支持正则表达式,因此必须find首先完成此操作(如果我错了,请纠正我)。但是,我怎样才能确保检查所有目录和子目录并复制所有相关文件夹,即使它们深埋在几个子目录中(请注意,上面的示例是一个简化的示例)我的原始文件夹的结构)。

那么有两个问题:

  • 我如何向 提供模式列表find
  • 如何通过管道传输findto的结果rsync

到目前为止,我只想到这个匹配Full

find . -regextype sed -regex ".*/.*[^DAT]Full$"

但是如何将 ID 列表添加到该find命令中呢?

答案1

使用需要出现在目录名称中的字符串文件,shell 循环这些字符串,并且rsync(假设我们要从变量中的目录复制$source到变量中的目录$target):

while IFS= read -r string; do
    rsync --archive --exclude='*DAT*/' --include='*/' --include="*$string*_Full/***" --exclude='*' \
        --prune-empty-dirs "$source"/ "$target"
done <strings.txt

选项的作用rsync(任何排除/包含模式的第一次点击都很重要):

  • --archive:复制所有权、权限、时间戳等。
  • --exclude='*DAT*/'DAT:排除名称中带有 的任何目录。
  • --include='*/':考虑所有目录(除了先前模式排除的目录)。这是rsync到达您感兴趣的实际目录所必需的。
  • --include="*$string*_Full/***":考虑与给定模式匹配的所有目录该目录下的所有内容。如果$string是的话parrot,就这样了--include="*parrot*_Full/***"
  • --exclude='*':不要考虑任何尚未明确包含的内容。
  • --prune-empty-dirs:不要传输没有明确包含任何内容的目录。

如果您想了解rsync运行时如何评估模式,请添加-vvrsync命令行。

测试:

$ tree
.
|-- from
|   `-- a
|       `-- b
|           |-- c_A_DATFull
|           |   `-- file
|           |-- c_A_DAT_Full
|           |   `-- file
|           |-- c_A_Full
|           |   `-- file
|           |-- c_B_DATFull
|           |   `-- file
|           |-- c_B_DAT_Full
|           |   `-- file
|           |-- c_B_Full
|           |   `-- file
|           |-- c_C_DATFull
|           |   `-- file
|           |-- c_C_DAT_Full
|           |   `-- file
|           `-- c_C_Full
|               `-- file
`-- strings.txt

12 directories, 10 files

$ cat strings.txt
A
B

$ source=from
$ target=to

(在这里运行循环)

$ tree
.
|-- from
[...]
`-- to
    `-- a
        `-- b
            |-- c_A_Full
            |   `-- file
            `-- c_B_Full
                `-- file

17 directories, 12 files

通过一次调用rsync

set -- --exclude='*DAT*/' --include='*/'
while IFS= read -r string; do
    set -- "$@" --include="*$string*_Full/***"
done <strings.txt
set -- "$@" --exclude='*'

rsync --archive "$@" --prune-empty-dirs "$source"/ "$target"

一个find办法:

set --
while IFS= read -r string; do
    set -- "$@" -o -name "*$string*_Full"
done <strings.txt
shift

# "$@" would now be something like
#    -name *LP02323*_Full -o -name *Paaaf*_Full -o -name ...etc

find "$source" -type d '(' "$@" ')' ! -name '*DAT*' -exec sh -c '
    source=$1; target=$2; shift 2
    for pathname do
        mkdir -p "$target/${pathname#$source}"
        rsync --archive "$pathname"/ "$target/${pathname#$source}"
    done' sh "$source" "$target" {} +

这将用于find生成您要复制的子目录的列表。这些被赋予一个循环它们的小内联脚本。

在循环的每次迭代中,都会创建目标上的相应目录(假设本地副本),并使用rsync.

从来没有find用过管道某些其他命令的路径名,除非您可以安排安全地分隔路径名。

有关的:

相关内容