將多個目錄中的檔案(如果其名稱出現在清單中)複製到單一目錄中

將多個目錄中的檔案(如果其名稱出現在清單中)複製到單一目錄中

我有一個巨大的資料夾樹,每個資料夾都有多個子目錄,大約向下 3 層。這是一個只有一個層級的範例:

$ tree
.
|-- AB.txt
|-- CD.txt
|-- destination_folder
|-- spreadsheet.txt
`-- subdirectory
    `-- EF.txt

2 directories, 4 files

我有一個我感興趣的文件名列表,名為spreadsheet.txt

$ cat spreadsheet.txt 
AB.txt
CD.txt
EF.txt

我想將出現的所有文件複製spreadsheet.txt到一個資料夾中,例如destination_folder.非常感謝您的幫忙!我想這會涉及findcp,但似乎無法解決,

答案1

每個檔案名稱運行find一次,並假設沒有檔案名稱包含嵌入的換行符:

#!/bin/sh

mkdir -p destination_folder || exit 1
while IFS= read -r name; do
    find . -path ./destination_folder -prune -o \
        -type f -name "$name" -exec cp {} destination_folder \;
done <spreadsheet.txt

這首先在目前目錄中建立目標目錄(如果失敗則終止)。然後,它逐行讀取輸入文件,並調用find以查找具有該名稱的任何常規文件。每當我們在搜尋中遇到目標目錄時,都會透過find使用來明確避免目標目錄。-prune

只要找到具有正確名稱的文件,就會將其複製到目標目錄。如果多個檔案同名,則in中的副本destination_folder會被覆寫。

如果當前目錄很大,或者檔案名稱列表很長(但不是幾千行),那麼這將是一個緩慢的操作。因此我們可能會選擇做一個單身的撥電至find。下面的程式碼假設它是用 eg 執行的,bash因為它使用陣列:

#!/bin/bash

mkdir -p destination_folder || exit 1

names=()
while IFS= read -r name; do
    names+=( -o -name "$name" )
done <spreadsheet.txt

find . -path ./destination_folder -prune -o \
    \( "${names[@]:1}" \) -type f -exec cp -t destination_folder {} +

在這裡,我還選擇使用cp -t(GNUcp擴充功能)來盡可能cp少地調用,而不是每個找到的檔案調用一次。

上面的程式碼建構了一個陣列 ,names最終將採用正確的格式與 一起使用find。根據您問題中的範例,在上述程式碼末尾實際執行的命令將是

find . -path ./destination_folder -prune -o '(' -name AB.txt -o -name CD.txt -o -name EF.txt ')' -type f -exec cp -t destination_folder '{}' +

為了避免目標目錄中的檔案名稱衝突問題,如果您使用的是 GNU cp(例如在 Linux 系統上),請使用cp-b--backup選項。

在非 Linux 系統上,GNU通常在透過套件管理器安裝 GNU coreutils 後cp可用。gcp


最後一個腳本,但對於/bin/sh(無數組):

#!/bin/sh

mkdir -p destination_folder || exit 1

set --
while IFS= read -r name; do
    set -- -o -name "$name" "$@"
done <spreadsheet.txt

shift

find . -path ./destination_folder -prune -o \
    \( "$@" \) -type f -exec cp -t destination_folder {} +

答案2

一個簡單的 for 迴圈:

for filename in $(cat spreadsheet.txt)
do
find . -name "$filename" -exec cp {} /destination/folder \;
done

相關內容