在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設定以及它如何影響萬用字元行為。

更新於:2022年12月26日

861 次瀏覽

開啟你的職業生涯

透過完成課程獲得認證

開始學習
廣告