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


27

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



4
mv1つの引数を受け入れることに驚いています」そうではありません。を展開した後にシェルが渡したすべての引数を受け入れます*
glglgl 14

回答:


41

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

デモは次のとおりです。

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

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

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

$ 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'

さらなる説明

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

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


30

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

touch file1 file2 file3 file4 file5
mkdir folder

次に、テストコマンドを実行します。この-vオプションは、シェルが実行するすべてのコマンドを印刷することを指定しますstderr-x私は印刷された同じことをしたいのオプションは、stderr- しかし、私はそれが行わたいのコマンドが評価されているが、シェルはそれを実行します。

sh -cxv 'echo mv *'

出力

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

したがって、シェルにフィードするecho mv *コマンドがあり、シェルが展開された後に 実行されるコマンドの後に、これらのファイルとフォルダーのすべて*echo mv続きます。

デフォルトでは、シェルは次のようなグロブを展開します。

sh -cxv 'echo file[1-5]'

出力

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

これは、set [+-]fglob関数の結果です。

sh -cxvf 'echo file[1-5]'

出力

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

そのmv *ため、シェルなどのデフォルトオプションで構成されたシェルでコマンドを実行する*と、現在のディレクトリ内のすべてのファイルの引数リストがロケールに従ってソートされた単語に展開されます。この引数リストexec(ve)mv (基本的に)追加してsyscall を実行します。したがって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、ディレクトリの内容(空でなく、名前がで始まるファイル/フォルダを含まない場合.を引数リストとして実行します。mv3つ以上の引数を指定して呼び出された場合、最終引数をディレクトリとして解釈するように指定されたPOSIXです-同じようln(実際、これらは基になる関数のツールに非常に似ているため)

echoしかし、十分なES:

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ターゲットがa /slashで終わっていない場合は単一の文字、およびsource_fileの最後のパス名コンポーネントの連結です。この2番目の形式は、最終オペランドが既存のディレクトリを指定するときに想定されます。

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

  • 2つのファイル

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

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

    • エラーメッセージと満足のいくため息が必要です。

1
はい、古いものを使用してsh、私はそれでデバッグするのを忘れましたが、私の元の質問に関しては、問題はシェルではないことを意味しmvますか?それは厄介で、当初考えていたよりも簡単ですが、本当のtrapです。
user2485710 14

5
@ user2485710、キーポイントは、Unixでは、シェルがコマンドライン引数をコマンドに渡す前にワイルドカードを展開する役割を担っていることです。Windowsでは、各コマンドはワイルドカード自体を展開する必要があります。これにより、Unixシェルは、任意のコマンドで機能する高度なワイルドカード機能を提供できます。
cjm 14

2
@mikeservは、これらのファイルがそれほど重要ではないという事実を考えて、駆除して次のステップにスキップしましたが、最初の投稿/質問の編集で表示されるようになったことを確認できます。
user2485710 14

6
@mikeserv tl; dr、*単一の引数ではありませんか?右?:)
ベルンハルト14

1
@Bernhard -実際に、それは私がカバーしていない一つのケースだ-それはので、かもしれないこと。
mikeserv 14

18

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

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

1
ありがとう。どのサブディレクトリが「最後のサブディレクトリ」であるかを確認する方法は?
ティム

7
echo ./*doを呼び出すだけで、シェルが使用する順序(通常はアルファベット順)を確認できます。
ジョフェル

1つのファイルで失敗した場合、なぜそう言わないのですか?
ヌメノン

@Noumenonあなたのコメントがわかりません。mv1つの引数のみで呼び出された場合、エラーメッセージを返します。
ジョフェル

あなたが正しいです。missing destination file operand after *filename*昨日はそうではありませんでしたが、私の歴史からの同じコマンドが今では与えます。
ヌメノン

4

入力するとmv ./*./*実行前にシェルが展開されますmv

注意すべきいくつかの点:

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

1

何を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

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

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

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

$ mkdir d

あなたはできる subdiretoryに複数のファイルを移動します

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

コマンドmv file1 file2 ... filen directoryが関係することはほとんどありません*
mikeserv 14

@Mike:私の答えは、シェル拡張の最終段階が後者を前者に効果的に変換することを指摘しています。これを知らないことがOPの混乱の原因であると思われます。
RedGrittyBrick

はい、しかし、私のポイントは、に続くロケールがなければシェルが展開*file dirないことです。df
mikeserv

@mikeserv:そのようなロケールがあります。私の例は、CentOS 5.6 GNU / Linuxシステムに接続するPuttyからのカットアンドペーストです。
RedGrittyBrick 14

それはどのロケールですか?あなたの例a b c dではないfile ... dirです。あなたはどこにもソートについて言及せず、それが起こるだけに*なると言うので、私はまったくコメントしましたfile ... dir
mikeserv 14
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.