Terminal

僅遞歸複製與文件中列出的模式匹配的某些目錄

  • July 11, 2018

我有一個具有以下結構的目錄:

-- 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不僅包含上面列出的三個文件夾,而且還包含數千個文件。

我只想複製名稱末尾有的目錄(不應複製DATFull目錄)並且還包含下面列表中的模式_Full

LP02323
KLOFJ9
Paaaf
9FZA

換句話說,應該複製包含上述列表中的字元串並在其名稱中(但不是 DAT)的目錄。 Full

因此,在上面的範例中,僅應複製以下目錄(及其所有內容和子目錄):

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

據我了解,rsync不支持正則表達式,因此必須首先完成find(如果我錯了,請糾正我)。但是我怎麼能這樣做以確保檢查所有目錄和子目錄並複制所有相關文件夾,即使它們深埋在幾個子目錄中(請注意,上面的範例是簡化的我的原始文件夾的結構)。

所以有兩個問題:

  • 如何將模式列表提供給find
  • 如何通過管道find傳輸 to的結果rsync

到目前為止,這只是我想到的匹配Full

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

但是如何將 ID 列表添加到此find命令中?

使用需要在目錄名稱中出現的字元串文件,對這些字元串進行 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/***":考慮與給定模式匹配的所有目錄以及該目錄下的所有內容。如果$stringparrot,這將是--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將路徑名傳遞給其他命令,除非您可以安排安全地分隔路徑名。

有關的:

引用自:https://unix.stackexchange.com/questions/454642