ファイルを含む複数のディレクトリに対して一連の操作を繰り返し実行しようとしています。各ディレクトリ内に2つのディレクトリを作成し、いくつかのファイルを各ディレクトリに移動したいと思います。
たとえば、私のディレクトリ構造は次のようになります。
root --
subdirectory1 --
file_a1_a.tif
file_a2_a.tif
file_a1_b.tif
file_a2_b.tif
subdirectory2 --
file_b1_a.tif
file_b2_a.tif
file_b1_b.tif
file_b2_b.tif
ファイルをこのように整理したいのですが…
root --
subdirectory1 --
subdirectory_a --
file_a1_a.tif
file_a2_a.tif
subdirectory_b --
file_a1_b.tif
file_a2_b.tif
subdirectory2 --
subdirectory_a --
file_b1_a.tif
file_b2_a.tif
subdirectory_b --
file_b1_b.tif
file_b2_b.tif
私は次のことをしていますが、トップレベルのディレクトリでのみ動作しているようです。
find . -type d -execdir bash -c "mkdir -p subdirectory_a && mkdir -p subdirectory_b && mv *_a.tif subdirectory_a 2>/dev/null && mv *_b.tif subdirectory_b 2>/dev/null" \;
どんな助けでも大変感謝します。
答え1
root
子だけがあり、孫はいないので、ディレクトリから次を実行できますroot
。
subA='subdirectory_a'
subB='subdirectory_b'
for d in */; do
mkdir -p "$d$subA" "$d$subB"
mv "$d"*_a.tif "$d$subA"
mv "$d"*_b.tif "$d$subB"
done
$d
and で拡張される for ループの glob のため、subdirectory1/
直接サブディレクトリにのみ一致します。その孫ファイル(すでに存在する場合は文句を言わないように存在)を作成し、ワイルドカードを再使用してファイルを孫ファイルに移動します。subdirectory2/
*/
root
mkdir
-p
シェルがglobを拡張したい場合は、引用符を解除する必要があります。だからそうですが、mv "$d"*_a.tif "$d$subA"
正確mv "$d*_a.tif" "$d$subA"
ではありません。
答え2
質問に投稿したコマンド
find . -type d -execdir bash -c "mkdir -p subdirectory_a && mkdir -p subdirectory_b && mv *_a.tif subdirectory_a 2>/dev/null && mv *_b.tif subdirectory_b 2>/dev/null" \;
正しく機能します(つまり、やるべきことを行います)。しかし、それが表現するのはあなたが望むものではありません。
このパラメータは、「...指定されたコマンドは-execdir
一致するファイルを含むサブディレクトリで実行されます」(ソースコード、
検索(1))
つまり、現在のジョブが直接であり、root
コマンドがそれをターゲットにしているsubdirectory1
場合、期待どおりにドロップダウンされません。内部でsubdirectory1
一致するものが-type d
見つかったので、その場所にとどまり、そこで指定されたコマンドを実行します。もちろん、その中にファイルがないので何も移動されませんが、また次のようなエラーが発生しないことにも注意してください。find
root
mkdir
root
mkdir -p
目次(1): 「存在する場合、エラーはありません。」
それでは、このゲームをあなたが望むゲームにするにはどうすればよいですか?同じ構造を投稿したとしましょう。
$ tree /tmp/root
/tmp/root
├── subdir1
│ ├── file_a1_a.tif
│ ├── file_a1_b.tif
│ ├── file_a2_a.tif
│ └── file_a2_b.tif
└── subdir2
├── file_b1_a.tif
├── file_b1_b.tif
├── file_b2_a.tif
└── file_b2_b.tif
3つの段階に分けることをお勧めします。すべてのタスクを実行するために1つのコマンドを使用する必要はありません。 「コードゴルフ」ではなく、目的の結果に集中してください。だからまずディレクトリを作成してください
$ find /tmp/root -maxdepth 1 -mindepth 1 -exec bash -c 'mkdir ${1}/subdirectory_{a,b}' sh {} \;
$ tree
.
├── subdir1
│ ├── file_a1_a.tif
│ ├── file_a1_b.tif
│ ├── file_a2_a.tif
│ ├── file_a2_b.tif
│ ├── subdirectory_a
│ └── subdirectory_b
└── subdir2
├── file_b1_a.tif
├── file_b1_b.tif
├── file_b2_a.tif
├── file_b2_b.tif
├── subdirectory_a
└── subdirectory_b
6 directories, 8 files
次に、ディレクトリツリーの特定のレベルで通常のファイルを見つけて移動します。今、私たちはそれを使用して-execdir
私たちが望むものを達成することができます
$ find /tmp/root -maxdepth 2 -mindepth 2 -type f -execdir bash -c 'case ${1} in *a.tif) echo cp ${1} ./subdirectory_a ;; *b.tif) echo cp ${1} subdirectory_b ;; esac' sh {} \;
cp ./file_b2_b.tif subdirectory_b
cp ./file_b2_a.tif ./subdirectory_a
cp ./file_b1_a.tif ./subdirectory_a
cp ./file_b1_b.tif subdirectory_b
cp ./file_a1_b.tif subdirectory_b
cp ./file_a1_a.tif ./subdirectory_a
cp ./file_a2_b.tif subdirectory_b
cp ./file_a2_a.tif ./subdirectory_a
この場合は、移動する前にエコーを使用してすべてが正しく機能していることを確認し、実際の移動を行わないことに注意してください。したがって、それを削除するとecho
正しく機能します。
$ find /tmp/root -maxdepth 2 -mindepth 2 -type f -execdir bash -c 'case ${1} in *a.tif) cp ${1} ./subdirectory_a ;; *b.tif) cp ${1} subdirectory_b ;; esac' sh {} \;
$ tree /tmp/root
/tmp/root
├── subdir1
│ ├── file_a1_a.tif
│ ├── file_a1_b.tif
│ ├── file_a2_a.tif
│ ├── file_a2_b.tif
│ ├── subdirectory_a
│ │ ├── file_a1_a.tif
│ │ └── file_a2_a.tif
│ └── subdirectory_b
│ ├── file_a1_b.tif
│ └── file_a2_b.tif
└── subdir2
├── file_b1_a.tif
├── file_b1_b.tif
├── file_b2_a.tif
├── file_b2_b.tif
├── subdirectory_a
│ ├── file_b1_a.tif
│ └── file_b2_a.tif
└── subdirectory_b
├── file_b1_b.tif
└── file_b2_b.tif
6 directories, 16 files
もちろん、これはデータの損失を防ぐためにレプリケーションを使用することに注意してください。我々はそれをより整理することができ、最終的に希望のディレクトリツリー構造を取得します。
$ find /tmp/root -maxdepth 2 -mindepth 2 -type f -delete
$ tree
.
├── subdir1
│ ├── subdirectory_a
│ │ ├── file_a1_a.tif
│ │ └── file_a2_a.tif
│ └── subdirectory_b
│ ├── file_a1_b.tif
│ └── file_a2_b.tif
└── subdir2
├── subdirectory_a
│ ├── file_b1_a.tif
│ └── file_b2_a.tif
└── subdirectory_b
├── file_b1_b.tif
└── file_b2_b.tif
6 directories, 8 files
簡単に言えば、私たちがすることはスクリプトで表現できます。
find /tmp/root -maxdepth 1 -mindepth 1 -exec bash -c 'mkdir ${1}/subdirectory_{a,b}' sh {} \; &&
find /tmp/root -maxdepth 2 -mindepth 2 -type f -execdir bash -c 'case ${1} in *a.tif) cp ${1} ./subdirectory_a ;; *b.tif) cp ${1} subdirectory_b ;; esac' sh {} \; &&
find /tmp/root -maxdepth 2 -mindepth 2 -type f -delete
もちろん、代わりにmv
2段階と3段階を1つに圧縮することはできますが、cp
データ損失のリスクを減らすのではなく、注意してください。
答え3
ディレクトリ内で実行すると、コマンドはroot
最上位subdirectoy_a
レベルに、およびおよびで終わるすべてのファイルとで終わるすべてのファイルを移動します。これは望むものではありません。これにより、リダイレクトされたエラーがなく、実際にエラーを表示できる場合は、トラブルシューティングが簡単になります。親ディレクトリがすでに存在するため、オプションは必要ありません。subdirectory_b
subdirectory1
subdirectory2
a.tiff
subdirectory1
b.tiff
subdirectory_b
/dev/null
-p
mkdir
持っているのではなく、root
内部(または実際の呼び出しディレクトリ)で実行してください。
mkdir subdirectory1/subdirectory_a subdirectory1/subdirectory_b subdirectory2/subdirectory_a subdirectory2/subdirectory_b && mv subdirectory1/file_a*a* subdirectory1/subdirectory_a && mv subdirectory1/file_a*b* subdirectory1/subdirectory_b && mv subdirectory2/file_b*a* subdirectory2/subdirectory_a && mv subdirectory2/file_b*b* subdirectory2/subdirectory_b
答え4
そしてzsh
:
cd root || exit
subdirs=(*(-/))
mkdir -p -- $^subdirs/subdirectory_{a,b} || exit
autoload -Uz zmv
zmv '(*/)*_(a|b).tif' '${1}subdirectory_$2/$f:t'
必要なら再帰的subdir1/subsubdir1
*
あなたの質問からわかるように(あなたの例では提案されていません*(-/)
)(*/)
。**
多数のファイルがあり、速度が問題の場合は、zsh組み込みコマンドを実行して(によって呼び出されますzmodload zsh/files
)。mkdir
mv
zmv
一つのために試運転zmv
なんだが教えてくれるところ会議オプションを追加してください-n
。
それぞれを含むディレクトリにおよびを作成したい場合は、subdirectory_a
他のアプローチがあります。subdirectory_b
*_a.tif
*_b.tif
mkmv() { mkdir -p -- $2:h && mv -- "$@"; }
zmv -P mkmv '(**/)*_(a|b).tif' '${1}subdirectory_$2/$f:t'
(ファイルは自分tif
のroot
ファイルも移動します。)