未知の種類のLinuxを実行している古いReadyNASDuo v1(Sparc)があります。
1,000以上のファイルを含むフォルダ構造で、ファイル名の最初の文字に基づいてフォルダ構造に移動したい(大文字と小文字は区別されない)。
理想的には、ファイル構造を次のようにしたいと思います。
myfiles-+
+-A
+ Apple.txt
+ avocado.txt
+-B
+ Banana.txt
+ broccoli.txt
etc. etc.
私はGoogleを持っていましたが、GUIツールしか見つかりませんでした。
これは、コマンドラインまたはスクリプトを介して実行できますか?
ここにあなたが望むことをするワンライナーのビットがあります:
$ mkdir -p output/{A..Z}; for i in tstdir/*; do export FILE=$(basename "$i"); LTR=$(echo" ${FILE:0:1}" | tr [a-z] [A-Z]); mv "$i" "output/$LTR/$FILE" ; done
これが展開された形式の同じコマンドで、何が起こっているかを確認できます。
$ mkdir -p output/{A..Z}
$ for i in tstdir/*; do
FILE=$(basename "$i")
LTR=$(echo "${FILE:0:1}" | tr [a-z] [A-Z])
mv "$i" "output/$LTR/$FILE"
done
上記は最初に、文字だけの出力ディレクトリが存在しないことを前提としているため、それを作成します。
$ mkdir -p output/{A..Z}
for
ループは次のように機能し、tstdir/*
内のすべてのファイルをループします。次に、このパスのbasename
を判別し、変数$FILE
に格納します。ループの各反復は、変数$i
に格納されます。
FILE=$(basename "$i")
次に、Bashes機能を使用して名前付き変数$FILE
の最初の文字を返し、次にtr
を使用して小文字を大文字に変換します。
LTR=$(echo "${FILE:0:1}" | tr [a-z] [A-Z])
これをもう少し分解します:
$ echo "${FILE:0:1}"
s
$ echo "${FILE:0:1}"
T
tr
コードを使用すると、何が起こっているかを確認できます。
$ echo "${FILE:0:1}" | tr [a-z] [A-Z]
S
$ echo "${FILE:0:1}" | tr [a-z] [A-Z]
T
コマンドの残りの部分は、ファイルを対応する最初の文字のディレクトリに移動するだけです。
次のファイルディレクトリがあるとします。
$ touch {a-z}file {A-Z}file
$ tree tstdir/ | head -10
tstdir/
|-- afile
|-- Afile
|-- bfile
|-- Bfile
|-- cfile
|-- Cfile
|-- dfile
|-- Dfile
|-- efile
...
ワンライナーを実行した後:
$ tree output/ | head -10
output/
|-- A
| |-- afile
| `-- Afile
|-- B
| |-- bfile
| `-- Bfile
|-- C
| |-- cfile
| `-- Cfile
...
zsh
_mkmv() {mkdir -p -- $argv[-1]:h && mv "$@"}
autoload zmv
zmodload zsh/files
zmv -Qp mkmv '(?)*(^-/)' '${(U)1}/$f'
_
zmv
自動ロード可能な関数として、zshの強力なパターンマッチングおよび拡張演算子を使用してファイルを安全にバッチで名前変更する関数。mkmv
:mv
のように機能する関数ですが、必要に応じてターゲットの親ディレクトリも作成する点が異なります。$argv[-1]
_:_$argv
_は_$*
_のように位置パラメータのリストであり、_$argv[-1]
_は最後のパラメータです。ここでは、_$3
_と同じようにzmv
はそれを_mkmv -- source destination
_と呼びます$var:h
_:csh
のように、 変数のheadを取得します。つまり、dir名です 。zmodload zsh/files
_:mkdir
やmv
を含むいくつかのファイル処理ユーティリティの組み込みバージョンを有効にする module をロードします。ここでは、パフォーマンスが大幅に向上しています。 '各ファイルに対して両方を呼び出しています。-Q
_:パターン内のbareグロブ修飾子を有効にします。最近では、_(^-/)
_を_(#q^-/)
_に書き換えることもできます。-p mkmv
_、zmv
の代わりに、名前を変更するプログラムとしてmkmv
関数を使用するようにmv
に指示します。(?)*(^-/)
_:パターン_(?)*
_は、名前を変更するファイルを照合するために使用されるグロブ修飾子を使用します。括弧内の_?
_(単一の文字に一致する)はcapturedであるため、置換では_$1
_と呼ぶことができます。 。(^-/)
_: glob qualifiers 名前だけでなく、より多くの基準に基づいてファイルを照合するために使用されます:^
_:次の修飾子を無効にします-
_:次の修飾子の場合、シンボリックリンクの場合は、リンク自体ではなく、リンクのターゲットの属性を考慮してください。/
_:ディレクトリタイプのファイルを選択します。前の2つの修飾子を使用すると、ディレクトリでもディレクトリへのシンボリックリンクでもないファイルが必要になります。${(U)1}
:一致したファイルのキャプチャされた最初の文字。U
で大文字に変換されます パラメータ展開フラグ$f
_は、一致したファイルの完全パスを指します。このスクリプトで試してください:
for first in $(ls -1 | sed 's/^\(.\).*$/\1/' | tr '[a-z0-9]' '[A-Z0-9]' | uniq)
do
mkdir tmp
mv "$first"* tmp/
lower=$(echo $first | tr '[A-Z]' '[a-z]')
mv "$lower"* tmp/
mv tmp/ "$first";
done
ロジックは次のとおりです。
sed
を使用して最初の文字を抽出します。tr
を使用して、最初の文字を小文字に変更します。これは、比較の数を減らすためです。uniq
で重複を削除します。これらのファイルを使用してスクリプトをテストしました。
Apple.txt
avocado.txt
banana.txt
broccoli.txt
car.txt
dddd.txt
delete.txt
zaad.txt
zdfa.txt
結果は次のとおりです。
.
├── A
│ ├── Apple.txt
│ └── avocado.txt
├── B
│ ├── banana.txt
│ └── broccoli.txt
├── C
│ └── car.txt
├── D
│ ├── dddd.txt
│ └── delete.txt
└── Z
├── zaad.txt
└── zdfa.txt
5 directories, 10 files
ここにブルートフォースアプローチがあります。
for i in {a..z}; do
upper=$(printf "%s\n" $i | tr '[a-z]' '[A-Z]');
ls -1 | grep -i "^$i" 2>/dev/null 1>&2 && mkdir -p $upper &&
mv "$i*" "$u*" $u/ 2>/dev/null;
done
これはすべての文字({a..z}
)、大文字に変換します(tr '[a-z]' '[A-Z]'
)、その文字で始まるファイルがあるかどうかを確認します(ls -1 | grep -i $i
)その場合は、大文字を名前として使用してディレクトリを作成します(mkdir -p $upper
)次に、問題の文字(小文字と大文字の両方)で始まるすべてのファイルを対応するフォルダーに移動します。
これをNASで実行していて、おそらく最小限のシェルがインストールされているので、{a..z}
形式が機能しない可能性があります。もしそうなら、代わりにこれを行います(I saidこれはブルートフォースアプローチでした):
for i in a b c d e f g h i j k l m n o p q r s t u v w x y z; do
upper=$(printf "%s\n" $i | tr '[a-z]' '[A-Z]');
ls -1 | grep -i "^$i" 2>/dev/null 1>&2 && mkdir -p $upper &&
mv "$i*" "$u*" $u/ 2>/dev/null;
done
SLMの回答を改善するために、0から9までのディレクトリーを作成することにより、数字で始まるファイルに対してこれを機能させることもできます。
mkdir -p output/{A..Z}; mkdir -p output/{0..9}; for i in tstdir/*; do export FILE=$(basename "$i"); LTR=$(echo "${FILE:0:1}" | tr [a-z] [A-Z]); mv "$i" "output/$LTR/$FILE" ; done