フォルダーのディレクトリを検索し、フォルダーの内容をその場所から1つ上のディレクトリに移動するスクリプトを記述しようとしています。これは私がこれまでに持っているものです:
find ./localFolders -name 'file' -type d -exec mv {}/* .. \;
私の問題は..
の宛先ディレクトリにあると思います。おそらく私はこれを間違って表現していますか?
任意のヘルプが便利です。
* edit**
この病気を簡素化するために、より多くの情報に行きます
私は、MS ExchangeからZimbraに移行しようとしている組織にいます。移行の一環として、メールボックスを転送する優れたユーティリティが見つかりましたが、PSTファイルをZimbraの使用可能な形式に転送することは困難です。
長い話を短くするためにいくつかの解決策を見つけましたが、1つの例外を除いてpstファイルを使用可能な形式にスピンアウトできました。
そのフォルダにメールを置く代わりに、“mbox”
と呼ばれるサブディレクトリが作成されます。おそらく、.emlファイルが分割されるmboxファイルに似ています。各ユーザーは異なり、他のユーザーとは異なるフォルダー構造を使用するため、スクリプトが実行されるまで各ディレクトリは不明です。さらに、mboxフォルダーの内容も一意です。
これらのディレクトリでは、mboxという名前のフォルダのみが定数であるため、findを使用してこれらのフォルダを見つけ、そのフォルダの内容を取得して1つのディレクトリに移動し、mboxという名前のフォルダを削除します。スクリプトに表示される実際のコマンドは次のとおりです。
find localFolders -name mbox -type d -exec mv {}/* .. \;
またはあなたが与えた例では:
find localFolders -name mbox -type d -execdir sh -c 'echo mv {}/* ..' \;
*
をワイルドカードとして使用して、mboxフォルダー内のすべてを選択しようとしています。私が知る限り、それは代わりにディレクトリの一部として扱われ、意図したとおりのワイルドカードではありません
考え?
これはどう?
find ./localFolders -name 'file' -type d -execdir bash -c 'mv -vnt . -- "$0"/*' {} \; -Prune
ファイル名のスペースと面白い記号に関しては安全です。楽しい!
find
を使用して適切に行うには、次の概念を理解する必要があります。
Linuxのすべてのプロセスには、内部状態の一部として作業ディレクトリがあります。ファイルシステム内のプロセスの「場所」として想像できます。シェルもプロセスであり、作業ディレクトリがあります。シェルの作業ディレクトリは、(通常)プロンプトに表示されるディレクトリです。
プロセスが作成されると、その親から作業ディレクトリを継承します。シェルからプロセスを開始する場合、シェルは親です。すべてのプロセスは、独自の作業ディレクトリを自由に変更できます。組み込みコマンドcd
を使用して、シェルの作業ディレクトリを変更できます。
作業ディレクトリは、相対ファイル名を扱うときに使用されます。相対ファイル名は、/
で始まらないファイル名です。たとえば、cat foo
を実行すると、現在の作業ディレクトリでファイルfoo
が検索されますが、cat /tmp/foo
を実行すると、/tmp
でファイルfoo
が検索されます。
find -exec
を扱うときは、常に作業ディレクトリについて考える必要があります。 -exec
の作業ディレクトリは、find
の作業ディレクトリです。 find
の作業ディレクトリは、シェルの作業ディレクトリです。
あなたの場合:
find ./localFolders -name 'file' -type d -exec mv {}/* .. \;
..
は、コマンドを実行するまでに、シェルの作業ディレクトリであるmv
の作業ディレクトリである-exec
の作業ディレクトリであるfind
の作業ディレクトリの親ディレクトリを参照します。それはあなたが望んでいたものではありません。
-execdir
は-exec
に似ていますが、最初に作業ディレクトリを、一致するアイテムが見つかったディレクトリに切り替えます。 -execdir
は質問の解決に向けた大きな一歩ですが、find
コマンドには別の問題があります:*
a.k.a. glob。
グロブはワイルドカードのようなものです。たとえば、foo*
はfoobar
およびfoobaz
に一致します(および*
もヌル文字列に一致するため、foo
)。ここまでは順調ですね。グロビングの興味深い部分は、実行されたコマンドではなく、シェルによって行われることです。 rm foo*
を実行すると、シェルはまず*
をfoobar
およびfoobaz
に展開し、rm foobar foobaz
を実行します。 rm
は*
を見ることはありません。
現在のディレクトリにfoo
で始まるファイルがない場合はどうなりますか?その後、シェルは(通常)*
を展開せず、*
を逐語的にコマンドに渡します。つまり、rm foo*
はrm foo*
として実行されます。 rm
はfoo*
という名前のファイルを探しますが、(ほとんどの場合)ファイルを見つけられず、エラーで中断します。あなたが疑問に思っている場合:はい、ファイル名に*
を含めることは可能です。いいえ、それを自宅で試してはいけません。
あなたの場合:
find ./localFolders -name 'file' -type d -exec mv {}/* .. \;
find
コマンドを実行する前に、シェルは最初にグロブ{}/*
を展開しようとします。パターン{}/*
に一致するファイルはないため、グロブはそのまま渡されます。
find
コマンドの機能を見てみましょう。 /home/username/somedir
からfind
コマンドを実行しており、その中にいくつかのファイルがあるディレクトリ/home/username/somedir/localFolders/foodir/file
が存在するとします。 find
はパラメータで指定されているため/home/username/somedir/localFolders
で検索を開始しますが、find
の作業ディレクトリはそこから実行されたため/home/username/somedir
です。
これでfind
がディレクトリ/home/username/somedir/localFolders/foodir/file
を見つけました。 -exec
を実行する前に、{}
を見つかったアイテムに置き換えます。つまり、mv {}/* ..
はmv /home/username/somedir/localFolders/foodir/file/* ..
になります。 mv
は、(おそらく)*
という名前のファイルを見つけられないため失敗します。
*
という名前のファイルがあり、mv
がファイルを..
に移動するとします。作業ディレクトリは/home/username/somedir
であることを忘れないでください。つまり、mv
はファイルを/home/username/somedir/..
である/home/username
に移動します。それはあなたが望んでいたものではありません。
find
コマンドの「修正」は、いくつかの要因に依存します。例えば:
file
ディレクトリに「ドットファイル」がありますか?ドットファイルは、ドットで始まる名前のファイルです。 *
globは(通常)ドットで始まるファイル名には展開されません。file
ディレクトリに他のディレクトリはありますか? find
はそれらに再帰しようとしますが、移動されているため失敗します。file
ディレクトリにfile
という名前のディレクトリがありますか?それらのファイルはどこに行くべきですか?file
ディレクトリに膨大な数のファイルがありますか?それは*
glob展開を台無しにするかもしれません。file
ディレクトリからのファイルとファイル名の衝突はありますか?上書きする必要がありますか?find
コマンドを修正するために、これらすべての要因を喜んで無視します。
-execdir
およびsh -c
を使用して、*
の展開を遅らせる修正方法を次に示します。
find ./localFolders -name file -type d -execdir sh -c 'mv {}/* ..' \;
*
は引用符で囲まれているため、事前に展開されません。 -execdir
がコマンドを実行すると、sh -c
は作業ディレクトリ内の*
を展開します。
sh -c
を使用しない別の修正を次に示します。
find ./localFolders -path "*/file/*" -execdir mv {} .. \;
-path
を使用して、file
という名前のディレクトリの下にあるすべてのアイテムを見つけました。 *
は引用符で囲まれているため、事前に拡張されません。今回はfind
が*
の解釈を処理します。これは./localFolders/foodir/file/bardir/file/somefile
のようなものにも一致することに注意してください。言ったように、私は喜んでその要素を無視しました。
完全を期すため、-execdir
を使用しない別の修正:
find ./localFolders -name file -type d -exec sh -c 'mv {}/* {}/..' \;