Bash

為什麼 mv 刪除了一個帶有 mv id_rsa *.old 的文件?

  • March 14, 2016

我想備份我~/.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.oldpresent 的文件,它將擴展為文字*.old(假設您尚未啟用nullglob)。

看起來您認為mv id_rsa *.old會移動id_rsaid_rsa.old*並被第一個參數替換,但事實並非如此。萬用字元由 shell 擴展,而不是命令。當mv看到命令時,shell 已經擴展了萬用字元。有四種情況:

  • 萬用字元模式不匹配任何文件。對於大多數 shell,這會使萬用字元模式未擴展,因此mv使用參數id_rsa和呼叫*.old。然後它移動id_rsa到一個名為*.old(星號是文件名的第一個字元)的文件。某些 shell(取決於它們的配置)將顯示錯誤並且在這種情況下不執行命令。
  • 萬用字元模式與一個不是目錄的文件完全匹配。在這種情況下,shell 將模式替換為匹配文件的名稱。因此mv移動id_rsa到該匹配文件,覆蓋前一個文件。這就是您的情況發生的情況:mv使用參數呼叫id_rsa,known_hosts.oldknown_hosts.old覆蓋。
  • 萬用字元模式匹配兩個或多個文件,最後一個(按字典順序)不是目錄。在這種情況下,mv抱怨,因為除了最後一個文件之外的所有文件都是源文件,將多個文件移動到同一個文件是沒有意義的。
  • 萬用字元模式匹配一​​個或多個文件,最後一個匹配(按字典順序)是一個目錄。源文件被移動到該目錄中。如果已經存在同名文件,則將其覆蓋。如果模式有多個匹配項,這也適用於模式匹配的所有文件,除了最後一個,因為mv將它們視為源文件。

為避免mv意外覆蓋目標文件,請使其提示確認。把它放在你的shell初始化中(例如.bashrc):

alias cp='cp -i'
alias mv='mv -i'

要根據現有名稱重命名文件,mv單靠它是沒有幫助的。您需要使用其他工具,或安排提供mv完整的目的地名稱。做你想做的事情的一種方法是使用大括號擴展,它可以讓你指定具有共同詞幹的單詞。

mv id_rsa{,.old}

shell 將其擴展為mv帶有參數id_rsaid_rsa與空字元串連接)和id_rsa.oldid_rsa與 連接.old)。

要根據模式批量重命名文件,最常用的工具是zmv(僅限 zsh)prenamemmv. 要將表單的所有文件從to重命名,您可以使用id_*SOMETHING*``id_*SOMETHING*.old

zmv 'id_*' '$f.old'
mmv 'id_*' 'id_#1.old'
prename 's/$//' id_*

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