日々良く使っていそうなパイプによる連結。「パイプはモナド!!」とか言いたい方は是非こちらへ。
行数を数えたい
単純に行数を数えたい場合は wc -l で十分です。wc は word count で、-l は line number を教えろという意味です。
$ netstat -tn | wc -l
34
でも何だか味気ないです。exact match でその行がどれくらいあるの? みたいなのが知りたい場合には sort と uniq を併せて使います。
$ netstat -tn | awk '{print $6}' | sort | uniq | wc -l
5
uniq は連続した重複行を 1 行にまとめてくれるので、sort を前にかまします。uniq に -c を付けるとその重複行が何行あったか教えてくれて便利です。
$ netstat -tn | awk '{print $6}' | sort | uniq -c
1
1 CLOSE_WAIT
32 ESTABLISHED
1 TIME_WAIT
1 状態
sort は -n で文字列ではなく数字として sort、-r で逆順で sort してくれるので、最後にくっつけるとものによっては見やすくなります。
$ netstat -tn | awk '{print $6}' | sort | uniq -c | sort -nr
31 ESTABLISHED
1 状態
1 TIME_WAIT
1 CLOSE_WAIT
1
欲しい行だけ抜き出す
grep とか egrep とか使えばいいですね。圧縮展開が面倒だ、というときには zgrep とか zegrep とかもあります。あんまり option 覚えていませんが、良く(?)使うのは
| option | 説明 |
|---|---|
-i |
大文字小文字区別しない |
-v |
マッチする行以外を表示 |
-a |
ascii として grep (制御文字入っちゃってるときとか) |
-h |
複数ファイル指定したとき行頭にファイル名を入れない |
少ないな、覚えてるの。表組する程でもないかもしれない。
行のうち欲しい部分だけ抜き出す
上にも出てるけど手軽なのは awk で $6 とかしてスペースとか区切りの文字を抜き出してしまう方法。若しくは cut で -c で抜き出す column を指定しても良い。
$ sudo cut -c -9 /var/log/messages* | uniq -c | sort -n | tail
9 Mar 29 20
9 Mar 30 02
10 Mar 9 08
10 Mar 18 01
10 Mar 20 01
17 Mar 30 00
27 Mar 12 01
225 Mar 29 19
351 Mar 13 07
9118 Mar 18 23
ちなみに、3/18 の 23:43 は OOM killer が走っていました。
気軽に Perl に手を出す
awk 力が高かったり grep 力が高かったりすると色々できそうですが、私の場合貧弱なので直ぐに Perl に手を出します。
perl は -n で引数で指定されたファイルや標準入力の各行を $_ という変数に入れて各行を処理してくれます。処理内容は -e でしてあげれば ok です。
$ netstat -tn | perl -ne '@F=split(" "); print $F[5]."\n";' | sort | uniq -c
1
2 CLOSE_WAIT
28 ESTABLISHED
1 TIME_WAIT
1 状態
これは awk と同じことをやってるんですが、-a を付けると awk っぽく振る舞ってくれるようになり @F の定義すら必要なくなります。
$ netstat -tn | perl -a -ne 'print $F[5]."\n";' | sort | uniq -c
1
2 CLOSE_WAIT
28 ESTABLISHED
1 TIME_WAIT
1 状態
また、-F で区切り文字も色々変えれます。-F, とかすればお手軽な CSV であれば読めます。で、これでもぉ立派な Perl なので、"Foreign Address" が 443 port のものの "State" だけ出力、というのも簡単にできます。
$ netstat -tn | perl -ane 'print $F[5]."\n" if $F[4] =~ /:443/;' | sort | uniq -c
6 ESTABLISHED
1 TIME_WAIT
正規表現さえ使えてしまうと、例えば URL っぽいものを全部引っこ抜くというのも簡単です。
$ curl -s http://www.google.com/ | perl -ne 'while (s/href="(http[^"]+)"//) { print $1."\n" }' | less
http://www.google.com/imghp?hl=en&tab=wi
http://maps.google.com/maps?hl=en&tab=wl
https://play.google.com/?hl=en&tab=w8
http://www.youtube.com/?tab=w1
http://news.google.com/nwshp?hl=en&tab=wn
https://mail.google.com/mail/?tab=wm
https://drive.google.com/?tab=wo
http://www.google.com/intl/en/options/
http://www.google.com/history/optout?hl=en
https://accounts.google.com/ServiceLogin?hl=en&continue=http://www.google.com/
https://plus.google.com/116899029375914044550
足し算したい
awk を使った場合は END を使うとファイル読み込みの最後の処理を指示できます。ps aux の結果から RSS の合計を得るには
$ ps aux | awk '{s+=$6} END {print s}'
6787580
s が自動的に 0 に初期化されて後は足されていきます。
繰り返す
zsh を全く使いこなしていないので未だに for 文を書いています。bash すら使いこなしていません。
for i in `seq -w 2 3 20`; do echo $i; done
02
05
08
11
14
17
20
これは 2 から 20 まで 3 ずつ増やして 0 詰の等幅で表示しています。echo を wget にしたりすると連番ゲットだぜ的なものになります。
$ for i in `seq -w 2 3 20`; do wget http://www.example.com/$i.png; done
これは Perl で URL っぽいものを引っこ抜き続けるのも同じです。`` で囲まれてる部分がだんだん長くなってくると、残念な気分が増してきます。mysql とか入れないようにしましょう。
再帰的に directory を掘る
未だに ack や ag を使っていない老害です。find と xargs を使っています。zsh があればここにあることは不要なはずです。あんまり参考にせず zsh とか使いこなしましょう。
近頃の find は何も引数つけないと -print と同じでファイルなどの名前を表示してくれます。GNU と FreeBSD とかの違いかもしれません。
find /usr/lib/python2.7 | head -n 5
/usr/lib/python2.7
/usr/lib/python2.7/nntplib.pyc
/usr/lib/python2.7/dbhash.py
/usr/lib/python2.7/inspect.pyc
/usr/lib/python2.7/textwrap.pyc
'-name' すると名前を絞ってくれます。例えば *py にマッチするものだけなら、
find /usr/lib/python2.7 -name '*py'| head -n 5
/usr/lib/python2.7/dbhash.py
/usr/lib/python2.7/_weakrefset.py
/usr/lib/python2.7/commands.py
/usr/lib/python2.7/mailbox.py
/usr/lib/python2.7/os.py
で、xargs で出てきた出力結果ファイルに一斉にコマンドを実行します
$ find /usr/lib/python2.6/site-packages/botocore -name '*py' | xargs egrep 'request\.' | less
/usr/lib/python2.6/site-packages/botocore/operation.py: in a request.
/usr/lib/python2.6/site-packages/botocore/awsrequest.py: """Represents a prepared request.
/usr/lib/python2.6/site-packages/botocore/response.py: # the request.
/usr/lib/python2.6/site-packages/botocore/response.py: if not http_response.request.method == 'HEAD':
/usr/lib/python2.6/site-packages/botocore/retryhandler.py: to send the request.
(snip)
これは、指定したフォルダ以下の py で終わるファイルで request という変数の attribute を参照している部分を探していますね。何したかったんだろう。。。
find と xargs の組み合わせは、ファイル名に space が入ってたりすると悲惨なことになるので find の -print0 と xargs の -0 を組み合わせる必要がありますが、まぁ、ぐぐってみて下さい。
find は -type でファイルタイプが指定できますが大抵 -type f で regular file に限定する程度でしょう。-mtime -3 とかで過去 3 日以内に変更されたファイル、なども選べるので、/var/log で作業するときには少し便利かもしれません。
証明書をゲットしたい
www.google.com のサーバ証明書だけ欲しい場合には以下で google.pem に保存できます。
$ openssl s_client -connect www.google.com:443 < /dev/null | openssl x509 > google.pem
中身にしか興味が無い場合には、さっさと parse しちゃいます。
$ openssl s_client -connect www.google.com:443 < /dev/null | openssl x509 -noout -text | less
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 8151063296760904526 (0x711e64e1d9287b4e)
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=US, O=Google Inc, CN=Google Internet Authority G2
Validity
(snip)
負荷分散されてる場合とか、一遍に調べたい場合には for で回しちゃいましょう。openssl の -servername は、対応してたら使えるといいですね!!
$ for i in `dig +short www.google.com`; do openssl s_client -servername www.google.com -connect $i:443 < /dev/null > $i.pem;done
$ ls
173.194.33.48.pem 173.194.33.49.pem 173.194.33.50.pem 173.194.33.51.pem 173.194.33.52.pem
JSON が返ってくるんですけど
perl でよければ URL っぽいもの引っこ抜く奴で正規表現で頑張れます。あと、json_pp ってコマンドもあって、これ使うと pretty print してくれるので grep とかできますね。
python 使うと json モジュールを呼び出して parse できます。
$ python -m json.tools < cfn.template
まぁ、素直に jq 使え、という話な気がしてきます。