web-dev-qa-db-ja.com

宛先を指定せずに `mv ./*`は何をしますか?

Returnキーを押す前に誤って宛先を指定するのを忘れました。どこでやる mv ./*移動先を指定せずに、現在のディレクトリの下のファイルとディレクトリを移動しますか?

29
Tim

最後の引数がディレクトリの場合は、現在の作業ディレクトリ内のすべてのファイルとディレクトリ(名前がドットで始まるものを除く)をそのディレクトリに移動しただけです。 2つのファイルがあった場合、最初のファイルが2番目のファイルを上書きした可能性があります。

ここにいくつかのデモンストレーションがあります:

つ以上のファイル、最後の引数はファイル

$ mkdir d1 d2 d3
$ touch a b c e
$ mv *
mv: target 'e' is not a directory

つ以上のファイル、最後の引数はディレクトリ

$ mkdir d1 d2 d3
$ touch a b c
$ mv -v *
'a' -> 'd3/a'
'b' -> 'd3/b'
'c' -> 'd3/c'
'd1' -> 'd3/d1'
'd2' -> 'd3/d2'

2つのファイル

$ touch a b
$ mv -v *
'a' -> 'b'

詳しい説明

シェルはグロブ(*)をmvの引数に挿入します。グロブは通常、アルファベット順に展開されます。 mvは常にファイルとディレクトリのリストを参照します。グロブ自体を見ることはありません。

コマンドmvは、2種類の移動をサポートしています。 1つはmv file ... directory。もう1つはmv old-file-name new-file-name(またはmv old-file-name directory/new-file-name)。

42
user26112

まず、テストベースを作成します-5つのファイルと1つのフォルダー:

_touch file1 file2 file3 file4 file5
mkdir folder
_

次に、テストコマンドを実行します。 _-v_オプションは、シェルが実行するすべてのコマンドをstderrに出力することを指定します。 _-x_オプションは、同じものをstderrに出力することを指定します-but実行したいafterコマンドは評価されますが、beforeシェルがそれを実行します。

_sh -cxv 'echo mv *'
_

出力

_echo mv *
+ echo mv file1 file2 file3 file4 file5 folder
mv file1 file2 file3 file4 file5 folder
_

シェルにフィードするコマンドは_echo mv *_であり、シェルが実行するコマンドはafter_*_が展開された_echo mv_の後に続くそれらすべてのファイルとフォルダ。

デフォルトでは、シェルはglobsを次のように展開します:

_sh -cxv 'echo file[1-5]'
_

出力

_echo file[1-5]
+ echo file1 file2 file3 file4 file5
file1 file2 file3 file4 file5
_

これは_set [+-]f_グロブ関数の結果です:

_sh -cxvf 'echo file[1-5]'
_

出力

_echo file[1-5]
+ echo 'file[1-5]'
file[1-5]
_

したがって、_mv *_のようなデフォルトのオプションで構成されたシェルでコマンドを実行すると、シェルは_*_ Wordに展開され、現在のディレクトリ内のすべてのファイルの引数リストがロケールに従ってソートされます。これは、mvに対してsyscall exec(ve)を実行します(基本的に)この引数リストが追加されます。したがって、mvは、シェルがそれらをグロブしてソートするときにすべての引数を取得します。これらの効果を確認するためにstraceを実行する以外に、次のようにデバッグを再度使用できます。

_sh -s -- mv * <<\SCRIPT
sed -n l /proc/$$/cmdline
echo "$@"
SCRIPT
_

出力

_sh\000-s\000--\000mv\000file1\000file2\000file3\000file4\000file5\000folder\
\000$
mv file1 file2 file3 file4 file5 folder
_

そして移植性:

_( PS4= IFS=/; set -x mv *; : "/$*/" ) 2>&1
_

出力

_: /mv/file1/file2/file3/file4/file5/folder/
_

基本的に、シェルはディレクトリのコンテンツを使用してmvを実行します(空ではなく、_._で始まる名前のファイル/フォルダーが含まれていない場合)を引数リストとして。 mvは、2つ以上の引数で呼び出された場合、最後の引数をディレクトリとして解釈するように指定されたPOSIXです。同じ方法でlnです(実際、 、それらは基礎となる機能において非常に類似したツールです)

十分なechoesただし:

_sh -cxv 'mv *' ; ls
_

出力

_mv *
+ mv file1 file2 file3 file4 file5 folder
folder/
_

すべてのファイルは最後の引数に移動されました。これはフォルダーであるためです。次に、それがフォルダでない場合はどうなりますか?

_sh -cxv 'cd *; mv *'; ls . *
_

出力

_cd *; mv *
+ cd folder
+ mv file1 file2 file3 file4 file5
mv: target ‘file5’ is not a directory

.:
folder/

folder:
file1  file2  file3  file4  file5
_

これが POSIXが指定するmvがその場合に動作する方法です。

_mv [-if] source_file target_file

mv [-if] source_file... target_dir
_

最初の概要形式では、mvユーティリティは、source_fileオペランドで指定されたファイルをtarget_fileで指定された宛先に移動します。この最初の構文形式は、最後のオペランドが既存のディレクトリを指定しておらず、既存のディレクトリを参照するシンボリックリンクでない場合に想定されます。この場合、source_fileが非ディレクトリファイルを指定し、target_fileが末尾の_/slash_文字で終了する場合、mvはこれをエラーとして扱い、source_fileオペランドは処理されません。

2番目の形式では、mvは、source_fileオペランドで指定された各ファイルを、target_dirオペランドで指定された既存のディレクトリ内の宛先ファイルに移動します。 target_dirは、既存のディレクトリを参照するシンボリックリンクです。各source_fileの宛先パスは、ターゲットディレクトリの連結、ターゲットが_/slash_で終わっていない場合は単一の_/slash_文字、およびソースファイル。この2番目の形式は、最後のオペランドが既存のディレクトリを指定する場合に想定されます。

したがって、_*_が次のように展開される場合:

  • 2つのファイル

    • 最初のrenamedから2番目のファイルがunlinkedまでのファイルは1つだけです。
  • 1つ以上のファイルの後にディレクトリまたは1つのファイルへのリンクが続く

    • ディレクトリまたはディレクトリへのリンクは1つだけである必要があります。そこには、その親の以前のコンテンツがすべて移動されています。
  • 他に何か

    • あなたはエラーメッセージと満足のいく安堵のため息を持っているべきです。
31
mikeserv

最初にシェルが展開します./*現在のディレクトリ内のすべてのファイル(ドットで始まるファイルを除く)。

  • ファイルがないか、ファイルが1つしかない場合:mvは失敗します
  • 2つのファイルがある場合:最初のファイルが2番目のファイルに移動されます(したがって、失われます)
  • ファイルが3つ以上ある場合:
    • 最後のものがディレクトリの場合:すべてのファイルがこのディレクトリに移動されます
    • そうでない場合、mvは失敗します。
18
jofel

mv ./*と入力すると、シェルはmvを実行する前に./*を展開します。

注意すべきいくつかの事柄:

  • ./*が2つ未満の引数に展開される場合、mvは論理的にはエラーを生成します。
  • ./*は通常、現在のディレクトリに存在し、ドットで始まっていないすべてのファイル(ディレクトリを含む)に展開されます。
  • シェルのドキュメントを読むことで、./*の展開対象を制御できます(man 7 globはトピックへのエントリポイントです)。シェルが異なれば、オプションも異なります。
4
rahmu

mv *の機能

ここに短い答えがあります:

シェルはワイルドカード*をディレクトリの内容のリストに展開します。次に、シェルはその完全なリストをコマンドに渡します。コマンドは*を見ることはありません。

コマンドmv file1 file2 ... filen directoryは、file1 ... filenをディレクトリに移動します。

ここでは、3つのファイルを含むテストディレクトリを作成します。

$ mkdir t
$ cd t
$ echo a>a; echo b>b; echo c>c
$ ls
a  b  c

複数のファイルを1つのファイルに移動することはできません

$ mv *
mv: target `c' is not a directory

サブディレクトリを追加しましょう

$ mkdir d

複数のファイルをサブディレクトリに移動することができます

$ mv *
$ ls
d
$ ls d
a  b  c
1
RedGrittyBrick