我有一個巨大的資料夾樹,每個資料夾都有多個子目錄,大約向下 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
.非常感謝您的幫忙!我想這會涉及find
和cp
,但似乎無法解決,
答案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