在 Linux 中如何移動文件
在 Linux 中移動文件看似比較簡單,但是可用的選項卻比大多數人想像的要多。本文介紹了初學者如何在 GUI 和命令行中移動文件,還介紹了底層實際上發生了什麼,並介紹了許多有一定經驗的用戶也很少使用的命令行選項。
移動什麼?
在研究移動文件之前,有必要仔細研究移動文件系統對象時實際發生的情況。當文件創建後,會將其分配給一個 索引節點 ,這是文件系統中用於數據存儲的固定點。你可以使用 ls 命令看到文件對應的索引節點:
$ ls --inode example.txt
7344977 example.txt
移動文件時,實際上並沒有將數據從一個索引節點移動到另一個索引節點,只是給文件對象分配了新的名稱或文件路徑而已。實際上,文件在移動時會保留其許可權,因為移動文件不會更改或重新創建文件。(LCTT 譯註:在不跨卷、分區和存儲器時,移動文件是不會重新創建文件的;反之亦然)
文件和目錄的索引節點並沒有暗示這種繼承關係,而是由文件系統本身決定的。索引節點的分配是基於文件創建時的順序分配的,並且完全獨立於你組織計算機文件的方式。一個目錄「內」的文件的索引節點號可能比其父目錄的索引節點號更低或更高。例如:
$ mkdir foo
$ mv example.txt foo
$ ls --inode
7476865 foo
$ ls --inode foo
7344977 example.txt
但是,將文件從一個硬碟驅動器移動到另一個硬碟驅動器時,索引節點基本上會更改。發生這種情況是因為必須將新數據寫入新文件系統。因此,在 Linux 中,移動和重命名文件的操作實際上是相同的操作。無論你將文件移動到另一個目錄還是在同一目錄使用新名稱,這兩個操作均由同一個底層程序執行。
本文重點介紹將文件從一個目錄移動到另一個目錄。
用滑鼠移動文件
圖形用戶界面是大多數人都熟悉的友好的抽象層,位於複雜的二進位數據集合之上。這也是在 Linux 桌面上移動文件的首選方法,也是最直觀的方法。從一般意義上來說,如果你習慣使用台式機,那麼你可能已經知道如何在硬碟驅動器上移動文件。例如,在 GNOME 桌面上,將文件從一個窗口拖放到另一個窗口時的默認操作是移動文件而不是複製文件,因此這可能是該桌面上最直觀的操作之一:
![Moving a file in GNOME.](/data/attachment/album/201909/24/162941j3bvbvvxnc5bxvvc.jpg "Moving a file in GNOME.")
而 KDE Plasma 桌面中的 Dolphin 文件管理器默認情況下會提示用戶以執行不同的操作。拖動文件時按住 Shift
鍵可強制執行移動操作:
![Moving a file in KDE.](/data/attachment/album/201909/24/162943i4px4s5mz48saswv.jpg "Moving a file in KDE.")
在命令行移動文件
用於在 Linux、BSD、Illumos、Solaris 和 MacOS 上移動文件的 shell 命令是 mv
。不言自明,簡單的命令 mv <source> <destination>
會將源文件移動到指定的目標,源和目標都由絕對或相對文件路徑定義。如前所述,mv
是 POSIX 用戶的常用命令,其有很多不為人知的附加選項,因此,無論你是新手還是有經驗的人,本文都會為你帶來一些有用的選項。
但是,不是所有 mv
命令都是由同一個人編寫的,因此取決於你的操作系統,你可能擁有 GNU mv
、BSD mv
或 Sun mv
。命令的選項因其實現而異(BSD mv
根本沒有長選項),因此請參閱你的 mv
手冊頁以查看支持的內容,或安裝你的首選版本(這是開源的奢侈之處)。
移動文件
要使用 mv
將文件從一個文件夾移動到另一個文件夾,請記住語法 mv <source> <destination>
。 例如,要將文件 example.txt
移到你的 Documents
目錄中:
$ touch example.txt
$ mv example.txt ~/Documents
$ ls ~/Documents
example.txt
就像你通過將文件拖放到文件夾圖標上來移動文件一樣,此命令不會將 Documents
替換為 example.txt
。相反,mv
會檢測到 Documents
是一個文件夾,並將 example.txt
文件放入其中。
你還可以方便地在移動文件時重命名該文件:
$ touch example.txt
$ mv example.txt ~/Documents/foo.txt
$ ls ~/Documents
foo.txt
這很重要,這使你不用將文件移動到另一個位置,也可以重命名文件,例如:
$ touch example.txt
$ mv example.txt foo2.txt
$ ls foo2.txt`
移動目錄
不像 cp 命令,mv
命令處理文件和目錄沒有什麼不同,你可以用同樣的格式移動目錄或文件:
$ touch file.txt
$ mkdir foo_directory
$ mv file.txt foo_directory
$ mv foo_directory ~/Documents
安全地移動文件
如果你移動一個文件到一個已有同名文件的地方,默認情況下,mv
會用你移動的文件替換目標文件。這種行為被稱為 清除 ,有時候這就是你想要的結果,而有時則不是。
一些發行版將 mv
別名定義為 mv --interactive
(你也可以自己寫一個),這會提醒你確認是否覆蓋。而另外一些發行版沒有這樣做,那麼你可以使用 --interactive
或 -i
選項來確保當兩個文件有一樣的名字而發生衝突時讓 mv
請你來確認。
$ mv --interactive example.txt ~/Documents
mv: overwrite '~/Documents/example.txt'?
如果你不想手動干預,那麼可以使用 --no-clobber
或 -n
。該選項會在發生衝突時靜默拒絕移動操作。在這個例子當中,一個名為 example.txt
的文件以及存在於 ~/Documents
,所以它不會如命令要求從當前目錄移走。
$ mv --no-clobber example.txt ~/Documents
$ ls
example.txt
帶備份的移動
如果你使用 GNU mv
,有一個備份選項提供了另外一種安全移動的方式。要為任何衝突的目標文件創建備份文件,可以使用 -b
選項。
$ mv -b example.txt ~/Documents
$ ls ~/Documents
example.txt example.txt~
這個選項可以確保 mv
完成移動操作,但是也會保護目錄位置的已有文件。
另外的 GNU 備份選項是 --backup
,它帶有一個定義了備份文件如何命名的參數。
existing
:如果在目標位置已經存在了編號備份文件,那麼會創建編號備份。否則,會使用simple
方式。none
:即使設置了--backup
,也不會創建備份。當mv
被別名定義為帶有備份選項時,這個選項可以覆蓋這種行為。numbered
:給目標文件名附加一個編號。simple
:給目標文件附加一個~
,當你日常使用帶有--ignore-backups
選項的 ls 時,這些文件可以很方便地隱藏起來。
簡單來說:
$ mv --backup=numbered example.txt ~/Documents
$ ls ~/Documents
-rw-rw-r--. 1 seth users 128 Aug 1 17:23 example.txt
-rw-rw-r--. 1 seth users 128 Aug 1 17:20 example.txt.~1~
可以使用環境變數 VERSION_CONTROL
設置默認的備份方案。你可以在 ~/.bashrc
文件中設置該環境變數,也可以在命令前動態設置:
$ VERSION_CONTROL=numbered mv --backup example.txt ~/Documents
$ ls ~/Documents
-rw-rw-r--. 1 seth users 128 Aug 1 17:23 example.txt
-rw-rw-r--. 1 seth users 128 Aug 1 17:20 example.txt.~1~
-rw-rw-r--. 1 seth users 128 Aug 1 17:22 example.txt.~2~
--backup
選項仍然遵循 --interactive
或 -i
選項,因此即使它在執行備份之前創建了備份,它仍會提示你覆蓋目標文件:
$ mv --backup=numbered example.txt ~/Documents
mv: overwrite '~/Documents/example.txt'? y
$ ls ~/Documents
-rw-rw-r--. 1 seth users 128 Aug 1 17:24 example.txt
-rw-rw-r--. 1 seth users 128 Aug 1 17:20 example.txt.~1~
-rw-rw-r--. 1 seth users 128 Aug 1 17:22 example.txt.~2~
-rw-rw-r--. 1 seth users 128 Aug 1 17:23 example.txt.~3~
你可以使用 --force
或 -f
選項覆蓋 -i
。
$ mv --backup=numbered --force example.txt ~/Documents
$ ls ~/Documents
-rw-rw-r--. 1 seth users 128 Aug 1 17:26 example.txt
-rw-rw-r--. 1 seth users 128 Aug 1 17:20 example.txt.~1~
-rw-rw-r--. 1 seth users 128 Aug 1 17:22 example.txt.~2~
-rw-rw-r--. 1 seth users 128 Aug 1 17:24 example.txt.~3~
-rw-rw-r--. 1 seth users 128 Aug 1 17:25 example.txt.~4~
--backup
選項在 BSD mv
中不可用。
一次性移動多個文件
移動多個文件時,mv
會將最終目錄視為目標:
$ mv foo bar baz ~/Documents
$ ls ~/Documents
foo bar baz
如果最後一個項目不是目錄,則 mv
返回錯誤:
$ mv foo bar baz
mv: target 'baz' is not a directory
GNU mv
的語法相當靈活。如果無法把目標目錄作為提供給 mv
命令的最終參數,請使用 --target-directory
或 -t
選項:
$ mv --target-directory=~/Documents foo bar baz
$ ls ~/Documents
foo bar baz
當從某些其他命令的輸出構造 mv
命令時(例如 find
命令、xargs
或 GNU Parallel),這特別有用。
基於修改時間移動
使用 GNU mv
,你可以根據要移動的文件是否比要替換的目標文件新來定義移動動作。該方式可以通過 --update
或 -u
選項使用,在BSD mv
中不可用:
$ ls -l ~/Documents
-rw-rw-r--. 1 seth users 128 Aug 1 17:32 example.txt
$ ls -l
-rw-rw-r--. 1 seth users 128 Aug 1 17:42 example.txt
$ mv --update example.txt ~/Documents
$ ls -l ~/Documents
-rw-rw-r--. 1 seth users 128 Aug 1 17:42 example.txt
$ ls -l
此結果僅基於文件的修改時間,而不是兩個文件的差異,因此請謹慎使用。只需使用 touch
命令即可愚弄 mv
:
$ cat example.txt
one
$ cat ~/Documents/example.txt
one
two
$ touch example.txt
$ mv --update example.txt ~/Documents
$ cat ~/Documents/example.txt
one
顯然,這不是最智能的更新功能,但是它提供了防止覆蓋最新數據的基本保護。
移動
除了 mv
命令以外,還有更多的移動數據的方法,但是作為這項任務的默認程序,mv
是一個很好的通用選擇。現在你知道了有哪些可以使用的選項,可以比以前更智能地使用 mv
了。
via: https://opensource.com/article/19/8/moving-files-linux-depth
作者:Seth Kenlon 選題:lujun9972 譯者:wxy 校對:wxy
本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive