Files

在多個(可變)文件夾中復製文件

  • December 19, 2020

我想複製具有可變子文件夾名稱的多個子文件夾中的文件。

例子:

mkdir rootdir
mkdir rootdir/dir1
mkdir rootdir/dir2
mkdir rootdir/dir3
touch rootdir/dir1/foo.txt
touch rootdir/dir2/foo.txt
touch rootdir/dir3/foo.txt

使用已知的子文件夾名稱,我可以單獨複製每個文件。

cp rootdir/dir1/foo.txt rootdir/dir1/bar.txt
cp rootdir/dir2/foo.txt rootdir/dir2/bar.txt
cp rootdir/dir3/foo.txt rootdir/dir3/bar.txt

但是對於未知數量的子文件夾名稱未知(我知道文件名),我不能再這樣做了。

我可以找到文件…

ls ./**/foo.txt
find . -name foo.txt

…但我沒有找到允許將此資訊傳遞到 cp (或替代工具)的語法。

有幾個選項:

find rootdir -type f -name foo.txt -execdir cp {} bar.txt \;

這會搜尋foo.txt在 中或下的任何位置呼叫的正常文件rootdir,當找到一個時,cp用於將其複製到bar.txt同一目錄中的名稱。該-execdir選項是非標準的,但通常實現,並將在找到文件的目錄中執行給定的實用程序。將{}替換為找到的文件名。

或者,

find rootdir -type f -name foo.txt -exec sh -c '
   for pathname do
       cp "$pathname" "${pathname%/*}/bar.txt"
   done' sh {} +

這基本上做同樣的事情,但呼叫一個sh -c包含成批找到的foo.txt文件的簡短內嵌腳本。循環中的cpin 會將這些中的每一個複製到與找到的文件相同的目錄中,但路徑名的文件名部分替換為bar.txt.

使用**, 正如您在問題中提到的那樣(假設是bash外殼):

shopt -s globstar nullglob dotglob

for pathname in rootdir/**/foo.txt; do
   cp "$pathname" "${pathname%/*}/bar.txt"
done

bash中,設置globstarshell 選項可以使用**for 遞歸匹配到子目錄,dotglob並使模式也可以匹配隱藏的名稱。shell 選項使模式完全消失,nullglob而不是在沒有匹配的情況下保持未擴展。

同樣,但使用zsh(明確要求正常文件並啟用對 globbing 的等效dotglob處理nullglobbash

for pathname in rootdir/**/foo.txt(.ND); do
   cp $pathname $pathname:h/bar.txt
done

在這裡,$pathname:h$pathname與刪除路徑名的文件名部分相同(:h如“僅頭部”,而不是尾隨位)。

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