LoginSignup
2
2

More than 3 years have passed since last update.

"treeコマンドのディレクトリ内のファイル一覧をソートしたい!"をPythonのsortedのkeyパラメータで

Posted at

はじめに

Windowsの話です。

treeコマンドは、ディレクトリの構造を木構造形式で見ることができるアレです。

tree.cmd
├─CrystalBeadsCurtain00002
│  │  crystal_bead_curtain_diffuse.tga
│  │  crystal_bead_curtain_transparency.png
│  │  DemoProducts_CrystalBeadsCurtain00002_0001.max
│  │  DemoProducts_CrystalBeadsCurtain00002_0001.rfa
│  │  FRONT_LOD0_DemoProducts_CrystalBeadsCurtain00002.dwg
│  │  PLAN_LOD0_DemoProducts_CrystalBeadsCurtain00002.dwg
│  │  SIDE_LOD0_DemoProducts_CrystalBeadsCurtain00002.dwg
│  │
│  └─SOURCE_DATA
├─ENA101Art00001
│  │  DemoProducts_ENA101Art00001_0001.max
│  │  DemoProducts_ENA101Art00001_0001.rfa
│  │  DemoProducts_ENA101Art00001_render.jpg
│  │  FRONT_LOD0_DemoProducts_ENA101Art00001.dwg
│  │  PLAN_LOD0_DemoProducts_ENA101Art00001.dwg
│  │  SIDE_LOD0_DemoProducts_ENA101Art00001.dwg
│  │
│  └─SOURCE_DATA
│          EN_A_101_A_103_A104_190603.fbx
│

一覧性がいいので、必要なファイルが揃っているかなどを確認したいときに便利です。
自分は割とよく使います。
ただ、ちょっとだけ改善出来たらいいなと思うところがあります。
それが 並び順 についてです。

Windowsのtreeコマンド

Windowsのtreeコマンドは、Linuxのtreeコマンドと違って、オプションが2つしかありません。
このオプションにソート(並び換え)に関するものはありません。
常に単純な名前順になってしまいます。

もっと見やすく並べられたらなぁというのが希望です。
出来ることなら、重要なファイルから順に並んでくれたらなおいいと思います。

これをPythonでなんとかします。

ディレクトリの一覧を取得する

まずはディレクトリの一覧を作ります。
こちらの方のブログ記事を参考にしました。

Powershellでディレクトリの一覧

当初、Powershellでそういうことが出来ないかとトライしてみました。
Windows10ではPowershellのウィンドウをとても簡単に "その場所" で開くことが出来ます。
そうするとパスの指定が不要になり、コマンドの実行が非常に簡単だからです。1
ただ、自分がPowershellに慣れてなくて、結局諦めました...。

テストコード

powershell:pstree.ps1
cls
function pstree($path, $level) {
if ($path | Test-Path) {
foreach($item in (Get-ChildItem $path) )
{
Write-Host ("`t"*$level + $item.Name)
if($item.PSIsContainer)
{
pstree $item ($level+1)
}
}
}
}
pstree "Z:\PROJECTS\MODELS" 0

そもそも、並び替えをどしたらよいのかわかりません。
リストを順番に見ていってスワップするような関数を書くとか?でしょうか。
なんか面倒くさそうな...。

でもPythonならもっと簡単に書けるはず!

Pythonでディレクトリの一覧

Python3で書きました。
pathlibを使用します。

tree.py
from pathlib import Path

def tree(path=None, level=0):
    p = Path(path)
    if p.exists():
        ff = list(p.glob('*'))
        for f in ff:
            print( '{0}{1}{2}'.format('\n' if level == 0 else '' , '\t' * level, f.name.split('\\').pop() ) )
            if f.is_dir():
                tree(f, level + 1)

path = r'Z:\PROJECTS\MODELS'
tree(path, 0)

結果 ↓

_tree.txt
DFC8638BAA
    control.jpg    <--- テクスチャ画像は一番後ろへまとめて並べたい
    DEMO_DFC8638BAA_0001.max
    DEMO_DFC8638BAA_0001.rfa
    DEMO_DFC8638BAA_render.jpg
    DEMO_logo.tga   <--- テクスチャ画像は一番後ろへまとめて並べたい
    DR03-109-01-DFC79.jpg   <--- テクスチャ画像は一番後ろへまとめて並べたい
    FRONT_LOD0_DEMO_DFC8638BAA.dwg
    FRONT_LOD1_DEMO_DFC8638BAA.dwg
    lonseal_lonrium_5116.png   <--- テクスチャ画像は一番後ろへまとめて並べたい dwgの間に入るなんてもってのほか!
    PLAN_LOD0_DEMO_DFC8638BAA.dwg
    PLAN_LOD1_DEMO_DFC8638BAA.dwg
    SIDE_LOD0_DEMO_DFC8638BAA.dwg
    SIDE_LOD1_DEMO_DFC8638BAA.dwg
    SOURCE_DATA
        DFC86-AA15-AA10_rev1.dwg
    SUS_diffuse.png
    SUS_glossiness.png
    SUS_normal.png
    top.jpg   <--- できれば拡張子ごとにきれいに並んでほしい
    fan_alpha.png
    fan_diffuse.png

DFD41AH18AA
    DEMO_DFD41AH18AA_0001.max
    DEMO_DFD41AH18AA_0001.rfa
    DEMO_DFD41AH18AA_render.jpg
    DEMO_logo.tga   <--- テクスチャ画像は一番後ろへまとめて並べたい
    FRONT_LOD0_DEMO_DFD41AH18AA.dwg
    FRONT_LOD1_DEMO_DFD41AH18AA.dwg
    PLAN_LOD0_DEMO_DFD41AH18AA.dwg
    PLAN_LOD1_DEMO_DFD41AH18AA.dwg
    SIDE_LOD0_DEMO_DFD41AH18AA.dwg
    SIDE_LOD1_DEMO_DFD41AH18AA.dwg
    SOURCE_DATA
        DFD41-AH18-AA00_rev2.dwg
        カタログ_P121.pdf
    top.jpg

普通にやると、やっぱり、"いい感じ" に並んでくれないです。 2
この並び順を直すには、globで集めたリストをソートしてやればいいわけです。

sortedのkeyに自作の関数を指定する

ソートにはsorted を使います。そして keyパラメータに自作の関数を指定します。
無名関数を当てているのをよく見ると思いますが、keyに関数を指定すると並び順を設定できます。

今回は、自分の意図した通りに並んでほしいので、自分ルールを定義します。
自分ルール用の関数の意図としては、"ファイルの種類ごとに並んでほしいんだけど、重要なファイルを先頭に持ってきて!" です。

sort_by_my_rule.py
def sort_by_suffix(f):
    keys = [ 'max', 'rfa', 'dwg', 'dxf', 'jpg', 'jpeg', 'png', 'tga', 'psd', 'mb', 'ma', 'fbx', 'obj', 'fmz', 'fzb', 'bak', 'pdf', 'ms', 'txt', 'bat', 'vbs', 'log', 'zip', 'rar', 'xlsx', 'xls', '.swatches']
    values = list(range(0,len(keys)))
    d = dict(zip(keys, values))
    ext = Path(f).suffix[1:]
    if ext in keys:
        return d[ext]*10
    else:
        return 1000

拡張子の辞書を作って、インデックスを返すようにしました。3

比較できるものを返す関数を定義する

正直なところ、はじめ、どんな関数を作ればいいのかよくわからなかったのですが、
要は数字か文字みたいな比較できるものを返せばいいみたいです。

sort_by_my_rule.py
ff = sorted( list(p.glob('*')) , key=sort_by_suffix )

このようにして出力すると

_tree.txt
DFC8638BAA
    DEMO_DFC8638BAA_0001.max
    DEMO_DFC8638BAA_0001.rfa
    FRONT_LOD0_DEMO_DFC8638BAA.dwg
    FRONT_LOD1_DEMO_DFC8638BAA.dwg
    PLAN_LOD0_DEMO_DFC8638BAA.dwg
    PLAN_LOD1_DEMO_DFC8638BAA.dwg
    SIDE_LOD0_DEMO_DFC8638BAA.dwg
    SIDE_LOD1_DEMO_DFC8638BAA.dwg
    DEMO_DFC8638BAA_render.jpg
    control.jpg
    DR03-109-01-DFC79.jpg
    top.jpg
    lonseal_lonrium_5116.png
    SUS_diffuse.png
    SUS_glossiness.png
    SUS_normal.png
    fan_alpha.png
    fan_diffuse.png
    DEMO_logo.tga
    SOURCE_DATA
        DFC86-AA15-AA10_rev1.dwg

整理されて見やすくなりました。

より使いやすくするには、もうひと工夫必要ですが、とりあえず目的は達成しました。


  1. フォルダウィンドウのアドレスバーにPowershellと入力してEnterすれば、その場所で開きます。cdする必要がありません。ちなみにcmdと入力すればコマンドプロンプトが起動します。 

  2. フォルダの中身はBIM、建築CG用のデータで、3Dモデルファイルとテクスチャ画像ファイルです。 

  3. 10倍してあるのは、あとでもっと細かいルールを追加する際、間に入れるため 

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2