新しいシステムを作るときに既存システムを参考にするけど古すぎてドキュメントがない、既存システムを他サーバに移設するためにディレクトリ情報を取得したい、とりあえずディレクトリ構造がわからないので調べなくてはならない。あるいはディレクトリ構造だけバックアップしたい。そんな需要は滅多に無いのですが遭遇してしまったのでメモしておきます。
3つほど取得方法を考えました。
というのもディレクトリ以外にも通常ファイルが10万以上あり、速度面でものすごく時間がかかったためです。
それぞれ Solaris、Linuxで検証してみました。
lsコマンド
# Solaris
ls -R [target_dirs] | sed -n -e 's/:$//p'
# Linux
/bin/ls -fR [target_dirs] | sed -n -e 's/:$//p'
速度を上げるためLinuxでは、fオプションでソートを無効にしています。Solarisは再帰的な取得の際にfオプションを指定できなかったので遅いです。
/bin/ls としているのはaliasでカラー表示するオプションが指定されているケースがあるので速度面で余計な事をさせない為です。
シンボリックリンク先にディレクトリがある場合も考慮したコマンドは下記に通りになります。
# Solaris
ls -RL [target_dirs] | sed -n -e 's/:$//p'
# Linux
/bin/ls -fRL [target_dirs] | sed -n -e 's/:$//p'
ただし、出力結果からどれがシンボリックリンクなのか判別することはできません。
findコマンド
# Solaris
find [target_dirs] -type d
# Linux
find [target_dirs] -type d
findコマンドはソートしない動きだったはずです。
シンボリックリンク先にディレクトリがある場合も考慮したコマンドは下記に通りになります。
# Solaris
find [target_dirs] -type d
find [target_dirs] -type l
// find コマンドのバージョンによっては-type d,lという書き方ができるようです
# Linux
find [target_dirs] -xtype d
Solarisはxtypeオプションが無いので分けて実行することで取得します。キャッシュがあるとはいえ2回実行するので遅いです。
xtypeオプションを使った結果はシンボリックリンクの判別は可能です。
と、書いたのですが別の環境で試すと区別なく表示されました。find [target_dirs] -xtype d -exec ls -dF {} \;
で区別できると思います。上記のコマンドもこの方法でできるでしょう?
treeコマンド
# Solaris
N/A
# Linux
tree -dfiUn --noreport [target_dirs] | sed -e '/->/d'
treeコマンドはSolarisには標準インストールされません。Linuxでもディストリビューションによっては標準でインストールされていないかもしれません。
デフォルトでシンボリックリンク先の情報まで出てしまいます。抑制するオプションはわかりませんでした。なのでsedコマンドでフィルタリングしています。
シンボリックリンク先にディレクトリがある場合も考慮したコマンドは下記に通りになります。
# Solaris
N/A
# Linux
tree -dfiUn --noreport [target_dirs]
デフォルトの結果からシンボリックリンクの判別は可能です。
eza コマンド
旧exa コマンドです。lsコマンドのような機能を提供しています。
exaがEOLとなったのでフォークされたものがezaです。以前と同じオプションが使用できるようです。
Rustで実装されており、かなり早いとの事でしたので試してみました。
# Linux
eza -1RD --color=never --absolute=on [target_dirs] | grep ^\/
オプションの最初の文字は数字の1です。
やはりわかりにくい為なのか、同じ意味の --oneline
というオプションもあります。
出力が多いのでgrepで必要な情報のみフィルタリングしています。
シンボリックリンク先にディレクトリがある場合も考慮したコマンドは下記に通りになります。
シンボリックリンクはわかりやすく表示されます。
# Linux
eza -1RD --color=never --absolute=on --show-symlinks [target_dirs] | grep ^\/
fd コマンド
同じくRust製コマンドのfdコマンドです。findコマンドの代替を狙っているようです。
全体としてfindと似た機能ですが、ターゲットを指定できないので、cdコマンドでターゲットディレクトリに移動してから実行する必要があります。
# Linux
cd [target_dirs]
fd -a -c never -t d
速度面を考えて、カラー表示を抑制しましたがそれほど変化がないかもしれません。
また、絶対パスで出力するようにしていますが好みで外して構わないと思います。
シンボリックリンク先にディレクトリがある場合も考慮したコマンドは下記に通りになります。
一見分かりづらいですが、シンボリックリンクの場合は、最後に/が付かきません。また、リンク先の情報は表示されません。
# Linux
cd [target_dirs]
fd -a -c never -t d -t l
速度面について
試したSolaris環境上では違いはそれほどありませんでした。
Linux上では、lsコマンド == fdコマンド <<<<< find コマンド < ezaコマンド < treeコマンドの順で短かったです。
フィルタリング処理をパイプで並列処理できているのが効いているのかもしれません。find コマンドとtreeコマンドはそれ程差はありませんでした。
あとから追加検証したexaコマンドとfdコマンドはRust製だけあって早かったです。fdコマンドはls コマンドとほぼ同じぐらいでした。exaコマンドは出力が多いせいなのかあまり早くありませんでした。
まとめ
シンボリックリンクの情報を気にする場合はfind コマンドとtreeコマンドになるでしょう(そもそも調査目的なので)。
Linuxであればfdコマンドが良いでしょう。十分高速なのでディレクトリとシンボリックリンクは2回に分けて実行しても良いかもしれません。
両方の環境で使えるのはfind コマンドなので汎用性があります(しかしオプションは共通ではない)。
上記コマンドは単純にディレクトリ情報を表示する場合も使えますが、リダイレクトでテキストファイルに落とすなど今後の作業の元ネタとして保存しておくことが良いでしょう。
追記
今回の話、全然再帰的な話ではなかったです。こちらを書きながら並行でこちらも書いていたのでタイトルを間違えました。でも、ls -RのRはrecursiveという意味だし、きっとコマンド内部ではサブディレクトリ全てを取得する為に再帰的な処理が行われているのでしょう。プログラムの再帰的な話はこちらをどうぞ。Rustもかなり早いです。