私は、最初の文字で1000以上のフォントを整理する方法(できれば端末)を探しています。
基本的にディレクトリA-Z, #
を作成し、ファイル名の最初の文字に基づいてフォントファイルをそれらのディレクトリに移動します。ディレクトリに移動する数字[0-9]またはその他の特殊文字で始まるフォント#
。
私は、最初の文字で1000以上のフォントを整理する方法(できれば端末)を探しています。
基本的にディレクトリA-Z, #
を作成し、ファイル名の最初の文字に基づいてフォントファイルをそれらのディレクトリに移動します。ディレクトリに移動する数字[0-9]またはその他の特殊文字で始まるフォント#
。
回答:
遅いpythonオプション:
#!/usr/bin/env python3
import os
import sys
import shutil
def path(dr, f): return os.path.join(dr, f)
dr = sys.argv[1]
for f in os.listdir(dr):
fsrc = path(dr, f)
if os.path.isfile(fsrc):
s = f[0]; target = path(dr, s.upper()) if s.isalpha() else path(dr, "#")
if not os.path.exists(target):
os.mkdir(target)
shutil.move(fsrc, path(target, f))
move_files.py
ディレクトリを引数として実行します:
python3 /path/to/move_files.py /path/to/files
スクリプトは、実際に必要な場合にのみ(sub)ディレクトリ(-ies)(大文字)を作成します
スクリプト:
ファイルをリストし、最初の文字を取得します(ソースパスを定義します):
for f in os.listdir(dr):
s = f[0]; fsrc = path(dr, f)
アイテムがファイルかどうかを確認します:
if os.path.isfile(fsrc):
最初の文字がアルファであるかどうかのいずれかのターゲットフォルダーを定義します。
target = path(dr, s.upper()) if s.isalpha() else path(dr, "#")
フォルダーが既に存在するかどうかを確認し、存在しない場合は作成します。
if not os.path.exists(target):
os.mkdir(target)
アイテムを対応するフォルダーに移動します。
shutil.move(fsrc, path(target, f))
2つのコマンドと2つの正規表現だけで、コードゴルフはできますが読み取り可能です。
mkdir -p '#' {a..z}
prename -n 's|^[[:alpha:]]|\l$&/$&|; s|^[0-9]|#/$&|' [[:alnum:]]?*
移動するファイルが大量で、プロセス引数リストに収まらない場合(はい、制限があり、わずか数キロバイトかもしれません)、別のコマンドでファイルリストを生成し、prename
、たとえば:
find -mindepth 1 -maxdepth 1 -name '[[:alnum:]]?*' -printf '%f\n' |
prename -n 's|^[[:alpha:]]|\l$&/$&|; s|^[0-9]|#/$&|'
これには、[[:alnum:]]?*
globパターンに一致するファイルがない場合にリテラルファイル名を移動しようとしないという利点があります。find
また、シェルグロビングよりも多くの一致基準を使用できます。別の方法として、nullglob
シェルオプションを設定し、の標準入力ストリームを閉じますprename
。1
どちらの場合も、-n
スイッチを削除して、ファイルの移動方法を示すだけでなく、実際にファイルを移動します。
補遺:次のコマンドで空のディレクトリを再び削除できます:
rmdir --ignore-fail-on-non-empty '#' {a..z}
1 shopt -s nullglob; prename ... <&-
zsh、関数、およびいくつかのzmv
コマンドを気にしない場合:
mmv() {echo mkdir -p "${2%/*}/"; echo mv -- "$1" "$2";}
autoload -U zmv
zmv -P mmv '([a-zA-Z])(*.ttf)' '${(UC)1}/$1$2'
zmv -P mmv '([!a-zA-Z])(*.ttf)' '#/$1$2'
このmmv
関数はディレクトリを作成し、ファイルを移動します。zmv
次に、パターンマッチングと置換を提供します。最初に、アルファベットで始まるファイル名を移動し、次に他のすべてを移動します。
$ zmv -P mmv '([a-zA-Z])(*.ttf)' '${(UC)1}/$1$2'
mkdir -p A/
mv -- abcd.ttf A/abcd.ttf
mkdir -p A/
mv -- ABCD.ttf A/ABCD.ttf
$ zmv -P mmv '([!a-zA-Z])(*.ttf)' '#/$1$2'
mkdir -p #/
mv -- 123.ttf #/123.ttf
mkdir -p #/
mv -- 七.ttf #/七.ttf
echo
in mmv
の定義なしで再実行して、実際に移動を実行します。
ディレクトリ名を大文字にする(または大文字でファイルを移動する)良い方法はありませんでしたが、後でrename
...
mkdir {a..z} \#; for i in {a..z}; do for f in "$i"*; do if [[ -f "$f" ]]; then echo mv -v -- "$f" "$i"; fi; done; done; for g in [![:alpha:]]*; do if [[ -f "$g" ]]; then echo mv -v -- "$g" \#; fi; done
またはもっと読みやすい:
mkdir {a..z} \#;
for i in {a..z}; do
for f in "$i"*; do
if [[ -f "$f" ]]; then
echo mv -v -- "$f" "$i";
fi
done
done
for g in [![:alpha:]]*; do
if [[ -f "$g" ]]; then
echo mv -v -- "$g" \#
fi
done
echo
実際にファイルを移動するには、テスト後に削除します
その後
rename -n 'y/[a-z]/[A-Z]/' *
-n
テスト後に問題がなければ削除して、再度実行します。
if [[ -d "${i^}" ]]
して、変数をi
大文字にすることができますmkdir {A..Z}
。
フォントを含むディレクトリ内の次のコマンドが機能するはずです。フォントストレージディレクトリの外部から使用する場合は、に変更for f in ./*
しfor f in /directory/containing/fonts/*
ます。これは非常にシェルベースの方法であるため、非常に遅く、また再帰的でもありません。これは、一致する文字で始まるファイルがある場合にのみディレクトリを作成します。
target=/directory/to/store/alphabet/dirs
mkdir "$target"
for f in ./* ; do
if [[ -f "$f" ]]; then
i=${f##*/}
i=${i:0:1}
dir=${i^}
if [[ $dir != [A-Z] ]]; then
mkdir -p "${target}/#" && mv "$f" "${target}/#"
else
mkdir -p "${target}/$dir" && mv "$f" "${target}/$dir"
fi
fi
done
1つのライナーとして、再びフォントストレージディレクトリ内から:
target=/directory/to/store/alphabet/dirs; mkdir "$target" && for f in ./* ; do if [[ -f "$f" ]]; then i=${f##*/}; i=${i:0:1} ; dir=${i^} ; if [[ $dir != [A-Z] ]]; then mkdir -p "${target}/#" && mv "$f" "${target}/#"; else mkdir -p "${target}/$dir" && mv "$f" "${target}/$dir" ; fi ; fi ; done
同様の文字列操作を使用して、bashパラメーター展開を使用するfindを使用するメソッドは、再帰的であり、純粋なシェルバージョンよりも多少速くなるはずです。
find . -type f -exec bash -c 'target=/directory/to/store/alphabet/dirs ; mkdir -p "$target"; f="{}" ; i="${f##*/}"; i="${i:0:1}"; i=${i^}; if [[ $i = [[:alpha:]] ]]; then mkdir -p "${target}/$i" && mv "$f" "${target}/$i"; else mkdir -p "${target}/#" && mv "$f" "${target}/#"; fi' \;
またはもっと読みやすい:
find . -type f -exec bash -c 'target=/directory/to/store/alphabet/dirs
mkdir -p "$target"
f="{}"
i="${f##*/}"
i="${i:0:1}"
i=${i^}
if [[ $i = [[:alpha:]] ]]; then
mkdir -p "${target}/$i" && mv "$f" "${target}/$i"
else
mkdir -p "${target}/#" && mv "$f" "${target}/#"
fi' \;
使用して、ディレクトリ名に各ファイル名の地図tr
そして、mkdir
とmv
:
find /src/dir -type f -print0 |
xargs -0 -I{} bash -c \
'dir=/dest/$(basename "{}" | cut -c1 | tr -C "a-zA-Z\n" "#" | tr "a-z "A-Z"); mkdir -p $dir; mv "{}" $dir'
tr
大文字に変換する別のものを追加しました。
xargs
電話するだけで迂回するのbash
ですか?find
whileループに出力をパイプ処理し、read
レコードごとに処理する方が簡単で読みやすいのではないでしょうか?
while
ループバージョン(bit.ly/2j2mhyb)の方が優れていると思います。
{}
置換を回避できます。例:。(ファイナルをおxargs
$1
xargs -0 -n1 -- bash -c 'dir=/dest/$(basename "$1" | ...); ...; mv "$1" "$dir"' _
_