結論
お急ぎの方のために結論から書きますと、以下のコマンドを実行すれば移動できます。
$ find . -type f | xargs -I@ mv @ {直下のディレクトリ名}/
解説
具体例を使いながら解説していきます。
ディレクトリ構成図
現在のディレクトリ構成が以下の通りだとします。
. ├ dest/ ├ foo.json ├ hoge.md ├ sample1 ├ sample2 ... ├ sample100 └ test1.txt
やりたいこと
カレントディレクトリにある全てのファイルを、同じくカレントディレクトリ内にあるdestディレクトリに移動させたいです。
エラー
一つずつ手で移動させるのも面倒なので、以下のコマンドを実行したところ、エラーが出ました。
$ find . -type f | xargs mv dest/ mv: ./foo.json is not a directory
mvコマンドを実行するにあたり「foo.jsonはディレクトリじゃない」と怒られています。
いやfoo.jsonがファイルなのは知っているよ。。どういうこと?
原因
調べてみると、原因はfindコマンドの実行結果が全てmvコマンドに渡されてしまうことにあるようです。
詳しく見て行きましょう。
まず試しにfindコマンド部分だけ実行してみると、ファイル名が全て表示されます。
$ find . -type f ./hoge.md ./foo.json ./test1.txt ./sample1 ...
エラーでは、この出力結果をそのままmvコマンドに渡していました。
すると以下のように、ファイルを別のファイルに移動させようとしていると解釈されてしまいます。
mv ./sample ./foo.json
こんなことがしたいわけじゃないですよね。移動させたい先はdestディレクトリです。
解決方法
使用したのは、xargsコマンドのIオプションです。
Iオプションは「xargs -I@」のように設定すると、@部分に受け取った引数を配置してくれます。
つまり今回の場合は「xargs -I@ @ dest/」とすると、実行時に@をファイル名に置き換えてくれるんです!
もう一度結論
ここで、最初に結論で書いたコマンドをもう一度見てみます。
$ find . -type f | xargs -I@ mv @ dest/
もう何をやっているかわかりますよね。 findコマンドによって直下のファイル名が出力されます。 そして、出力されたファイル名が@部分に1つずつ入るので、内部では以下が実行されることになります!
mv ./hoge.md dest/ mv ./foo.json dest/ mv ./test1.txt dest/ mv ./sample1 dest/ ... mv ./sample100 dest/
無事に直下のファイルを全て直下のdestディレクトリに移動できました!
xargsコマンドのIオプションの補足
xargsコマンドのIオプションで指定する記号は@でなくても良いようです。
以下は{}を使用した場合の例です。
$ find . -type f | xargs -I{} mv {} dest/