web-dev-qa-db-ja.com

mvがmvid_rsa * .oldのファイルを削除したのはなぜですか?

~/.ssh/id_rsaid_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)
8
Bojan Landekić

名前がknown_hosts.oldに変更されたため、以前のknown_hosts.oldの内容が上書きされました。

そこにはすでにknown_hosts.oldという名前のファイルがあるので、グロブパターン*.oldknown_hosts.oldに展開されています。

一言で言えば、次のとおりです。

mv id_rsa *.old

に拡張されました:

mv id_rsa known_hosts.old

bashに、known_hosts.oldという名前のファイルが存在しない場合、リテラル*.oldに展開されます(nullglobを有効にしていない場合)。

32
heemayl

mv id_rsa *.oldid_rsaid_rsa.oldに移動し、*が最初の引数に置き換えられると思ったようですが、そうではありません。ワイルドカードは、コマンドではなくシェルによって展開されます。 mvがコマンドを確認するまでに、シェルはワイルドカードを展開しています。 4つのケースがあります:

  • ワイルドカードパターンはどのファイルとも一致しません。ほとんどのシェルでは、これによりワイルドカードパターンが展開されないままになるため、引数id_rsaおよび*.oldを指定してmvが呼び出されます。次に、id_rsa*.oldというファイルに移動します(アスタリスクはファイル名の最初の文字です)。一部のシェル(構成によって異なります)は、代わりにエラーを表示し、その場合はコマンドを実行しません。
  • ワイルドカードパターンは、ディレクトリではない1つのファイルと正確に一致します。この場合、シェルはパターンを一致するファイルの名前に置き換えます。したがって、mvid_rsaをその一致するファイルに移動し、前のファイルを上書きします。これがあなたのケースで起こったことです:mvが引数id_rsaknown_hosts.oldで呼び出され、known_hosts.oldが上書きされました。
  • ワイルドカードパターンは2つ以上のファイルに一致し、最後のファイル(辞書式順序)はディレクトリではありません。この場合、最後のファイルを除くすべてのファイルがソースファイルであり、複数のファイルを同じファイルに移動することは意味がないため、mvは文句を言います。
  • ワイルドカードパターンは1つ以上のファイルと一致し、最後の一致(辞書式順序)はディレクトリです。ソースファイルはそのディレクトリに移動されます。同じ名前のファイルがすでに存在する場合は、上書きされます。パターンに複数の一致がある場合、mvはそれらをソースファイルと見なすため、これは最後のファイルを除くパターンに一致するすべてのファイルにも適用されます。

mvが予期せずターゲットファイルを上書きしないようにするには、確認を求めるプロンプトを表示します。これをシェルの初期化に入れます(例:.bashrc):

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

既存の名前に基づいてファイルの名前を変更するには、mvだけでは役に立ちません。別のツールを使用するか、mvに完全な宛先名を指定するように手配する必要があります。実行しようとしていたことを実行する1つの方法は、 中括弧の展開 を使用することです。これにより、共通の語幹を持つ単語を指定できます。

mv id_rsa{,.old}

シェルはこれを引数id_rsa(空の文字列と連結されたid_rsa)およびid_rsa.oldid_rsaと連結された.old)を使用してmvに展開します。 )。

パターンに従ってファイルの名前を一括変更するために最も一般的に役立つツールは、 zmv (zshのみ)、 prename および mmv 。フォームのすべてのファイルの名前をid_SOMETHINGからid_SOMETHING.oldに変更するには、次を使用できます。

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