ディレクトリにたくさんのファイルがあるとします
filename-1.ext1
filename-1.ext2
filename-1.ext3
filename-2.ext1
filename-2.ext2
filename-2.ext3
filename-3.ext1
filename-3.ext2
filename-3.ext3
次に、同じディレクトリにファイルと同じ名前(ファイル名は拡張子なし)のサブディレクトリを作成し、次のように移動します。
filename-1
├──filename-1.ext1
├──filename-1.ext2
└──filename-1.ext3
filename-2
├──filename-2.ext1
├──filename-2.ext2
└──filename-2.ext3
filename-3
├──filename-3.ext1
├──filename-3.ext2
└──filename-3.ext3
これを達成するための最も効率的な方法は何でしょうか?
編集: ext1、ext2、ext3 は、.foo、.bar、.top、.coffee などの 3 つの異なるファイル名を示すだけです。ファイル名が似ているということではありません。
答え1
を使用しているのでzsh
、次のように実行できます。
for name (*.ext<->(.)) mkdir -p -- $name:r && mv -- $name $name:r
または、より一般的な長い形式のループを使用するとfor
、
for name in *.ext<->(.); do
mkdir -p -- $name:r &&
mv -- $name $name:r
done
*.ext<->
これは、任意の番号に一致するパターンに一致するすべての通常ファイルを反復処理します。通常ファイルのみの一致を強制するのは、<->
glob 修飾子です。ドットを含む通常ファイルのファイル名に一致させたい場合は、パターン全体を に変更します。後でファイル名拡張子を削除する必要があるため、ドットが存在する必要があります。緩いパターンではなく、より厳密なパターンを使用するには、 のようなものを使用します。このパターンでは、文字列 で始まる名前に一致させる必要があることを知っている必要があります。(.)
*.*(.)
filename-<->.ext<->(.)
filename-
$name:r
展開すると、 と同じ値になりますが、拡張子は含まれ$name
ません (つまり、値の「ルート」のみになります)。
--
両方に対してオプションの終了を通知しmkdir
、mv
ダッシュで始まる名前がオプションと間違われるのを防ぐために使用します。
答え2
とzmv
:
autoload -Uz zmv # best in ~/.zshrc
mkmv() { mkdir -p -- $2:h && mv -- "$@"; }
zmv -P mkmv -n '(*).ext<->(#q.)' '$1/$f'
(-n
満足したら削除してください)。
そうすれば、zmv
の健全性チェックの恩恵を受けることができます。
答え3
for
bash シェルと zsh シェルの両方と互換性のある次のループを使用します。
for file in *.*; do
[ -f "$file" ] &&
mkdir -p -- "${file%.*}" &&
mv -- "$file" "${file%.*}/"
done
-p
オプションでmkdir
ファイルが存在することを確認するとエラーは発生しません%.*
ファイル名から拡張子を削除します。
答え4
GNU parallel (その威力に気づき始めたばかりのツール) を使用すると、次のようになります。
ls | parallel 'mkdir -p {.}; mv -i {} {.}'
これは CPU に縛られるものではないため、parallel
速度上の利点はないと思われますが、それでも他の多くのソリューションよりも短くなります。
これはファイル名のパターンに依存しません。