Bash
為什麼 mv 刪除了一個帶有 mv id_rsa *.old 的文件?
我想備份我
~/.ssh/id_rsa
的到id_rsa.old
,它看起來被刪除了!這怎麼可能?:)root@localhost:~/.ssh# ls -l total 16 -rw------- 1 root root 3326 Mar 12 11:22 id_rsa -rw-r--r-- 1 root root 756 Mar 12 11:22 id_rsa.pub -rw------- 1 userx userx 666 Mar 8 11:09 known_hosts -rw-r--r-- 1 userx userx 666 Feb 29 10:53 known_hosts.old root@localhost:~/.ssh# mv id_rsa *.old root@localhost:~/.ssh# ls -l total 12 -rw-r--r-- 1 root root 756 Mar 12 11:22 id_rsa.pub -rw------- 1 userx userx 666 Mar 8 11:09 known_hosts -rw------- 1 root root 3326 Mar 12 11:22 known_hosts.old root@localhost:~/.ssh# touch p root@localhost:~/.ssh# mv p *.p root@localhost:~/.ssh# ls -l total 12 -rw-r--r-- 1 root root 756 Mar 12 11:22 id_rsa.pub -rw------- 1 userx userx 666 Mar 8 11:09 known_hosts -rw------- 1 root root 3326 Mar 12 11:22 known_hosts.old -rw-r--r-- 1 root root 0 Mar 12 11:28 *.p root@localhost:~/.ssh# rm *.p root@localhost:~/.ssh# ls -l total 12 -rw-r--r-- 1 root root 756 Mar 12 11:22 id_rsa.pub -rw------- 1 userx userx 666 Mar 8 11:09 known_hosts -rw------- 1 root root 3326 Mar 12 11:22 known_hosts.old userx@localhost:~$ uname -r 4.2.0-30-generic userx@localhost:~$ lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 15.10 Release: 15.10 Codename: wily userx@localhost:~$ bash --version GNU bash, version 4.3.42(1)-release (x86_64-pc-linux-gnu)
它已被重命名為
known_hosts.old
,因此覆蓋了 以前的內容known_hosts.old
。由於您已經在其中命名
known_hosts.old
了一個文件,因此 glob 模式*.old
已擴展為known_hosts.old
.簡而言之,如下:
mv id_rsa *.old
已擴展為:
mv id_rsa known_hosts.old
在
bash
中,如果那裡沒有名為known_hosts.old
present 的文件,它將擴展為文字*.old
(假設您尚未啟用nullglob
)。
看起來您認為
mv id_rsa *.old
會移動id_rsa
到id_rsa.old
,*
並被第一個參數替換,但事實並非如此。萬用字元由 shell 擴展,而不是命令。當mv
看到命令時,shell 已經擴展了萬用字元。有四種情況:
- 萬用字元模式不匹配任何文件。對於大多數 shell,這會使萬用字元模式未擴展,因此
mv
使用參數id_rsa
和呼叫*.old
。然後它移動id_rsa
到一個名為*.old
(星號是文件名的第一個字元)的文件。某些 shell(取決於它們的配置)將顯示錯誤並且在這種情況下不執行命令。- 萬用字元模式與一個不是目錄的文件完全匹配。在這種情況下,shell 將模式替換為匹配文件的名稱。因此
mv
移動id_rsa
到該匹配文件,覆蓋前一個文件。這就是您的情況發生的情況:mv
使用參數呼叫id_rsa
,known_hosts.old
被known_hosts.old
覆蓋。- 萬用字元模式匹配兩個或多個文件,最後一個(按字典順序)不是目錄。在這種情況下,
mv
抱怨,因為除了最後一個文件之外的所有文件都是源文件,將多個文件移動到同一個文件是沒有意義的。- 萬用字元模式匹配一個或多個文件,最後一個匹配(按字典順序)是一個目錄。源文件被移動到該目錄中。如果已經存在同名文件,則將其覆蓋。如果模式有多個匹配項,這也適用於模式匹配的所有文件,除了最後一個,因為
mv
將它們視為源文件。為避免
mv
意外覆蓋目標文件,請使其提示確認。把它放在你的shell初始化中(例如.bashrc
):alias cp='cp -i' alias mv='mv -i'
要根據現有名稱重命名文件,
mv
單靠它是沒有幫助的。您需要使用其他工具,或安排提供mv
完整的目的地名稱。做你想做的事情的一種方法是使用大括號擴展,它可以讓你指定具有共同詞幹的單詞。mv id_rsa{,.old}
shell 將其擴展為
mv
帶有參數id_rsa
(id_rsa
與空字元串連接)和id_rsa.old
(id_rsa
與 連接.old
)。要根據模式批量重命名文件,最常用的工具是
zmv
(僅限 zsh)prename
和mmv
. 要將表單的所有文件從to重命名,您可以使用id_*SOMETHING*``id_*SOMETHING*.old
zmv 'id_*' '$f.old' mmv 'id_*' 'id_#1.old' prename 's/$//' id_*