在Linux系統中複製目錄到已存在的目錄?
概述
複製檔案是使用Linux shell執行的最常見操作之一。我們通常為此目的使用cp(複製)命令。
我們將討論如何遞迴地將資料夾移動到另一個位置,無論是否覆蓋。
問題介紹
我們首先需要理解在這個問題中“將資料夾複製到另一個位置”是什麼意思。
一個好的例子可以幫助你更好地理解它。
$ tree -a . ├── src │ ├── .hidden.file │ ├── srcFile.txt │ └── subSrc │ └── subSrcFile.txt └── target └── originalTarget.file
3個目錄,4個檔案
如上圖所示,我們在src資料夾下有兩個目錄。有一些原始碼檔案和一個子資料夾。我們還有一個隱藏檔案.hidden.file。
現在我們需要將原始檔夾複製到目標資料夾。
我們希望目標資料夾與原始檔夾相同。
├── src │ ├── .hidden.file │ ├── srcFile.txt │ └── subSrc │ └── subSrcFile.txt └── target ├── .hidden.file ├── srcFile.txt └── subSrc └── subSrcFile.txt
但是,如果我們只是將原始檔夾的內容複製到目標資料夾,我們希望src下的所有內容都遞迴地移動到目標資料夾。我們也希望目標資料夾下的原始檔案保持不變。
├── src │ ├── .hidden.file │ ├── srcFile.txt │ └── subSrc │ └── subSrcFile.txt └── target ├── .hidden.file ├── originalTarget.file ├── srcFile.txt └── subSrc └── subSrcFile.txt
由於目標目錄已經存在,我們不能只使用cp -r src target方法來完成此任務。相反,我們需要首先在目標目錄中建立一個名為src的新目錄。然後,我們可以將檔案從src移動到新建立的src目錄。
之後,我們將討論如何透過兩種不同的方法來實現我們的目標:
使用cp命令
使用rsync命令
使用cp命令
讓我們首先看看如何使用cp命令來解決這個問題,因為它相當常見。
cp命令不覆蓋目標目錄
如果原始檔夾不為空,我們不能簡單地使用cp命令將原始檔夾的內容複製到目標資料夾。
但是,cp有一個-i選項,它將原始檔視為普通檔案而不是資料夾。
如果我們使用-rT選項,則cp命令將遞迴遍歷原始檔夾的內容,並在目標資料夾中建立它們的副本。
$ cp -rT src target $ tree -a . ├── src │ ├── .hidden.file │ ├── srcFile.txt │ └── subSrc │ └── subSrcFile.txt └── target ├── .hidden.file ├── originalTarget.file ├── srcFile.txt └── subSrc └── subSrcFile.txt
4個目錄,7個檔案
tree的-a選項告訴我們我們正在將源目錄中的所有內容複製到目標目錄。但是,源目錄不包含在複製操作中。所以我們完成了!
Bash萬用字元技巧
我們已經透過使用帶有-rT選項的cp命令解決了這個問題。
我們可以透過將src中的所有內容複製到target來解決問題。因此,我們可能能夠編寫如下內容:cp -r src/* target。
我們可以透過將src中的所有內容複製到target來解決問題。因此,我們可能能夠編寫如下內容:cp -r src/* target。
$ cp -r src/* target $ tree -a . ├── src │ ├── .hidden.file │ ├── srcFile.txt │ └── subSrc │ └── subSrcFile.txt └── target ├── originalTarget.file ├── srcFile.txt └── subSrc └── subSrcFile.txt
4個目錄,6個檔案
正如tree輸出所示,src下的大多數檔案都成功傳輸到目標資料夾,除了.dot檔案。這是因為使用“globstar”選項時,shell會忽略任何以句點(“.”)開頭的檔名。
解決此問題的方法有兩種。一種解決方案是修改全域性設定,以便萬用字元包含.dot檔案。為此,可以使用shopt -s dotglob命令。
$ ( shopt -s dotglob; cp -r src/* target ) $ tree -a target target ├── .hidden.file ├── originalTarget.file ├── srcFile.txt └── subSrc └── subSrcFile.txt
1個目錄,4個檔案
$ shopt dotglob
dotglob off
從上面的輸出中我們可以看到,.dot檔案也已成功建立。此外,我們將我們的shoptcp命令與cp命令一起放在括號(…)中,以便它們在子shell中執行,因為我們希望shoptcp命令隻影響單個cp命令。
命令執行後,當我們檢查萬用字元選項時,它們仍然被停用。
更改bash的預設行為很容易。但是,如果您正在為自己編寫指令碼,這可能會很不方便。特別是,如果您想避免意外後果。
您也可以使用“src/.”而不是“src/*”將.dot檔案新增到您的原始碼控制系統。
讓我們看看它是否按預期工作。
$ cp -r src/. target $ tree -a target target ├── .hidden.file ├── originalTarget.file ├── srcFile.txt └── subSrc └── subSrcFile.txt
1個目錄,4個檔案
cp命令和覆蓋目標目錄
如果我們想用目標資料夾的內容替換原始檔夾的內容,那麼使用-R選項比使用-O選項更容易。所以讓我們首先刪除目標資料夾並執行cp -r命令。
$ rm -r target && cp -r src target $ tree -a . ├── src │ ├── .hidden.file │ ├── srcFile.txt │ └── subSrc │ └── subSrcFile.txt └── target ├── .hidden.file ├── srcFile.txt └── subSrc └── subSrcFile.txt
4個目錄,6個檔案
使用rsync命令
rsync是解決此問題的有用工具。
rsync命令不覆蓋目標目錄
我們可以使用兩個rsync命令列來遞迴複製目錄:
rsync -a source target:將source的內容複製到target
rsync -a src/ target - **將src目錄的內容複製到target**
上面兩個命令幾乎相同。帶有前導斜槓的命令正是我們正在尋找的。
讓我們在我們的示例中測試一下:
$ rsync -a src/ target $ tree -a . ├── src │ ├── .hidden.file │ ├── srcFile.txt │ └── subSrc │ └── subSrcFile.txt └── target ├── .hidden.file ├── originalTarget.file ├── srcFile.txt └── subSrc └── subSrcFile.txt
4個目錄,7個檔案
tree的結果顯示該命令已解決我們的問題。
rsync命令和覆蓋目標目錄
我們已經瞭解到,我們可以組合兩個命令列,“sudo rmdir /path/to/folder && sudo cp -r /source/folder /path/to/destination”來解決這個問題。
使用rsync,我們可以一次完成所有操作:
$ rsync -a --delete src/ target $ tree -a . ├── src │ ├── .hidden.file │ ├── srcFile.txt │ └── subSrc │ └── subSrcFile.txt └── target ├── .hidden.file ├── srcFile.txt └── subSrc └── subSrcFile.txt
4個目錄,6個檔案
執行rsync命令後,target和source都包含相同的內容。因此,我們找到了解決原始問題的替代方案。
此解決方案的秘訣是-delete開關。
-delete選項告訴rsync刪除target/中不在source/中的任何檔案,確保source和target在傳輸結束時最終相同。
結論
我們已經討論瞭如何在遞迴地將資料夾移動到另一個資料夾,無論是否覆蓋。
我們學習了兩種解決問題的方法:使用常見的cp(複製)和rsync命令。
我們討論了bash的dotglob設定以及它如何影響萬用字元行為。