定石を知りスキルを上げる:スマートな紳士のためのシェルスクリプト(5)(2/2 ページ)
前回に引き続き、今回もOS付属のシェルスクリプトを読んでいく。「本当にこれでいいのか?」と思うような読みにくい記述も見つかるが、よく読むとシェルスクリプトならではの流儀を学ぶことができる(編集部)
リダイレクトとパイプ
次の書き方もなかなかおもしろい。ファイル$IFACEDIR/$1の内容を1行ごとに変数lineに読み込ませて処理をするという記述になっている。
while read line; do [ -n "$line" ] && echo "$line" done < "$IFACEDIR/$1"
この処理は、次のように記述することもできる。
cat "$IFACEDIR/$1" | while read line; do [ -n "$line" ] && echo "$line" done
処理速度の観点からいうと、リダイレクトを使った処理の方が処理が高速になる。これは次のような簡単なシェルスクリプトで比較できる。
#!/bin/sh while read line do sleep 10 exit done
#!/bin/sh cat /COPYRIGHT | while read line do sleep 10 exit done
リダイレクトを使う場合、処理はそのシェルの中で完結することになる。リダイレクトのシェルスクリプトを実行しても、そのシェルのみが動作していることを確認できる。
% ps d | grep while | grep -v grep 25687 6 S+ 0:00.00 - /bin/sh ./while-test1.sh %
パイプで接続した場合、シェルはサブシェルを生成し、その中で処理を実施する。パイプは便利な機能だが、このようにサブシェルを生成して処理を実施するため、その分処理は遅くなる。
% ps d | grep while | grep -v grep 25680 6 S+ 0:00.01 - /bin/sh ./while-test2.sh 25682 6 S+ 0:00.00 `-- /bin/sh ./while-test2.sh %
リダイレクトのみで済むようなケースでは、パイプで流し込まずにリダイレクトリで処理した方が高速になるということは覚えておきたい。
IPアドレスとcase
次の書き方はcaseの使い方として珍しいものではないが、指定されている文字列がIPアドレスになっているところが目を引く。
case "$n" in 127.*|0.0.0.0|255.255.255.255|::1) :;; *) newns="$newns${newns:+ }$n";; esac
ネットワーク関係の処理では、このようにIPアドレスをcase分の分岐対象に指定するものがあり、こういった書き方をよく見かける。
文字列の加工とバックスラッシュクォート
sh(ash)では変数展開時に、文字列の先頭または末尾からパターンに一致する文字列を取り除くことができる。#および##が先頭からの削除、%および%%が末尾からの削除となる。#と%が最短一致で、##と%%が最長一致となる。
resolvconf(8)では次のように#が使われている。
iface="${line#\# resolv.conf from *}"
これは、コメントとして「# resolv.conf from 」が使われている部分を削除するという記述になる。シェルスクリプトでは、#はコメントの始まりとして使われるため、変数における#の後に、\#のようにエスケープ表現を使っている点が注目ポイントとなる。
標準入力を変数へ
resolvconf(8)には次の記述も見られる。あまり見かけない書き方だ。
resolv="$(cat)"
これは標準入力を丸ごと変数に代入するという処理になる。対象とするデータサイズが小さいものに限られており、文字列のみで構成されている場合などは、こうした使い方もできる。
Copyright © ITmedia, Inc. All Rights Reserved.