シェルスクリプトでデータを文字列の長い行順にソートする方法
はじめに
データを文字列の長い行順(あるいは短い行順)に並び替えする方法について説明します。
もともとのきっかけは、find
コマンドで検出したディレクトリを階層の深い順に削除しないとエラーメッセージが表示される問題を解消したいということでした。
「階層が深いディレクトリ=パスの文字列が長いディレクトリ」をどうやってソートしようかなと考えて当エントリをまとめることにしました。
検証環境
$ uname -moi
x86_64 MacBookPro11,4 Darwin
$ bash -version | head -n 1
GNU bash, バージョン 5.0.11(1)-release (x86_64-apple-darwin18.6.0)
準備
適当にディレクトリを作成して試してみます。
スペースを含んでも正しく動作するかを確認したかったので、ここではあえてスペースを含むディレクトリも作ってみました。
# 適当なディレクトリを作成する
$ mkdir -p aaa/bbb/ccc 'aaa/d ddd/ee'
# treeコマンドでディレクトリ構成を確認してみる
$ tree
.
└── aaa
├── bbb
│ └── ccc
└── d ddd
└── ee
5 directories, 0 files
単純にfind
で出力してみる
まずは単純にfind
でディレクトリのみを出力してみます。
$ find . -type d
.
./aaa
./aaa/bbb
./aaa/bbb/ccc
./aaa/d ddd
./aaa/d ddd/ee
ディレクトリ構造を単純に探索していった結果に見えます。
find
の実行結果を文字列の長い順にソートしてみる
今度は文字列長でソートしてみます。
やり方としては単純です。
- 各行の文字列の先頭にスペース区切りで 文字列長 を付与
- 数値でソート
- 付与した 文字列長 を除去
# (1)を実装
$ find . -type d \
| awk '{ print length, $0 }'
1 .
5 ./aaa
9 ./aaa/bbb
13 ./aaa/bbb/ccc
11 ./aaa/d ddd
14 ./aaa/d ddd/ee
# (1)~(2)を実装
$ find . -type d \
| awk '{ print length, $0 }' \
| sort -nr
14 ./aaa/d ddd/ee
13 ./aaa/bbb/ccc
11 ./aaa/d ddd
9 ./aaa/bbb
5 ./aaa
1 .
# (1)~(3)を実装
$ find . -type d \
| awk '{ print length, $0 }' \
| sort -nr \
| cut -d" " -f2-
./aaa/d ddd/ee
./aaa/bbb/ccc
./aaa/d ddd
./aaa/bbb
./aaa
.
ひとこと
これを組み合わせて、tmp_
というプレフィックスを持つディレクトリのみを削除する場合は以下のようになります。
$ find . -type d -name 'name_*' \
| awk '{ print length, $0 }' \
| sort -nr \
| cut -d" " -f2- \
| while read -r d; do rm -r "$d"; done
ディスカッション
コメント一覧
まだ、コメントがありません