情報工学科 3年生対象 専門科目 システムプログラミング 第3回、第4回、第5回、第6回 makeコマンド 動的リンクライブラリ シェルスクリプト 情報工学科 篠埜 功 開発支援ツール make • コンパイルを要するソースファイルの数が多くなった場合,手 間がかかる • 1つのヘッダファイルを複数のソースファイルで使用している 場合,ヘッダファイルの修正→ 関連する全てのソースファイ ルの際コンパイル • makeを使用 – ファイルの変更をした場合、その影響を受けるファイルを 再コンパイルする。(不要な再コンパイルをしない) – ファイルの日付情報を用いる。 Makefile • ファイルの作成方法を記述したルール – コロンの前にmakeで作成するファイル名前を書く。 – コロンの右にコロンの左のファイルを作るために必要なファイルをス ペースで区切って並べる – 次の行以下にそのファイルを作るためのコマンドをTABキーを押し たあとに記述。2つ以上のコマンドを書いてもよい。 (例) TAB main : main.o add.o mult.o gcc -o main main.o add.o mult.o main.o : main.c addmult.h gcc -c main.c add.o : add.c gcc -c add.c mult.o : mult.c gcc -c mult.c make • さきほどの例を内容とするMakefileというファイルを作成し、 $ make を実行する。この場合、Makefileの一番上のmainを作成しようとする。 main : main.o add.o mult.o gcc -o main main.o add.o mult.o main.o : main.c addmult.h gcc -c main.c add.o : add.c gcc -c add.c mult.o : mult.c gcc -c mult.c make さきほどの例で、add.cやaddmult.hなど、ソースファイルの 内容を変更し(スペースやコメントを入れるなど)、 $ make を実行して何が起きるか確認せよ。 (参考) touchコマンドを使うと、中身を変えずにファイルの 時刻情報のみ更新できる。 $ touch add.c など。 make $ make add.o などと、コロンの左側のものをmakeの引数に与えると、それ を作成しようとする。 main : main.o add.o mult.o gcc -o main main.o add.o mult.o main.o : main.c addmult.h gcc -c main.c add.o : add.c gcc -c add.c mult.o : mult.c gcc -c mult.c Makefile • コロンの左に書くのはファイル名でなくてもよい。 test1: ls –l test2: ps –ef | grep sasano $ make test1 とするとファイル一覧が表示され、 $ make test2 とするとプロセス一覧からsasanoを含む行を抜き出し たものが表示される。 make clean というターゲットを作っておき、実行コマンドとして不要な ファイルを削除するコマンドを書いておくということがよく行われる。 $ make clean とすると、ソースファイルではないファイルが削除されてディレクト リがきれいになる。 main : main.o add.o mult.o gcc -o main main.o add.o mult.o main.o : main.c addmult.h gcc -c main.c rm に-fオプションは add.o : add.c 強制削除のオプ gcc -c add.c ションであり、存在 しないファイルが引 mult.o : mult.c 数にあたえられても gcc -c mult.c メッセージが出ない。 clean : rm –f main main.o add.o mult.o Makefileの名前について Makefileの名前は”Makefile”でなくてよい。 makeコマンド(GNU make)はdefaultでは”GNUmakefile”, “makefile”, “Makefile”をこの順で探し、最初に見つかった もので実行する。これ以外のものを使いたい場合は-fオプ ションで指定する。たとえばmyMakefileという名前で Makefileを作成したときは、 $ make –f myMakefile のように実行すればよい。 練習問題 前回のlibaddmult.aを作ってからmainを作成する手順を makeコマンドで行えるようにMakefileを作成せよ。 マニュアル表示コマンド man • (例) gcc, ar, makeコマンドについて調べたい $ man gcc $ man ar $ man make • コマンドの処理内容,様々なオプションの解説が書か れている。 • manコマンドについては $ man man で調べる。 共有ライブラリ(shared library) • 動的リンクライブラリ(dynamic link library)とも言う。 • 実行形式ファイルにはライブラリの中身は含まれず、 実行時にリンクされる。 • 実行形式ファイルのサイズの削減 • ライブラリを修正する場合、ライブラリファイルのみ修 正すればよく、リンク作業が不要。 共有ライブラリ作成例 さきほどのadd, mult関数の例で共有ライブラリを作成する。 $ gcc –shared –o libaddmult.so add.c mult.c これでadd, mult関数が共有ライブラリとしてlibaddmult.soに作成さ れる。 $ gcc –L. –o main main.c –laddmult (あるいは $ gcc –o main main.c libaddmult.so と明示的に指定) これでlibaddmult.soが実行時にリンクされるようになる。 $ ./main を実行する前に、 $ setenv LD_LIBRARY_PATH . を実行しておく。(シェルがtcshの場合。シェルがbashの場合は、 $ LD_LIBRARY_PATH=.; export LD_LIBRARY_PATH とする。) add.cを変更してlibaddmult.soを作り直し、mainを実行する と、mainを作成しなおさなくても変更が反映されていることが分かる。 $ ldd main (lddはlist dynamic depencenciesの略) で、mainが動的にリンクするファイル一覧が表示される。 補足 • -lxxx でリンクする際には、libxxx.soが先に検 索される。 (例)/usr/lib/libm.so, /usr/lib/libm.aのように 両方ある場合は/usr/lib/libm.soが(defaultで) 使われる。 レポート課題1 1. 2. 3. 4. 5. 6. 長さnのint型の配列の各要素に1から100までの整数をランダムに作成して 代入する関数randAssignを定義したファイルrandAssign.c 長さnのint型の配列を受け取り、要素を小さい順に並べ替える関数sortを定 義したファイルsort.c randAssign関数のプロトタイプ宣言を記述したファイルrandAssign.h sort関数のプロトタイプ宣言を記述したファイルsort.h 以下の内容のmain関数を記述したmain.c – 長さnの配列を作成し、それをrandAssign関数に渡して整数をランダムに 格納させ、sort関数に渡してソートをさせ、その結果を画面に出力するプ ログラム。長さnの値はmain.cに直接書いてよい。キーボードから入力す るようにしてもよい。 – main関数の先頭部分でrandAssign.h, sort.hを読み込む。 Makefile – 実行形式ファイル(mainとする)をmakeコマンドで作成できるように作成す る。 配列を関数に渡すとき、長さをもう一つの引数として 渡す。 レポートの提出方法 □ 下記のファイルを作成し、提出 • randAssign.c, randAssign.h, sort.c, sort.h, main.c, Makefile, kadai1.txt □ 提出方法 システムプログラミング講義用の課題提出用フォルダ内に あるkadai1というフォルダの中に自分の学籍番号を名前と するフォルダを作成し、その中に上記ファイルを置く。 kadai1.txt内に学籍番号、氏名、日付、および作成したプ ログラムの簡単な説明を記載する。 □ 提出期限 10月27日の講義開始時間まで。締め切り後に提出した場 合、成績への反映を保証しない。 □ アーカイブを作る必要はありません(作ってもいいですが)。 □ 動的リンクにするか静的リンクにするかについても自由。 前回の補足 共有ライブラリを作る時、gccのオプションで-fPICをつけた 方がよい。 (例) $ gcc –fPIC -shared –o libaddmult.so add.c mult.c その他の部分は同じ。 シェルスクリプト • シェルに対する命令をファイルに記述したもの • シェルとは – コマンドインタプリタ。UNIX系OSではシェルはユ ーザプログラムであり、自分でシェルを作成する こともできる。 シェル(/bin/sh)に直接打ち込む例 [sasano@oli004 ~]$ sh sh-2.05b$ A=ls sh-2.05b$ $A <lsの実行結果> sh-2.05b$ シェルスクリプトは、シェル(通常 は/bin/sh)に対する命令列をファ イルに格納したものである。ここ ではファイルに入れずにシェル (/bin/sh)上で直接実行してみる。 (補足) shと打つことによって、shというファイルが環境変数 PATHに入っているディレクトリから検索され、その結果 /bin/shが見つかり、それが実行される。 A=ls などのように、変数名=文字列 の形で、変数を定義できる。=の前後にスペースを入れて はいけない。スペースを入れると、この場合、Aをコマンド 名として解釈しようとしてcommand not foundになる。 変数の値の参照は、$変数名とすればよい。 (参考) /bin/tcshの場合 [sasano@oli004 4kai]$ set A=ls [sasano@oli004 4kai]$ $A <lsの実行結果が表示される> [sasano@oli004 4kai]$ /bin/tcsh では、上記のように、set A=lsの形で、set コマンドを用いてシェル変数を定義する。(ここでは= の前後にスペースがあってもよい。) シェル変数の一覧は $ set で画面に表示される。(shでもsetで一覧表示。) 環境変数 /bin/shや/bin/bashの場合: $ export シェル変数名 のようにすることにより、シェル変数が同一の変数名で環境変数となる。 たとえば、 $ A=test $ export A など。環境変数の一覧は $ printenv で表示される。個々の環境変数の値は $ printenv A のように、環境変数名をprintenvコマンドの引数に与えると表示される。 /bin/tcshの場合: $ setenv A test のように、setenvコマンドを用いる。(=はないことに注意) 環境変数一覧、個々の値の表示については/bin/shと同じ。環境変数の 値も$環境変数名で参照できるが、同じ名前のシェル変数がある場合、 そちらが優先される。 環境変数の例 dateコマンド(日時の表示)を実行すると [sasano@oli004 4kai]$ date 2009年 10月 6日 火曜日 13:45:42 JST のようになるが、 [sasano@oli004 4kai]$ setenv LANG C のようにすると、 [sasano@oli004 4kai]$ date Tue Oct 6 13:47:27 JST 2009 のように英語表示になる。 (/bin/shの場合は、LANG=Cとしてからdateを実行 すればよい) シェル変数の例 PATH, HOME, USER, HOSTNAMEなどのシェル変数が 通常使われている。 $ echo $PATH $ echo $HOME $ echo $USER $ echo $HOSTNAME などで確認できる。 /bin/shでも/bin/tcshでも同じ。 シェルスクリプト • ファイルにシェルに対する命令(スクリプト)を書いた もの。 • 1行目に#!/bin/sh と書く。これによって、/bin/shがス クリプトを実行することになる。 – #!/bin/bash, #!/bin/tcshなど、他のシェルを指定し てもよいが、その場合はスクリプトの書き方は異な る。 • ファイルの属性を、実行を許可するように変更する必 要がある。 $ chmod 755 test.sh などのようにして変更できる。 例1(打ち込んで確認) (1)以下を中身とするtest1.shというファイルを作成 #!/bin/sh ls -l (2)ファイルの属性を変更 $ chmod 755 test1.sh (3)実行 $ ./test1.sh これによって、ls –lが実行される。あるいは、 $ /bin/sh test1.sh でもよい。 (4) カレントディレクトリのファイルリストが表示されることを 確認。 シェル変数の使用(打ち込んで確認) (1)以下を中身とするtest2.shというファイルを作成 #!/bin/sh A=ls B=-l $A $B (2)ファイルの属性を変更 $ chmod 755 test2.sh (3) 実行 $ ./test2.sh (4) カレントディレクトリのファイルリストが表示されるこ とを確認。(例1と同じ) for文(例1)(打ち込んで確認) #!/bin/sh for i in 1 2 4 do echo $i done 1 2 4 と表示されればOK。 echoは引数に与えられた文字列 を表示するコマンド。$iが文字列 に展開されてから表示される。 for文の構文、意味 構文 for variable in wordlists; do commands; done wordlists: 要素をスペースかタブで区切る。 commands: コマンドをセミコロンで区切る。 意味 wordlistsの要素を左から順番に変数variableに代 入し、commandsを実行する。 セミコロンは改行で置き換えてよい。 for文はコマンドであり、コマンドが書けるところには自由に書くこ とができる。例えばfor文の本体部分にfor文を書いてもよい。 for文の例2(打ち込んで確認) #!/bin/sh for D in `date` do echo $D done バッククオート`でコマンドを 囲むと、その部分がコマン ドの実行結果で置き換えら れる。 dateコマンの出力結果には スペースが含まれており、ス ペースで区切られた一つ一 つがDに代入され、echoで1 つずつ表示される。 for文の例3(打ち込んで確認) #!/bin/sh for L in * do echo $L done *はカレントディレクトリの ファイルがスペースで区切 られたものに展開される。 $ echo * で確認できる。 Lにはカレントディレクトリの ファイル名が一つずつ代入さ れ、それがechoで表示され る。 for文の例4(打ち込んで確認) #!/bin/sh for F in * do cp $F $F.bak done Fにはカレントディレクトリの ファイルのファイル名が一つ ずつ代入され、それがcp で.bakつきのファイルにコ ピーされる。 for文の例5(打ち込んで確認) #!/bin/sh for F in *.c do echo $F cp $F $F.bak done 第一回目に書いた シェルスクリプトは、 上記のシェルスクリプ トの最後にexit 0を加 えたもの。 *.cは、カレントディレクトリ において、ファイル名の最 後の部分が.cになっている ファイルのファイル名がス ペースで区切られたものに 展開される。 Fにはカレントディレクトリ の.cで終わるファイル名が一 つずつ代入され、それが echoで表示されたの ち、.bakつきのファイルにコ ピーされる。 構文 if文 if condition; then commands; [elif condition; then commands;]… [else commands;] fi condition: 条件 commands: コマンドをセミコロンで区切る。 [ ] はオプション(なくてもよいという意味)。 conditionの終了statusが0なら真、0以外は偽。 意味 conditionの終了statusが0ならthenパートを実行。 そうでなければelif以下、あるいはelseパートを(もし あれば)実行。 セミコロンは改行で置き換えてよい。 if文はコマンドであり、コマンドが書けるところには自由に書くこと ができる。例えばif文のelseパートにif文を書いてもよい。 終了status コマンドは終了statusを返す。 シェルスクリプトではexit 0 等、exitの右に書く数によって 終了statusを指定する。 Cのプログラムでは、main関数のreturn文あるいはexitシ ステムコールの引数によって終了statusを指定する。 コマンドの終了statusはシェルが受け取り、$?という変数 に保持している。 (例) $ ls aaa $ echo $? もしaaaというファイルがなければlsコマンドの終了status が1になっている。 if文の例1(打ち込んで確認) #!/bin/sh if test $1 -le $2 then echo $1 is less than or equal to $2. else echo $1 is greater than $2. fi testは比較などさまざまな判定を行うコマンド。オ プションによりさまざまな判定が行える。 test arg1 –le arg2 は、arg1がarg2より小さいか どうか判定。 $1はシェルスクリプトの1番目の引数、 $2はシェルスクリプトの2番目の引数を表す。 if文の例2(打ち込んで確認) #!/bin/sh if diff $1 $2 > /dev/null then echo No differences were found between $1 and $2. else echo Some differences were found between $1 and $2. fi diffは2つのファイルの比較を行うコマンド。 終了statusは、同じとき0, 異なるとき1である。 diffコマンドの標準出力への出力は/dev/nullへリダイレクトさ れるので捨てられる。(リダイレクトについて後日解説する) testコマンドについて testコマンドは大小比較などさまざまな判定に使われる。 数値比較、文字列比較、ファイル形式の判定、ファイルの 修正時刻の比較などがある。さらに、条件をand, or, notで 組み合わせることもできる。 testコマンドは非常によく使われるので略記法がある。 test …は [ … ] と略記してよい。 例えば、test $1 –le $2は、[ $1 –le $2 ]と書ける。 [の次の空白と、]の手前の空白は省けないので注意。 if文の例3(打ち込んで確認) #!/bin/sh if [ $1 -le $2 ] then echo $1 is less than or equal to $2. else echo $1 is greater than $2. fi 例1におけるtest $1 –le $2を[ $1 –le $2 ]で置き 換えたもの。 ヒアドキュメント シェルスクリプト内部で、コマンドへのキーボードからの入力を シェルスクリプト内に直接書いておくことができる。 コマンド << str ……… str のように、<<の右に区切り文字列を(自分で決めて)書き、その 次の行から、指定した文字列が最初に現れるまでの部分を、 ファイルからコマンドへ < でリダイレクトしたのと同等の効果が ある。 ヒアドキュメントの例1(打ち込んで確認) #!/bin/sh cat << EOF <html> <body> hello </body> </html> EOF 上記のようにある程度長いメッセージを 出力したい場合、ヒアドキュメントを使うと きれいに書ける。 ヒアドキュメントの例2(打ち込んで確認) #!/bin/sh cat << EOF > sample.c #include <stdio.h> int main (void) { printf ("test\n"); return 0; } EOF gcc -o sample sample.c ./sample これはシェルスクリプト内でCのファイルを作成し、 コンパイルして実行する例である。 レポート課題2 課題2-1, 2-2, 2-3の3つの課題(後述)のシェ ルスクリプトをkadai2-1.sh, kadai2-2.sh, kadai2-3.shというファイル名で作成せよ。 レポートの提出方法 □ 下記のファイルを作成し、提出 • kadai2-1.sh, kadai2-2.sh, kadai2-3.sh, kadai2.txt □ 提出方法 システムプログラミング講義用の課題提出用フォルダ内に あるkadai2というフォルダの中に自分の学籍番号を名前と するフォルダを作成し、その中に上記ファイルを置く。 kadai2.txt内に学籍番号、氏名、日付、および作成したプ ログラムの簡単な説明を記載する。 □ 提出期限 11月17日の講義開始時間まで。締め切り後に提出した場 合、成績への反映を保証しない。 課題2-1 テキストファイルのファイル名をシェルスクリプトの引数とし て受け取り、そのファイルが存在すればファイルの中身を 表示し、存在しない場合には、 ファイル名: No such file exists. と表示して終了するようにせよ。実行方法は、 $ ./kadai2-1.sh test.txt のようにファイル名を引数として与える。この場合、test.txt というファイルが存在すれば中身を表示する(表示はcatコ マンドを使えばよい)。存在しなければ上記のメッセージを 表示する。 ファイルの存在確認は、testコマンドを用いて、 test –f ファイル名 で行うようにせよ。コマンド “test –f ファイル名” の終了statusは、そのファイルが存在して通常 のファイルなら真、そうでなければ偽である。 課題2-2 課題2-1のプログラムに,引数の個数チェックを 行う処理を追加し、ファイル名が引数に与えら れなかった場合、 $ ./kadai2-2.sh Usage:./kadai2-2.sh filename のようにエラーメッセージを表示するようにせよ。 引数の個数は$#という変数に入っており、testコマンドで test $# -eq 0 (あるいは [ $# -eq 0 ]) により、引数が0個かどうかを判定できる。 起動したコマンド名(この場合は./kadai2-2.sh)は$0に 入っているのでそれを使う。 課題2-3 テキストファイルのファイル名とキーワードをキーボードから受 け取り、指定した文字列を含む行を表示するシェルスクリプトを grepコマンドを用いて作成せよ。 (実行例) text.txtのファイルの中にThis is a test. という行があ る場合、 $ ./kadai2-3.sh 赤字の部分はキーボードか Enter filename: test.txt らの入力 Enter keyword: es This is a test. キーボードからの入力はreadコマンドで受け取る。 (例) read x とすると、変数xにキーボードからの入力が入る。 メッセージ表示後に改行しないようにするには echo –n …. のようにすればよい。表示する文字列の最後に空白を入れた い場合、表示する文字列を””で囲めばよい。 補足1 前回紹介したifコマンドはネストしてよい。例えば、elseパート有り のifコマンドをネストして、 if … then … else if … then … else … fi fi のような形で使える。これは外側のifコマンドにおけるelseパート のコマンド(赤字の部分)がifコマンドになっているということである。 補足2 さきほどのifコマンドのネストは if … then … elif … then … else … fi のように書いてもよい。この場合はifコマンドのネストで はなく、1つのifコマンドである。
© Copyright 2024 ExpyDoc