それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

標準入力行を文字長さ順にソートする

PATHを文字の長さ順にソートしたいと思いました。

PATH文字読みにくい。

PATH=/usr/local/share/npm/bin:/Users/takuya/.rbenv/shims:/usr/local/sbin:/Users/takuya/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/opt/X11/bin

: を 改行に置換して表示

takuya@air:~/Desktop$ echo $PATH | gsed 's/:/\n/g' |  sort # gsedはgnu sed 
/Users/takuya/.rbenv/shims
/Users/takuya/bin
/bin
/opt/X11/bin
/sbin
/usr/bin
/usr/local/bin
/usr/local/sbin
/usr/local/share/npm/bin
/usr/sbin

改行に置換しても見にくい

改行に置換してもヤッパリ見にくい。

辞書順(ディレクトリ型)ソートはあまり綺麗じゃない。

takuya@air:~/Desktop$ echo $PATH | perl -pe 's/:/\n/g' | sort -dnr
/usr/sbin
/usr/local/share/npm/bin
/usr/local/sbin
/usr/local/bin
/usr/bin
/sbin
/opt/X11/bin
/bin
/Users/takuya/bin
/Users/takuya/.rbenv/shims

もっと見た目を美しくしたい。

標準入力で受け取った複数行を文字の長さ順にソートした。

sedgnu sed なので、\n を使える前提。

方法1:readを活用。

takuya@takuya@air:~/Desktop$ echo $PATH  | sed s/:/\\n/g | while read f ; do echo ${#f} $f ;done | sort -n
4 /bin
5 /sbin
8 /usr/bin
9 /usr/sbin
12 /opt/X11/bin
14 /usr/local/bin
15 /usr/local/sbin
17 /Users/takuya/bin
24 /usr/local/share/npm/bin
26 /Users/takuya/.rbenv/shims
takuya@air:~/Desktop$ echo $PATH  | sed s/:/\\n/g | while read f ; do echo ${#f} $f ;done | sort -nr
26 /Users/takuya/.rbenv/shims
24 /usr/local/share/npm/bin
17 /Users/takuya/bin
15 /usr/local/sbin
14 /usr/local/bin
12 /opt/X11/bin
9 /usr/sbin
8 /usr/bin
5 /sbin
4 /bin

ソート結果が美しい!!
でもread 面倒だし。

方法2 for 使えばイイじゃん?

for はパイプで渡せないんだわ。

for で複数行を受け取るには
takuya@air:~/Desktop$ echo $PATH  | sed s/:/\\n/g | for i in `cat /dev/stdin/` ; do  echo ${#i} $i; done  | sort -nr
26 /Users/takuya/.rbenv/shims
24 /usr/local/share/npm/bin
17 /Users/takuya/bin
15 /usr/local/sbin
14 /usr/local/bin
12 /opt/X11/bin
9 /usr/sbin
8 /usr/bin
5 /sbin
4 /bin

ぶっちゃけココマデやるならawk でよくね?

 awk '{print length($0),  $0 } ' # 各行が変数$0 に入るので、 lengthで文字長print

awk で 文字長に置換する。

takuya@air:~/Desktop$ echo $PATH  | sed s/:/\\n/g | awk '{print length($0),  $0 } ' | sort -nr
26 /Users/takuya/.rbenv/shims
24 /usr/local/share/npm/bin
17 /Users/takuya/bin
15 /usr/local/sbin
14 /usr/local/bin
12 /opt/X11/bin
9 /usr/sbin
8 /usr/bin
5 /sbin
4 /bin

rubyワンライナーでやるならもっと楽だし。

ruby -pne " $_ " # cat と同じ
結果
takuya@air:~/Desktop$ echo $PATH  | ruby -ne 'puts $_.split(/:/)' | ruby  -lne 'print $_.size," ", $_ ' | sort -nr
26 /Users/takuya/.rbenv/shims
24 /usr/local/share/npm/bin
17 /Users/takuya/bin
15 /usr/local/sbin
14 /usr/local/bin
12 /opt/X11/bin
9 /usr/sbin
8 /usr/bin
5 /sbin
4 /bin

perl 普段使わないから忘れてた。

perl -pe 's/:/\n/g' # 改行が使える
takuya@air:~/Desktop$ echo $PATH | perl -pe 's/:/\n/g' |  awk '{print length($0),  $0 } ' | sort -nr
26 /Users/takuya/.rbenv/shims
24 /usr/local/share/npm/bin
17 /Users/takuya/bin
15 /usr/local/sbin
14 /usr/local/bin
12 /opt/X11/bin
9 /usr/sbin
8 /usr/bin
5 /sbin
4 /bin

いにしえ系sed

 sed 's/:/\ # ココは 純粋にkaigyouを入れる。 ctrl+k 押後、 \を入力、改行して、Ctrl+y
/g' |
伝統文化のsed面倒だし。
takuya@air:~/Desktop$ echo $PATH | sed 's/:/\
/g' | sort -dnr  | awk '{ print length($0), $0}' | sort -nr
26 /Users/takuya/.rbenv/shims
24 /usr/local/share/npm/bin
17 /Users/takuya/bin
15 /usr/local/sbin
14 /usr/local/bin
12 /opt/X11/bin
9 /usr/sbin
8 /usr/bin
5 /sbin
4 /bin

結局改行をどうするかの扱いが面倒でした。

sedsed だけど perl -pe の方が便利だし、GNU sed でやるのが一番きれいだと思った。