2859

チュートリアルシェルスクリプトを用いて処理の自動化を行えば、複数コマンドの実行や大量のデータ処理を容易に行うことが可能です。今回はシェルスクリプトに関するチュートリアル（全2回シリーズ）の第1回目として、シェルスクリプトの基本や、sed と awk に焦点をあてた UNIXコマンドの便利な使い方について近畿大学の和田義孝先生に解説していただきます。なお、チュートリアル記事は1ページ目のみを本誌掲載し、続きは日本計算工学会 HP 上で公開していますので、そちらも併せてご参照ください。

第1回 シェルスクリプトとUNIX コマンドの便利な使い方
和田 義孝
1

自動化やコマンド化できるシェルスクリプト

表1

シェル（shell）とはプログラムを実行するためのユーザと OS を橋渡しするためのコマンド・インタプリタと呼ばれるプログラムのことです。このシェルは UNIXで利用されてきました。近年では、Linux、Mac OS Xや Cygwin とよばれる Linux と同等の環境を Windows で提供するソフトウェアにおいて利用可能です。シェルは多くの機能があり、シェル自体でプログラミングが可能です。つまり、シェルをうまく使うと「複数コマンド実行の自動化」や「新しいコマンドの作成」など、キーボードで入力するコマンドを記録またはそれ以上に活用できます。今回はこのシェルの機能を中心にテキストファイルを処理する sed およびパターン処理言語である awk の利用方法（便利な組み合わせ方）を解説いたします。

2

シェルの種類

シェルには幾つかの種類があります。おおまかに
分 け て2種 類 あ り ま す。1つ は Bourne シ ェ ル の 系 列 とC shell の系列です。本稿では、Bourne shell の系列である bash（Bourne-Again SHell）を題材にします。理由は、Windows（Cygwin）, Mac OS X, Linux の主要な OS で利用できるためです。
すでにターミナルの起動方法がわかる方は次の章へ読み飛ばしてください。まだインストールがされていない方やターミナルの起動方法がわからないかたはこ
こが最初のポイントになります。これから Windows,筆者紹介
わだ よしたか近 畿 大 学 理 工 学 部 機 械 工 学 科 准 教 授。 博 士（工学）。東京大学寄付講座助手、財団法人高度情報科学技術研究機構研究員、諏訪東京理科大学を経て2012年より現職。専門は破壊力学、自動格子生成、非接触全視野ひずみ計測。

Vol.17, No.4 2012

シェルの種類Mac OS X それから Linux においてどのように起動するのかを紹介します。
◇ Windows の 場 合 に は Cygwin を 利 用 Windows は もともとコマンドプロンプト（cmd.exe）というキーボードから入力を受付けてコマンドを実行する機能を持っています。しかし、シェルに比べると機能が劣り同じ事をさせるのは困難です。シェルや sed および awk などのテキスト処理を行うコマンドを Windows 環境に準備する必要があります。そこで、Cygwin を導入します。
Cygwin プロジェクトは Linux と同じ環境を提供するソフトウェア群を公開しています。この環境を使えばMac OS X や Linux への移植は極めて容易になります。
また様々なスクリプトプログラムも環境の差異のみ注意すればそのまま動かすことが可能です。プロジェクトのサイト（http://www.cygwin.com）からインストールを行う setup.exe をダウンロードして実行してください。 詳 し く は 情 報（http://cygwin.com/install.html な ど）を参照してインストールしてください。インストールが完了すると、Cygwin Terminal というアイコンがデスクトップに作られます。これをダブルクリックするとターミナルおよびシェル（bash）が起動します。
続きは Web で
日本計算工学会誌「計算工学（Vol.17, No.4）」HP：
http://www.jsces.org/Issue/Journal/（33）

チュートリアル

シェルスクリプトと UNIX コマンドの便利な使い方 (1)◇ Mac OS X は ターミナルおよびターミナル およびシェルおよび シェル が 含 まれている
bash, sed,awk はすでにインストールが完了している
ので、Macintosh HD > アプリケーション > ユーティリティから、「ターミナル」を起動してください。特に何も設定していなければターミナルの起動と同時に bash が起動されておりプロンプト（bash では$）が表示されます。
◇ Linux は UNIX を 真似て真似 て 開発 された OS、OS 、 ターミナルおよびシェルおよび シェルがシェル が 含 まれている Linux も Mac OS と同様に基本はターミナルで操作する OS なので、例えば、Ubuntu や Feodra では、gnome-terminal が端末という名称でインストールされています。このアプリケーシ
ョンを起動してください。Mac OS X と同様に bash が起動されプロンプトが表示されます。
以下ここまでのまとめを記します。
 Windows では Cygwin のインストールが必要 ターミナル（端末）はキーボード入力や文字情報を出力するためのユーザ・インターフェース 起動するとプロンプト（入力可能のサイン）が表示
 シェルには幾つかの種類があるがここでは bashについて解説
２ 欠 かせないパターンマッチング
かせない パターンマッチング
早速ですがコマンドラインで次のように入力してEnter キーをおしてください。「$」は入力可能を表すプロンプトと呼ばれるサインです。入力しなくてよいです。コマンドラインからの入力を表すためにつけるので注意してください。
「$」のあとの空白は最初からあるので、「$ 」以降を正確に空白も含めて入力してください。
$ mkdir TESTENV$ touch a.txt$ echo *何が表示されたでしょうか。少なくとも TESTENV とa.txt の 2 つは表示されたと思います。最初のコマン
ドは TESTENV という名前のフォルダ（UNIX ではディレクトリと呼ぶ）を作成するコマンドです。さらに touch
コマンドはファイルが存在しない時は空のファイルを作成します。最後の行はなんでしょうか。今作業しているフォルダにあるファイル名全てを表示したようです。別の言い方をすると、シェルにおいて「*」は作業フォルダにあるファイル名全てを表しています。このようにファイル名や文字列をパターンで表現し、削除や追加などの変更を行います。これが自動化のポイントになります。この入力した文字または「文字＋文字」が意味を持つものをメタキャラクタと呼びます。
パターンマッチングに関連するメタキャラクタは「*」「[X]」「?」があります。それぞれ、意味はファイル名で 0 文字以上の任意の文字、[]の中の 1 文字、任意の 1 文字をそれぞれ表します。bash のパターンマッチ
ングを利用するとある程度ファイル名を絞り込むこと計算工学ができます。
$ echo *.txt$ echo [A-Z]*
しかし、複雑な処理を行うためにはこれでは不十分です。さらに複雑なパターンマッチングを行うための正規表現を紹介します。
◇ 正規表現 とは コンピュータでは様々なものが検索の対象になっていますが、その基本は文字列です。
正規表現は、「特定の文字列を表現するのではなく、特定の条件を満たす文字列を表現するための表記方法」といえます。例えば、拡張子がない文字列だけを表示したり、大文字で始まるファイル名やフォルダ名を表示するといったことも次のようにしてできます。幾つかアルファベット大文字で始まるファイルと拡張子のないファイルを作成して確認してください。
$ ¥ls | egrep '^[^.]+$'$ ¥ls | egrep '^[:upper:]'
コマンドの解説をします。ls は作業フォルダにあるファイルやフォルダの一覧を出力します。ls の前についている¥は本当の ls を呼び出す（エイリアス設定をキャンセルする）ためにつけました。そして本題です。
egrep は拡張された正規表現で行単位にマッチングを行うコマンドです。シングルクォートの中が正規表現になります。[:upper:]でアルファベットの大文字1 文字とマッチします。膨大な行数を持つファイルの中からパターンにマッチする文字列があるかどうかを調べることができます。また、|は、ls の出力結果を画面に出力せずに egrep コマンドへ渡してくださいというパイプと呼ばれるシェルの機能です。
UNIX の世界では早くからシェルやコマンドで正規表現が利用されていましたが、表記上の差異が存在します。またサポートされている表現（メタキャラクタ）が異なります。現在では POSIX 標準に正規表現も定められていますがやはりコマンドによっては解釈をさせるためのエスケープキャラクタなどを入力する必要があります。本稿ではまずは、書いてある通りに入力してどのように出力結果が変化するのかを見てもらえればよいかと考えています。表 2 によく使われる正規表現をまとめました。本文を読み進めていく上でこの表を何度も参照して動作をチェックしてみてください。
◇ さっそく 使 ってみよう まずはコマンドラインでファイルがどのように選択されるかを調べてみましょう。そのまえに、重要な約束事を確認します。ここをしっかりと行わないとうまく動かなくなります。ご注意ください。
◇ ファイル の 作成 本稿で示されるシェルプログラ
ムの枠の上に例えば、cfile.sh などのように名前が記されています。これはプログラムを格納するためのファイル名です。中身は単なるテキストファイルなのでテキストエディタで作成してください。拡張子を.sh としてこのファイルがシェルスクリプトである(33-2)

Vol.17, No.4 2012

チュートリアル

シェルスクリプトと UNIX コマンドの便利な使い方 (1)ことを明示するのがよいでしょう。シェルは拡張子では実行の可否を判断しないので拡張子がない場合や、違う場合でも実行可能です。

ェルスクリプトだけを入力してください。
cfile.sh#!/bin/sh¥rm -f *.txt
for n in sample11.txt sample1A.txt sampleA1.txt ¥sampleAA.txt sample_A.txt
dotouch ${n}done

表２ 正規表現で利用される記号（メタキャラクタ）とその表記表記（表記 （ メタ説明キャラクタ））
キャラクタ.
任意の1文字、スペースも含む、シェルの?と同じ?
直前の文字の0回か1回の繰返+直前の文字の1回以上の繰返
括弧内の任意の1文字[XXX ]
例 [ABC] 大文字AかBかCのどれか1文字
括弧内以外の文字[^XXX ]
例 [^A-Z] 大文字アルファベット以外(数字記号含)*直前の文字の0回以上の繰返{n ,m }
直前の文字や正規表現のn 回以上、m 回以下の繰返{n }直前の文字や正規表現のn 回の繰返{n ,}直前の文字や正規表現のn 回以上の繰返
文字列の先頭または行の先頭、[^XXX ]とは違う^
例 ^[0-9]* 数字から始まる行（文字列）
文字列の最後、または行の最後$
例 *Z$ Zで終わる行（文字列）正規表現のpattern をグループ化(pattern )例 (ab|ba)ort abortかbaortと一致
正規表現に使われる記号\（メタキャラクタ）のエスケープ
例 \* 文字*と一致

cat > data.txt << EOSFirst Name,Family Name,Initial,ID #,Year
JOHN,ABC,-,25,2011
ROBERT,DEF,-,35,2000
JOHN,GHI,-,42,1998
end
EOS

プログラム１◇ for による 処理：
処理 ： shell01a.sh の 解説 この簡単なシェルスクリプトは拡張子.txt を持つファイルに対して存在すればそのファイル名を表示します。
1 行目 シェルスクリプトをコマンドとして実行する◇ シェルスクリプト の 実行 実行方法は２通りあります。コマンドラインから実行することには変わりないのですが、次のような２通りがあります。シェルス
クリプトのファイル名を cfile.sh とします。
$ sh cfile.sh# sh の代わりに bash 可または、$ chmod +x cfile.sh # １回だけ実行$ ./cfile.sh# ./ を付けるの２通りです。２番目の例では最初の chmod コマンドは一度だけ実行すればよいです。シェルスクリプトに実行許可を与えるコマンドです。つまり、シェルスクリプト自体を新しいコマンドとして実行させたい時に有効な方法です。何度もコマンドを実行するときに有効です。
◇ 前準備の前準備 の シェルスクリプト の 実行 以下のcfile.sh のファイルを作成し、実行してください。
すると６つのファイルが作成されます。touch コマン
ドについてはオンラインマニュアル（man touch と入力）を参考にしてください。touch コマンドで生成されるファイルは空です。また data.txt はカンマで区切られたデータを含むファイルになります。
３ シェルスクリプトによるシェルスクリプト によるファイルによる ファイルのファイル の 選択
プログラムを自動化するときによく対象となるのはファイルではないでしょうか。ここでは、ファイル名を取得して変更することによりその機能や方法を例示します。これから説明するために行番号を与えます。
しかし、入力する際はプログラム１のように行番号を入力する必要はありません。あくまでも黒枠の中のシ計算工学

cfile.sh

ために必要な記述です。chmod コマンドで実行パーミションを与えてコマンドとして利用する場合には必要です。シェルは最初の行を読み取りどのプログラムで2 行目以降を実行するのかを判断します。/bin/sh はシェルのプログラムがファイルシステムのどの場所にあるのかを示しています。より知るには UNIX のファイルやディレクトリの指定方法が参考になります。
2 行目 シェルで繰返し処理を行うための基本的な構文を図 1 に示します。 name は変数名です。変数の参照は${ name }のように$とカッコがつきます。word は数字、文字列、パターンマッチングなども利用できます。このスクリプトでは*.txt となっているのでいま作業しているフォルダにある拡張子が.txt であるす
べてのファイルが対象となります。最後に、 list です。ここは実行されるコマンドが列挙されます。実際はあまり意識しなくてもよいのですが、bash が内蔵しているコマンドなのかそれとも OS にあるコマンドなのかの区別は自ら調べないとわかりません。if は bash
で呼び出される制御構文の１つですちょっと変わっているのが 5 行目にある fi です。単に if の終わりなので fi となっているということです。シェルではリーバースワードと呼ばれ構文の終わりを宣言する特別な意味を持ちます。
3 行目 この if 文は変数${name}に格納されている文字列と同じファイル（フォルダでもよい）が存在すれば画面に表示（4 行目の echo）し、そうでなければ何もしないという判断をしています。-e は条件を表します。その他の条件判断の例を表２に示します。ところ
で、プログラミング経験のある方は if( )then という構文は納得できる記述かと思います。なぜ、[ -f${name} ]のようにカッコがさらについているのかについて説明します。実は”[“が bash に内蔵されて(33-3)

Vol.17, No.4 2012

チュートリアル

シェルスクリプトと UNIX コマンドの便利な使い方 (1)いるコマンドなのです。これは test というコマンドの別表記です。なるべく短く読みやすく記述したいために、test –f ${name}の代わりということです。
それでは、カッコで閉じなくてもよいのではないのかと思うかもしれませんが、カッコで記述した場合は対応するカッコで閉じて記述してください。本稿ではtest ではなくカッコで統一します。
4 行目 echo は変数の内容を出力します。
5 行目 if 文の終わりを宣言します。
6 行目 for 文のループを終えることを宣言します。

表２

説明-a file
file が存在すれば真 -e でも同じ-f file
file が存在し通常ファイルであれば真-d file
file が存在しディレクトリ(フォルダ)であれば真-r file
file が存在し読み込み可能であれば真-s file
file が存在しサイズが0より大きければ真-w file
file が存在し書き込み可能であれば真-x file
file が存在し実行可能であれば真str1 == str2 文字列の比較 str1 とstr2 が等しければ真arg1 -eq arg2 数値の比較 arg1 とarg2 が等しければ真arg1 -ne arg2 数値の比較 arg1 と arg2 が異なれば真arg1 -lt arg2 数値の比較 arg1 がarg2 より小さければ真数値の比較 arg1 がarg2 より小さいか等しければarg1 -le arg2
真arg1 -gt arg2 数値の比較 arg1 がarg2 より大きければ真数値の比較 arg1 がarg2 より大きいか等しければarg1 -ge arg2
真shell01a.sh
1 #!/bin/sh2 for name in *.txt ; do3if( [ -f ${name} ] ) then4echo ${name}
5fi
6 doneプログラム２

test コマンドの条件表記

条件表記

shell02a.sh
1 #!/bin/sh
2 for name in *.txx ; doecho ${name}34 doneshell01a.sh

プログラム３for name in [word ... ] ; do

$ sh shell02a.sh
*.txx

list
done

図３
図１

list
elif list ; thenlist
elselistfibash の if 文

以上のようにファイルをある程度絞り込んでファイルがあるかどうかを調べる方法を紹介しました。
◇ 期待通りの
期待通 りの 動作をしない
動作 をしない例
をしない 例 ： shell02a.sh の 解説 shell01a.sh などの例で次のように思った方もいたかもしれません。
「いまいるフォルダにあるファイルを表示するのであればファイルがあるかどうかのチェックは不要では？」確かにそのようですが、shell02a.sh を入力して実行してください。先ほどと違う点はわざと拡張子(.txtを .txx)を間違えます。そして、ファイルの存在チェックを行いません。期待したいのは、何も表示しないという状態です。理由は、存在しないファイルを指定しているからです。出力は図３に示します。残念ながらシェルは「*.txx」をそのまま出力しました。for 文ではパターンマッチングに失敗するとそのままメタキャラクタも含めて出力します。これがファイルの存在をチェックする必然性です。
計算工学

shell02a.sh の実行結果

bash の for 文

if list ; then

図２

shell02a.sh

４ ． Excel を 使 わない 行 と 列 の 編集 ～ awk と sed～～◇ sed とその使とその 使 い 方 の 基本 ～ 行 に 対 する処理する 処理 ～sed と stream editor とよばれ、行頭から順番に文字や文字列を正規表現によりパターンを記述して置換や変換するためのテキストエディタの１つです。普通のエディタは画面に文字列を表示するのが普通ですからちょっと戸惑う方もいるかも知れません。しかし、世にあるデータは通常整然と並んでないと使い物になりません。一番わかり易いのが Excel に代表されるような表で表されるデータです。膨大なデータになるといくら Excel を使っても 1 つずつ確認まではしないと思います。そこで、効率良く処理するストリームエディタの出番です。この sed は様々な処理ができますが、1行単位で処理を行うことがポイントになります。
早速サンプルを見てみましょう。入力データは図４の内容になりますシェルスクリプト cfile.sh により作られたデータです。ファイル名は data.txt です。
先頭行はデータのタイトルを表し、各データは「,」で区切られています。また、文字も空白もない（改行だけの）行が２行目行にあります。
それでは shell03.sh を実行して sed の働きを確認しましょう。そのまま実行する各 sed コマンドの実行がそのまま続けて出力されてしまいます。echo で区切り（ここでは=を 20 文字）を表示入れても良いです。
記述を短くするために e を新しいコマンドとして定義します。そして、解説のために行番号を付けます。パイプ|と cat コマンドを使うと行番号を出力結果につけることが簡単にできます。図５のプロンプトのよう(33-4)

Vol.17, No.4 2012

チュートリアル

シェルスクリプトと UNIX コマンドの便利な使い方 (1)に入力してください。

ります。置換の書式は次のとおりです。実行結果は 27から 32 行目になります。

First Name,Family Name,Initial,ID #,Yearm, n s/ pattern1/ pattern2/gm, n は省略可能です。pattern1 を pattern2 に置き換えます。g は行の中にあるすべての pattern1 を対JOHN,ABC,-,25,2011
ROBERT,DEF,-,35,2000
JOHN,GHI,-,42,1998
end
図４象とするオプションです。g を省略すると行の中にある最初の patten1 のみが置換されます。

入力データ:data.txt$ sh shell03.sh | cat -n
12 JOHN,ABC,-,25,2011
3 ROBERT,DEF,-,35,2000
4 JOHN,GHI,-,42,1998
5 end
6 ====================
7
8 JOHN,ABC,-,25,2011
9 ROBERT,DEF,-,35,2000
10 JOHN,GHI,-,42,1998
11 endshell03.sh
123
4
56
78
91011#!/bin/shalias e='echo ===================='# eに=以降の命令を実行させる別名を設定
sed -n '2,$p' data.txt ; e # 2行から最終行まで表示
sed -n '/^$/,/^end/p' data.txt ; e# 空白行から先頭にendを含む行まで表示
sed '1,4d'data.txt ; e # 1行から4行まで削除
sed '$d'data.txt ; e # 最終行を削除
sed '1,/^$/d' data.txt ; e # 1行から空白行まで削除
sed 's/JOHN/GEORGE/g' data.txt# JOHNをGEORGEに置換プログラム４... （省略）...

shell03.sh

それでは、shell03.sh の解説をいたします。
1 行目 他の例と同じです。シェルがこのファイルをどのプログラムに実行させるのかを明示して記述します。
この場合はシェルがシェルを起動することになります。
2 行目 文字 e を echo 以下の文字列の別名として設ます。ここでは、正規表現が使われています。^は行の先頭、$は行の末尾つまり、文字も空白もない空の行から、先頭に end と文字列がある業までを指定しています。実行結果は 7 から 11 行目になります。
7 行目 d は削除を意味します。ここでは-n は不要です。実行結果は 13, 14 行目になります。
8 行目 sed のメタキャラクタ$は最終行を表します。
したがって、最終行以外を表示します。実行結果は 16から 20 行目になります。
9 行目 1 行目から空白行まで、この例では、1,2 行が削除されます。実行結果は 22 から 25 行目になります。
10 行目 すべての行の JOHN を GEORGE に置換します。sの前に行の指定をすれば特定の部分だけ置換対象にな
計算工学====================First Name,Family Name,Initial,ID #,Year

図５shell03.sh のコマンドの入力と実行結果

GEORGE,ABC,-,25,2011
ROBERT,DEF,-,35,2000
GEORGE,GHI,-,42,1998
end

shell04.sh

定します。これ以降「e」ひと文字は% echo ====================を実行することになります。入力を減らす便利な機能です。他のシェルにも同様の機能があります。
4 行目 sed のコマンドは必ずシングルクォート「'」で囲んでください。2,$は行の指定をしています。2行目から$(最終行)までという意味です。p はストリームを表示するという意味を持ちます。つまり、2 行目以降を表示せよという一部を抜き出す処理をします。
このとき sed のオプション-n が重要な役割をします。
試しに-n を付けずにシェルスクリプトを実行してください。実行結果は 1 から 5 行目になります。
5 行目 n, m という表記は文字列の出現でも指定でき

2627282930
31
32

1 #!/bin/sh
2 for name in *.txt ; do3echo 'Source full name:' ${name}4mn=`echo ${name} | ¥5sed "s/¥([^.]¥+¥)¥(.[^.]¥+¥)$/¥1/"`6nn=`echo ${name} | ¥7sed "s/¥([^.]¥+¥)¥(.[^.]¥+¥)$/¥2/"`8echo 'Extracted file name:' ${mn}9echo 'Extracted extension:' ${nn}10echo11 doneプログラム５

shel0l4.sh

次の例では sed を使って拡張子とそれ以外の文字列を分けることを行います。拡張子を変更したり元のファイル名に連番をつけたりすることができるようになるので応用が効くシェルスクリプトと sed の利用法です。注意ですが、ファイル名に複数のピリオドがある
意図通り動作しません。ここではポイントとなる 5 行目の正規表現を見てみましょう。以下に順を追って説明します。
 sed で文字列の置換を行なう（s/ pat1/ pat2 /の形）
 pat1 は 2 つの正規表現のグループで構成
第一グループ¥([^.]¥+¥)ピリオド以外の文字

第二グループ¥(.[^.]¥+¥)ピリオドに続くピリオド以外の文字

第二グループは行の最後($)にある条件を追(33-5)

Vol.17, No.4 2012

チュートリアル

シェルスクリプトと UNIX コマンドの便利な使い方 (1)加pat2 は最初のマッチしたグループを参照する¥1でマッチした文字列に置き換え(前方参照と呼ぶ)

shell05.sh
123456789101112131415^は否定を表すので、[^.]でピリオド以外の文字を表します。文字も記号も含みます。それが、+(sed では\+で正規表現であることを明示します。これが多少分かりにくい原因)を用いてピリオド以外の文字の 1 回以上の繰返しを表します。つまり拡張子を区切るピリオドより前の文字全てにマッチするパターンになります。

#!/bin/shalias e='echo ===================='## 1,2,4列を表示
awk -F , '$1=="JOHN" {print $1,$2,"("$4")"}' data.txt; e## 5列が2001以上のとき1,2,5列を表示
awk -F , '$5>=2001 {print $1,$2,"("$5")"}' data.txt; e## JOHNがある行数を数え表示
awk -F , '/JOHN/ { sum++ } ¥END{ printf "Num. of JOHNs =%d¥n",sum }' data.txt; e## 読み込み行数をつけて、1,2,5列を表示
awk -F , '{print NR,$1,$2,"("$5")"}' data.txt; e## sedで1,2行を削除、4列目の平均を計算
sed -n '3,5p' data.txt | ¥awk -F , '{sum+=$4; print sum} ¥END{ printf "average=%f¥n",sum/NR }'プログラム６shell05.shsample .txt
4 行目 「–F ,」はデータを区切る文字の指定になりまsample¥([^.]¥+¥).txt¥(.[^.]¥+¥)¥(…¥)で前方参照する
グループ明示最初のグループなので前方参照 ¥1¥(…¥)で前方参照する
グループ明示
2番目のグループなので前方参照 ¥2

図６す。もし空白やタブを区切りとしたい場合は-F による指定は省略できます。条件(1 列目が JOHN のとき)を満足した時に 1,2 と 4 列目を表示します。特に if などの表記は必要ありません。
6 行目 4 行目の例と同じですが、5 行目が 2001 以上の時に表示します。
8-9 行目 出現した文字列がいくつの行にわたってあプログラム６の正規表現

前方参照とは、前にマッチした正規表現を参照することを言います。マッチした文字列を再度使いたい場合がよくあります。こういった時にはマッチさせる正規表現を( )でグループ化し（sed ではエスケープキャラクタを使って\( \)とする）それらの参照が便利に利用できます。グループは２つあり拡張子より前の部分と、ピリオドを含んだ拡張子の部分の２つです。同じ正規表現でパターンマッチングを行いますが、置換部分が５行目で\1 と７行目で\2 になっているのは図６のように抜き出したい部分が異なるからです。以上の使い方を知っているだけで相当複雑な処理が可能です。
さて、次にシェルの機能について補足です。4 行目
では、変数 mn に代入しますがバッククォートで囲まれた内部は通常のコマンドが並んでいます。これは、シェルの内部でシェルを実行し、その結果を変数に代入するために用意されたメタキャラクタです。この場合は echo と sed の処理の結果を変数 mn に代入せよという意味があります。コマンドの出力を変数に代入した
い時はこういった書き方が使え、外部のプログラムをどんどん使って良い記述方法が提供されています。
`...`と同じで別の記述方法は$( commands)です。全
く同じ働きをします。
○awk とその使い方の基本 ～行と列に対する処理～
awk はかなり強力なストリームエディタです。sedができることは大抵できます。しかし、記述がより多くなるという欠点があります。これまで行なってきたことは機能や範囲を限定することにより簡単な記述ができるように工夫されています。awk は他のプログラ
ミング言語と同じように if 文、for 文それから数学関数の sin, cos なども用意されています。Excel で計算できる基本的な処理は少ない記述でこなせる能力があります。例題を通して基本的な使い方とその結果を見てみましょう。
計算工学るのかを数えます。/regexp/はでは正規表現が利用できます。9 行目に見慣れない END { list }の形が出てきました。これは最後に 1 回だけ処理する内容を記述します。逆に、BEGIN { list }というのもあります。
これはデータを読み込む前に 1 回だけ処理する内容を記述します。数をかぞえる、和を求めるなどの処理には必須の表現です覚えておいてください。
11 行目 大文字のの単語には意味があるものがあります。NR は現在処理している行数です。ここでは元のファイルの行数を表示しています。NF は現在処理している列(awk ではフィールドと呼ぶ)数を表します。FS は-F オプションで指定した列の区切り記号です。既定値
は空白とタブです。
13-15 行目 awk や sed はこのように組み合わせて意味のある部分だけを表示することも可能です。今回は平均を調べたいので入力行がデータ数と同じに sed で加工し、そのあとに awk で和と平均の計算を行いました。
５ ファイル 名 の 取得と取得 と 変更
最後の例をプログラム８に示します。作業しているフォルダにある.txt の拡張子を持つファイルの先頭の文字だけを大文字に変換し、５桁の連番を与えたファイル名に変更するシェルスクリプトです。実行結果を図７に示します。
shell06.sh を見てみましょう。
3 行目 シェルスクリプト内部でシェルスクリプトを実行しています。ここでは、余計なエラーメッセージを抑制するためにファイルストリームの指定をしてcfile.sh が出力する全てのメッセージを/dev/null に出力して廃棄するよう指定します。これは UNIX 流の方法です。/dev/null の代わりにファイルを指定すると指定したファイルに書き込まれます。
4 行目 ls は作業しているフォルダのファイル一覧を出力します。引数に*.txt を与えることにより拡張し(33-6)

Vol.17, No.4 2012

チュートリアル

シェルスクリプトと UNIX コマンドの便利な使い方 (1)が.txt のファイルのみを出力します。ls の前にある\は別名でないコマンドの ls を使うことを指示します。
5 行目 変数 counter に 0 を代入します。この変数がファイルに連番を付けるために使われます。
6 行目 for 文によるループの宣言です。拡張子.txt を対象とするため*.txt とパターンを記述します。
7 行目 シェルは主に文字を対象として動作します。数値計算を行わせるために let コマンドで数値計算を行いますという宣言をして++演算子で counter に 1 を足します。
8-9 行目 プログラム 6 の前方参照の例と同じですが、若干異なります。参照されるグループは全部で３つあります。\1 は、ファイル名の先頭１文字、\2 はファイ
ル名の 2 文字目以降から最後のピリオド前まで、\3 はピリオドから拡張子全体を表します。sample.txt が対象ファイル名とすると、\1 が s、\2 が ample、\3 が.txtを表すようなパターンです。そして、\U...\E で囲まれたパターンを大文字にせよという命令になります。
ここでは\1 に対して適用されるので、sample.txt は、Sample と変換され、変数 bnam に代入されます。
10-11 行目 ピリオドと拡張子が変数 exte に代入されす。なお、今回の原稿執筆でも bash, sed, awk, egrepのオンラインマニュアルを何度も参考にしました。使い方は簡単です。
% man commandです。
「スペース」キーでページ送り,「b」キーでページ戻り、「q」で終了です。「/」の後に探したい文字列を入力し ENTER で検索できます。是非、オンラインマニュアルも参考にしてください。次回は、ファイルないのデータの並び替えやグラフの大量生成など GUI では操作が困難な場合の処理についてより実践的に解説いたします。

ます。
12 行目 分解し変換されたファイル名に連番をつけます。bash には C 言語と同様なフォーマットを受け付ける printf というコマンドがあります。これを利用して出力を整えるのが簡単です。結果を変数 nstr に代入します。
13-15 行目 分解されたファイル名の確認のため画面に出力します。e により区切り記号も表示します。
16 行目 mv コマンドはファイルを移動または名前を変更するコマンドです。mv src dest の形式です。この
例では${name}のファイル名を${nstr}の新しいファイル名に変更します。
shell06.sh
123456789101112131415161718#!/bin/sh
alias e='echo ===================='
sh cfile.sh >/dev/null 2>&1
¥ls *.txt
counter=0
for name in *.txt ; dolet ++counter
bnam=`echo ${name} | ¥sed "s/¥([^.]¥)¥([^.]¥+¥)¥(.[^.]¥+¥)$/¥U¥1¥E¥2/"`exte=`echo ${name} | ¥sed "s/¥([^.]¥+¥)¥(.[^.]¥+¥)$/¥2/"`
nstr=`printf "%s_%05d%s" ${bnam} ${counter} ${exte}`
echo 'Source file name:' ${name}echo 'Modified file name :' ${nstr}
emv ${name} ${nstr}
done¥ls *.txt

プログラム７shell06.sh

６ まとめ
詳細な解説は紙面の都合で出来ませんでしたが、まずはここに示した例を元に、理解できる範囲で改変して試してください。試行錯誤し繰り返し試すことが正規表現やシェルスクリプトを理解するためには必要で
計算工学(33-7)

Vol.17, No.4 2012