シェルを覚えた経緯を詳し目に書いてみる

perl - the best friend of find(1) 404 Blog Not Foundを見てて、シェルについて書いてみたくなりました。
丁度、Linuxを学ぶための10個の効果的な方法で言及したシェルを覚えた経緯を詳しく書いてみたかったのでだらだらと書いてみる。


前回書いた内容がこちら。
順を追って解説していきます。

シェル覚えた経緯。

  1. 第一段階としてはパイプラインを覚える |
  2. 第二段階はsort や grep など、パイプラインで処理するのに便利なコマンドを覚える。
  3. 第三段階でls | awk '{print $2}' とかやってみて、スペースで区切られた2列目が表示される事に感動してみる。
  4. 第四段階でls | awk '{print "ls "$2}'でコマンドを作ってみてls | awk '{print "ls "$2}'|sh でコマンドをばーっと処理してくれる事に感動してワンライナーを作り出す。
  5. 第五段階でxargs を覚えたり、awk のFSの設定方法とかを覚えたり、`で囲み始めてワンライナーが徐々に上手くなる。
  6. 第六段階でシェルスクリプトを書き出して、for FILES in `ls`でループまわし始めたりしてスクリプトかき始める
  7. なんかいつの間にかシェルうまくなってた? ←イマココ

第一段階としてはパイプラインを覚える |

本当の初期にはlsとかcdとかあるんでしょうが、そこはとりあえずすっ飛ばして、
パイプライン。


オプションやコマンドとか十分にわかんなくても、
色々出来る様になります。*1
cat file | sort | uniq とかやっていた時代が私にもありました。*2

第二段階はsort や grep など、パイプラインで処理するのに便利なコマンドを覚える。

んで、パイプラインを処理していく内に便利なコマンドやそのオプションをどんどん覚えていきました。


もちろん今も勉強中ですが、よく使った物をピックアップ

  1. sort 並び替え sort -u でuniqと同じ意味も持ったりする
  2. uniq ソート済みのデータの重複行をなくす。uniq -c でカウントしたり
  3. grep ファイルの文字列検索。一致する行を出す。
  4. tee ファイルにログを書き出しながら標準出力にもそのまま出してくれる。
  5. tail 文書の末尾を出す。tail -fで追加された物をどんどん出してくれる。
  6. less 結果を上下にスクロール出来る様になる。


たとえば、tail -f logfile | grep " /index.html "とかでindex.htmlのログのみを見たり。
sort textfile | less で、ソートした結果をキーで移動できたりと、
応用範囲は色々広がりました。

第三段階でls | awk '{print $2}' とかやってみて、スペースで区切られた2列目が表示される事に感動してみる。*3

たとえばls -l | awk '{print $3}' とかすると所有者だけ表示できたりして。
ls -l | awk '{print $3}' | sort | uniq -c なんかでそれぞれどのぐらいのファイル持ってるか確認できたりして。


awkでとりあえず print と文字列の結合とsplitだけ覚えてから
ワンライナーの応用範囲広がりました。


必要な部分だけ取り出したり、文字列組み合わせたりと。

第四段階でls | awk '{print "ls "$2}'でコマンドを作ってみてls | awk '{print "ls "$2}'|sh でコマンドをばーっと処理してくれる事に感動してワンライナーを作り出す。

shって、文字列渡すとそれをコマンドで処理してくれるんですよね。
ファイル比較用にfind | awk '{print "diff ./"$1" ../org/"$1"}' | sh とかやったものです。
例によってdiffのオプションでフォルダ比較できたりするのですが。


そういうの知らないけど力技で対応したり。
find | grep "\.svn\/entries" | sed -e "script"
で、特定のファイルだけ文字列置換とかですね。


超強引なやり方ですので、本当ならきちっとオプション付けた方が良い*4んですが、
オプションってかなり多いので、覚えられなかったんですよね。
徐々に覚えて行ってますが、先にこういう強引なやり方でシェルを覚えていきました。

第五段階でxargs を覚えたり、awk のFSの設定方法とかを覚えたり、`で囲み始めてワンライナーが徐々に上手くなる。

というわけで、ps -ef | grep "/usr/bin/ruby /program" | awk '{print "kill "$2}' | shなんて
してたら、別の人がやってる作業はawk でkillなんて作ってないしshにも渡してなかったんですよね。


「どうやってるんですか?」って聞いたところ
xargs 教えて貰いました。
ps -ef | grep "/usr/bin/ruby /program" | awk '{print "kill "$2}' | sh が
ps -ef | grep "/usr/bin/ruby /program" | awk '{print $2}' | xargs kill になります。
おお、すげー。と教えて貰った日からすぐ使い始めました。
あと、awkawk 'BEGIN { FS=","} {print $1}'とすると,で分けてくれる様になることを知ったり
CURRENT_PATH=`pwd`なんかも覚えていきました。

ちょっと話がそれますが、xargsに関してはperl - the best friend of find(1) 404 Blog Not Found内で
いまどきfindとxargsを使う時は-print0と-0を忘れずに

ディレクトリ名に0x20(空白)が入るMac OS X環境でfindに-print0を使わずにxargsで受け取るのはヤバい。かなり危険。一度AppleiTunesのアップデートスクリプトで 0x20デリミタの想定外動作をやらかして、誤消去したことがあったよなぁ。
なので「findには必ず-print0オプションを付けて、xargs -0で受け取る」というのを広く世に広めたい。例えば

find . -type f -name '*~'  -print0 | xargs -0 rm 

という感じ。

と紹介されていました。


2/1からMac使い始めたんですが知りませんでした。
今まで問題起きてなくてよかった。

第六段階でシェルスクリプトを書き出して、for FILES in `ls`でループまわし始めたりしてスクリプトかき始める

ワンライナーを書いてたけどシェルスクリプトはあまり書いてなかった私。
ですが、シェルスクリプトにする必要性がある箇所がいくつかでてきて
for FILES in `ls`で、ファイル毎に処理が出来る事を知り
ニーズもあったのでシェルスクリプトなんかも書き出しました。
if の書き方やforの書き方を覚えて、これまでの知識を利用してシェルを書いてます。

なんかいつの間にかシェルうまくなってた? ←イマココ

大分周りの人に聞かれる様になってきて、結構Linux使えるようになってきたのかなあと。
でも、まだまだ勉強中。
他の人が使ってるテクニックとか見ては勉強してる毎日です。

追記:
調子にのってvim版も書いてみました。
http://d.hatena.ne.jp/zenpou/20080225/1203946622

*1:初心者はむしろこっちから覚えると良いと思ってる。

*2:実はsortだけで同じ事出来たりする。

*3:いまさらですけどlsだとだめですよね。ls -lじゃないと。

*4:ひとつのプログラムで済むのでリソースあまり使わないしバグもあまりない