次のページ 前のページ 目次へ

11. 実生活での例

UNIX の核となるアイデアは、単純なコマンドをパイプやリダイレクトにより結 合して、本当に複雑な作業でさえ行なえるようにすることです。以下の例を御覧ください。 最も混みいった問題についてのみ説明しましょう。他のことについては、これまでの 章や man ページを参考にしてみてください。

問題 : ls を使うとファイルの一覧がスクロールして、画面から消えてしまう。

解答

$ ls | less

問題 : 単語のリストを含んだファイルがあります。それを逆順でソートし、印刷したいのですが。

解答

$ cat myfile.txt | sort -r | lpr

問題 : データファイル内に同じデータを含む行が幾つもあります。 それを切り詰める方法はありますか。

解答

$ sort datafile.dat | uniq > newfile.dat

問題 : 「mypaper.txt」か「mypaper.tex」か、それに似た名前のファイ ルがあるのですが、どこにあるのか思い出せません。見つける方法は?

解答

$ find ~ -name "mypaper*" 

説明 : find はディレクトリツリー(この例では、~ 以降)の 全てのファイルを一覧するすごく便利なコマンドです。-name を使いフィ ルターをかけて出力することができます。

問題 : 「entropy」を含んだファイルがディレクトリ中にあります。 SEARCH コマンドのようにそれがどのファイルにあるか探す方法はありますか?

解決方法:はい、このようにします。

$ grep -l 'entropy' *

問題 : どこかに「entropy」を含んだテキストファイルがあると思うんで すが、それがどこのなんていうファイルか知りたい。VMS では search entropy [...]*.*;* を使いましたが、grep ではサブディレクトリ以下を再 帰的に探すことができません。いい考えありますか?

解答

$ find . -exec grep -l "entropy" {} \; 2> /dev/null

説明:find . はカレントディレクトリから始めて、全てのファイル一覧を出力し、 -exec grep -l "entropy" は各ファイルを対象に実行します ({} により表される)。\ はコマンドを終了させます。 当然、この構文が面倒だと感じるでしょうね。

代わりに、次のようなスクリプトファイルを書くと良いでしょう。 (訳注:私は find . -type f |xargs grep 'entropy' のようにしています)


#!/bin/sh
# rgrep: 再帰的な grep
if [ $# != 3 ]
then
  echo "Usage: rgrep --switches 'pattern' 'directory'"
  exit 1
fi
find $3 -name "*" -exec grep $1 $2 {} \; 2> /dev/null

説明: search のような grepfind とを組み合わせれば、 両方の世界で最も使いやすいものになると思います。

問題 : 2 行のヘッダーで始まるデータファイルがあり、各行には不要なスペー スで区切られた n 個のデータがあります。各行の 2 番目と 5 番目のデータが欲 しいのですが、Fortran でプログラムを書いた方がいいでしょうか?

解答 : いいえ、こっちの方が早い。

$ awk 'NL > 2 {print $2, "\t", $5}' datafile.dat > newfile.dat

説明:コマンド awk は実際はプログラム言語で、データファイルの 3 行目 から開始して、各行の 2 番目と 5 番目をタブで区切ってプリントします。 awk を学びなさい --- 多くの時間を節約できますよ。

問題 : FTP サイトからダウンロードした ls-lR.gz の内容を調べた い。サブディレクトリ毎に「計 xxxx 」の行が含まれています。xxxx はディレ クトリ内容を KB 単位のサイズで表したものです。この xxxx の集計を行ないたいのですが。

解答

$ zcat ls-lR.gz | awk ' $1 == "total" { i += $2 } END {print i}'

説明:zcat.gz ファイルの内容を出力し、awk にパイプし ます。awk は man ページに丁寧にのっていますよ ;-)

問題:データファイルの値を計算する Fortran プログラム myprog が あります。数百のファイルを読み込ませて結果を出力したいのですが、データファ イル名をいちいち打つのが面倒です。VMS では長いコマンドファイルを書くと 思いますが、Linux ではどうすればいいのでしょう?

解答: すごく短いスクリプトでできますよ。myprog が常に「 mydata.dat 」を読み、結果を標準出力( stdout )に表示するようにしておいて、次のスクリプト を書きます。


#!/bin/sh
# myprog.sh: 多くの異なるファイルに対して同じコマンドを実行します。
# 使用方法: myprog.sh *.dat
for file in $*  # for all parameters (e.g. *.dat)
do
  # ファイル名を result.dat に追加していきます。
  echo -n "${file}:    " >> results.dat
  # 現在の引数を  mydata.dat にコピーして、myprog を実行します。 
  # そして、出力を results.dat に追加します。
  cp ${file} mydata.dat ; myprog >> results.dat
done

問題 : 私のテキストファイル内の「geology」を全て「geophysics」に置 き換えたいのですが、手作業でしなければならないのでしょうか?

解答:いいえ、このシェルスクリプトを書いてください。


#!/bin/sh
# $* の $1 を $2 に置き換えます。
# 使用方法:replace "old-pattern" "new-pattern" file [file...]
OLD=$1          # スクリプトの最初のパラメータ
NEW=$2          # 2 番目のパラメータ
shift ; shift   # 最初の二つのパラメータを捨てる。次はファイル名です。
for file in $*  # パラメータとして与えられた全てのファイルでループします。
do
#  OLD を NEW に置換して、テンポラリファイルに保存します。
  sed "s/$OLD/$NEW/g" ${file} > ${file}.new
# テンポラリファイルをオリジナルファイル名にリネームします。
  /bin/mv ${file}.new ${file}
done

問題 : 幾つかデータファイルがあって、その長さは判らないんですが、 最後から 1 つ前の行と 2 つ前の行を削除するには 、えーと...手作業ですか?

解答: もちろん、ノー。スクリプトを書いてください。


#!/bin/sh
# prune.sh は n-1番目と n-2 番目の行をファイルから削除します。
# 使用方法: prune.sh file [file...]
for file in $*   # 全てのパラメータでループします。
do
  LINES=`wc -l $file | awk '{print $1}'`  # ファイルの行番号
  LINES=`expr $LINES - 3`                 # LINES = LINES - 3
  head -n $LINES $file > $file.new        # 最初 KINES 行を出力します。
  tail -n 1 $file >> $file.new            # 最終行を加えます。
done

これらの例があなたの興味をそそりますように...


次のページ 前のページ 目次へ