2010年06月18日
情報科学類 コンピュータリテラシ
                                       筑波大学 システム情報工学研究科 
                                       コンピュータサイエンス専攻, 電子・情報工学系
                                       新城 靖
                                       <yas@is.tsukuba.ac.jp>
このページは、次の URL にあります。
	http://www.coins.tsukuba.ac.jp/~yas/coins/literacy-2010/2010-06-18
あるいは、次のページから手繰っていくこともできます。
	http://www.coins.tsukuba.ac.jp/~yas/
	http://www.cs.tsukuba.ac.jp/~yas/
bash (Bourne-Again SHell) は、sh (Bourne Shell)の機能を強化したもの。 シェル・スクリプトを書く時には、多くのシステムで備わっている /bin/sh を 使うことも多い。(/bin/sh はあるが /bin/bash がないシステムもある。)
$ ls ~/Desktop | nkf -e 
(デスクトップにあるファイルの一覧の表示。
漢字を含む名前のファイルも、nkf -e の働きで表示される。)
$ 
echo コマンド、history コマンド、あるいは、コピー&ペースト機能を用いて
端末から打ち込んだものを結果をファイルに保存する。以下の例では、echo コ
マンドを使ってファイルを作成している。
$ ls ~/Desktop | nkf -e  
(^p で1行もどす。^a で、行頭に移動して 「echo '」と打ち、^e して
「' > ls-desktop」 と打つ)
$ echo 'ls ~/Desktop | nkf -e' >  ls-desktop  
$ cat ls-desktop  
ls ~/Desktop | nkf -e
$ ls -l ls-desktop  
-rw-r--r--  1 yas  prof  22  6 17 11:59 ls-desktop
$ 
不要な部分をエディタで削除すれば、シェル・スクリプトの完成である。この
例では不要な部分がないので、シェル・スクリプト ls-desktop は完成してい
る。完成したシェル・スクリプトを実行するには、次のようにbash コマンドの
引数としてファイル名を指定すればよい。
$ bash ls-desktop 
(デスクトップの表示)
$ 
bash で動くものは、sh でも動くことが多い。
$ sh ls-desktop 
(デスクトップの表示)
$ 
bash 」と打つのは煩わ
しいことがある。その場合は、次のようにする。
1行目にテキスト・エディタで #!/bin/bash と書き加える。
$ emacs ls-desktop 
(1行目に「#!/bin/bash 
」と書き加える。)
$ cat ls-desktop 
#!/bin/bash
ls ~/Desktop | nkf -e
$ 
chmod +x で実行可能属性を付ける
$ ls -l ls-desktop 
-rw-r--r--  1 yas  prof  34  6 17 12:09 ls-desktop
$ chmod +x ls-desktop 
$ ls -l ls-desktop 
-rwxr-xr-x  1 yas  prof  34  6 17 12:09 ls-desktop
$ 
ファイル名を指定すると、実行することができる。ファイル名としては、明示
的に相対パス名であることを示すために先頭に「./」を付けるか、ホー
ムディレクトリにあるこを示すために「~/」を付ける(ホーム・ディレ
クトリにあることを仮定している)。
$ ./ls-desktop  
(デスクトップの表示)
$ ~/ls-desktop  
(デスクトップの表示)
$ 
~/bin に置くと、他のコマンド(ls, cp,
emacs) 等と同じように実行することができる。
$ mkdir ~/bin 
(注意: mkdir は、1度だけ実行すればよい。)
$ mv ls-desktop ~/bin 
$ ls-desktop 
(デスクトップの表示)
$ 
シェル・スクリプトを実行する時に、シェル・スクリプトに対して引数を与え ることができる。 The Unix Super Text 40.13.2 参照。
ls-desktop では、「デスクトップ」だけ表示できる。これはこれで便利である が、他の漢字を含む任意のディレクトリを表示したいという要求もある。たと えば、「書類」や「ダウンロード」も表示できるようにしたい。そこで、「引 数」としてディレクトリ名を含むようにする。シェル・スクリプトの名前を 「ls-e」 とする。
$ cd ~/bin 
$ ls -l ls-desktop  
-rwxr-xr-x  1 yas  prof  34  6 17 12:09 ls-desktop
$ cp ls-desktop ls-e 
$ ls -l ls-e 
-rwxr-xr-x  1 yas  prof  34  6 17 13:16 ls-e
$ emacs ls-e 
(修正)
$ cat ls-e 
#!/bin/bash
ls $* | nkf -e
$ ls -l ls-e 
-rwxr-xr-x  1 yas  prof  27  6 17 13:15 ls-e
(cp の時点で x ビットは立っているので chmod +x は不要。)
$ ls-e ~/Desktop 
(デスクトップの内容)
$ ls-e ~/Downloads 
(「ダウンロード」の内容)
$ 
この例では、ls-desktop の「~/Desktop」を「$*」に置き換えている。「$*」
は、コマンドに与えられた全ての引数ということを意味している。
$1,$2,... で参照できる。
$*では、全ての引数を参照できる。
shift コマンドで引数をずらすことができる。
$#で引数の数がわかる。
#」を使ってコメントを書くことができる。bash は、
文字「#」移行、行末まで無視する。
$ echo a b # c d 
a b
$ # echo a b c 
$ 
~/.bashrc という名前のファイルにあるプログラムを自動的
に実行する。~/.bashrc では、次のようなことを行う。
$ /usr/bin/emacs 
$ /bin/ls 
環境変数 PATH にディレクトリ名を登録しておくと、ディレクトリ名を省略す
ることができる。
例: 
$ echo $PATH 
(省略):/usr/bin:/bin:(省略)
$ emacs 
$ ls 
~/.bashrc に保存する。
以下の例は、ssh でよくアクセスするホストをシェル変数に登録している。
$ cat ~/.bashrc 
...
coins=coins.tsukuba.ac.jp
www=www.$coins
icho=icho.u.tsukuba.ac.jp
...
$ 
これを使うと、ssh が簡単になる。
$ ssh $www 
$ ssh $icho 
~/.bashrcなどを設定して、~/bin を PATH環境変数に含まれ
るようにすることを奨める。自分で作成したプログラムやシェル・スクリプトを
~/bin に置くと、ファイル名を指定しなくても
(「~/ファイル名」や 
「./ファイル」打たなくて)、
~/bin以下の短いファイル名で実行できるようになる。
coins では、標準で ~/bin が PATH に含まるように設定されて
いるので、各自設定する必要はない。
/bin/sh) は、Bourne SHell と呼ばれる。対話的な利用では、csh
や bash を使う人でも、シェル・スクリプトを作成する時には、sh を使う人も多
い。
実際には、Unix オリジナルの sh ではなく、bash (GNU Bourne-Again SHell) という高機能のプログラムが広く使われている。bash が sh という名前で実行 された時に sh のごとく振舞う。多くの sh の機能は、bash ではそのまま利用 できる。
エイリアスとは一般に「別名」の意味。1つのものに2つ以上の名前をつける。
cd ~/public_html」を簡単に実行するためのコマンド
「cd-web」 を alias として定義する。
$ cd-web 
-bash: cd-web: command not found
          # 最初は cd-web というコマンドは見つからない
$ alias cd-web 
-bash: alias: cd-web: not found
          # 最初は cd-web という alias も見つからない
$ alias cd-web='cd ~/public_html' 
          # aliasの定義
$ alias cd-web 
alias cd-web='cd ~/public_html'
          # aliasの定義の確認
$ pwd 
/home/prof/yas
          # 最初はホーム・ディレクトリに居る
$ cd-web 
          # 定義したaliasの実行
$ pwd 
/home/prof/yas/public_html
          # ~/public_html に移動している。
$ 
~/.bashrc に alias の定義を追加したものを有効にするには、次のような方法 がある。
$ bash 
$ 
$ . ~/.bashrc 
$ 
 $ cat ~/.bashrc
 #
 # coins standard ~/.bashrc
 #
 if [ -f /usr/local/lib/standard/bashrc ]; then
	 . /usr/local/lib/standard/bashrc
 fi
 # add your own code below
 $ 
まず、端末で何かコマンドを実行しなさい。以下の例では、 /Applications/Calculator.app を実行している。
$ open /Applications/Calculator.app  
(^p で1行もどす。^a で、行頭に移動して 「echo '」と打ち、^e して
「' >  run-calc」 と打つ)
$ echo 'open /Applications/Calculator.app'  > run-calc 
$ cat run-calc  
open /Applications/Calculator.app
$ 
bash の機能で、^p (Control+P) で1行戻して、echo でファイルに落とす。
echo には、実行したコマンドを
「'シングルクォート'」で括る(
'|') などして、エスケープして与えると安全である。
作成したファイルは、そのまま実行できる。
$ bash run-calc  
いちいち bash と打たないでもいいようにするために、chmod コマンド
で実行可能属性をつける。
$ ls -l run-calc  
-rw-r--r--  1 yas  prof  34  6 16 15:08 run-calc
$ chmod +x run-calc  
$ ls -l run-calc  
-rwxr-xr-x  1 yas  prof  34  6 16 15:08 run-calc
$ ./run-calc  
$ ~/run-calc 
$ 
エディタ(Emacs)で1行目に「#!/bin/bash」か「#!/bin/sh」を入れる。
#!/bin/bash
open /Applications/Calculator.app 
完成したコマンドを ~/bin に移動する。
$ mkdir ~/bin 
(注意: mkdir は、1度だけ実行すればよい。)
$ mv run-calc ~/bin 
$ run-calc 
$ 
echo コマンドではなく、history コ
マンドを使う。
$ open /Applications/Firefox.app 
$ open /Applications/Emacs.app 
$ history 
(ヒストリの表示して、何行必要か数える。
history コマンド自身の分、1行多く保存する。)
$ history |tail -3 > run-fe 
 history |tail -3 > run-fe
$ cat run-fe 
  512  open /Applications/Firefox.app
  513  open /Applications/Emacs.app
  514  history |tail -3 > run-fe
$ emacs run-fe 
(不要な部分を削除する。1行目に #!/bin/bash と入れる。)
$ cat  run-fe 
#!/bin/sh
open /Applications/Firefox.app
open /Applications/Emacs.app
$ ls -l run-fe 
-rw-r--r--  1 yas  prof  70  6 16 15:35 run-fe
$ chmod +x run-fe 
$ ls -l run-fe 
-rwxr-xr-x  1 yas  prof  70  6 16 15:35 run-fe
$ ./run-fe 
$ ~/run-fe 
$ mkdir ~/bin 
(注意: mkdir は、1度だけ実行すればよい。)
$ mv run-fe ~/bin 
$ run-fe 
$ 
$ cd /usr/bin 
$ file * | grep shell 
$ 
そのプログラムが、一般のプログラム(機械語)かシェル・スクリプトかは、 file コマンドを使うと調べることができる。
 $ cd /usr/bin
 $ ls -l apropos
 -r-xr-xr-x  1 root  wheel  1808  5 19  2009 apropos
 $ file apropos
 apropos: POSIX shell script text executable
 $ head apropos
 #!/bin/sh
 #
 # apropos -- search the whatis database for keywords.
 # whatis  -- idem, but match only commands (as whole words).
 #
 # Copyright (c) 1990, 1991, John W. Eaton.
 # Copyright (c) 1994-1999, Andries E. Brouwer.
 #
 # You may distribute under the terms of the GNU General Public
 # License as specified in the README file that comes with the man
 $ 
if then else fi
for
while
case
exec
eval
exit
.
$((式)) で簡単な計算ができる。
この機能を確認しなさい。
The Unix Super Text 41.3.8項 参照。
$ cat add 
#!/bin/bash
a=$1
b=$2
x=$(($a + $b))
echo $x
$ ./add 10 20 
30
$ 
フィルタを利用したシェル・スクリプトを作成してみさない。
$ lldir ~ 
drwxr-xr-x  59 yas  prof  12288  6 16 15:37 /home/prof/yas
$ lldir / 
drwxrwxr-t  27 root  admin  1326  4 22 15:43 /
$ 
$ date 
2010年 6月17日 木曜日 16時57分54秒 JST
$ date-num 
2010-06-17-16-57-55
$ 
$ date-cities 
Tokyo
2010年 6月17日 木曜日 17時09分35秒 JST
New York
2010年 6月17日 木曜日 04時09分35秒 EDT
London
2010年 6月17日 木曜日 09時09分35秒 BST
$ 
ヒント: 都市の情報は、/usr/share/zoneinfo/ にある。
夏時間(daylight saving time/summer time)により、
経度の標準からずれていることもある。
$ l2 file.tex 
ヒント: if を使う。 「&&」を使う方法もある。
$ lpshow file.tex 
(画面には、file.pdf が Preview.app で表示される)
ヒント: 拡張子 .pdf を持つファイルを open コマンドで開くと、標準では
Preview.app が動作するが、他のプログラム(例えば Adobe Reader)にも変更で
きる。この課題でも他のプログラムを使ってもよい。
$ ls-c ~/syspro/file/ 
fd-print.c
file-copy.c
mmap-head.c
stdio-thru.c
utmp-print.c
wtmp-last10.c
ystat.c
ystat.h
ヒント:シェルの
ファイル名置換
で *.c や *.h といったファイル名のものだけを取り出す。
余裕があれば、-l などのオプションが付けられるようにしなさい。
$ ls-dot ~ 
.
..
.bashrc
.emacs
.login
$ 
ヒント
方法1:シェルの ファイル名置換 「.*」というパタンで探す。
方法2: ls に -a オプションを付けると、全てのファイルを表示し、 そのうち、先頭が「.」のものを抜き出す。 先頭が「.」のものを抜き出すには、 grep コマンドで次のパタンを検索する。
$ grep '^\.' 
abc
.abc
.abc
aaa
.aaa
.aaa
^D
$ 
余裕があれば、-l などのオプションが付けられるようにしなさい。
$ lsd ~ 
Desktop/
Documents/
Downloads/
Library/
Mail/
Maildir/
Movies/
Music/
Pictures/
WinFiles/
bin/
public_html/
$ 
方法1: ls -F の結果を grep で必要なものだけを抜き出す。
方法2:
余裕があれば、-l などのオプションが付けられるようにしなさい。 余裕があれば、ls と同じように、ファイル名の順に並べ替えなさい。
$ ls-size ~yas/syspro/www 
-rwxr-xr-x   1 yas  prof  27056 Jun 12 11:54 cgi-printarg.cgi
-rwxr-xr-x   1 yas  prof  18376 Jun 19 01:29 cgi-hello.cgi
-rw-r--r--   1 yas  prof   5287 Jun 12 11:54 cgi-printarg.c
-rw-r--r--   1 yas  prof   1579 Sep 26  2002 get.c
-rwxr-xr-x   1 yas  prof    985 May 20 17:17 cgi-printarg-ruby.cgi
-rw-r--r--   1 yas  prof    486 Jun 11 21:20 cgi-hello.c
-rw-r--r--   1 yas  prof    297 Sep 22  2003 Makefile
drwxr-xr-x   5 yas  prof    170 Jun 19 01:27 CVS
-rw-r--r--   1 yas  prof     54 Feb 14  2004 data
total 128
$ 
ヒント:ls -l の出力を sort コマンドでソートする。
ソートは、第5フィールドで行う。
$ wc-lines *.c 
      85     228    1836 proc-uid-print.c
      75     187    1156 pipe-rw-dup.c
      50     152    1141 vaddr-print.c
      46     140    1071 proc-create.c
      67     161    1014 pipe-rw-nodup.c
      38      93     819 signal-int.c
      50      98     802 setjmp-longjmp.c
      32      90     561 run-n.c
      27      66     535 home-print.c
      20      50     424 cont-1.c
      20      50     424 cont-0.c
      25      60     419 t-system.c
      20      40     384 exec-date.c
      14      49     370 arg-print.c
      15      44     355 env-print.c
      12      32     305 cont-2.c
      13      16     174 fork-hello.c
       4      10      60 main-return.c
$ 
この課題では、合計(Total)は表示されなくてもよい。
ヒント:wc の出力を sort コマンドでソートする。for で1つずつ wc コマン ドを実行して、全体の結果を sort するか、引数 $* で wc した後、sort する。
$ ps aux 
USER       PID  %CPU %MEM      VSZ    RSS   TT  STAT STARTED      TIME COMMAND
root         1   0.0  0.0  2456708   1356   ??  Ss   火08AM    1:26.40 /sbin/la
yas       3549   0.0  0.0  2435468    980 s000  Ss    3:40PM   0:00.01 -bash
yas       3548   0.0  0.0  2450900    748   ??  S     3:40PM   0:00.00 /usr/sbi
yas       3546   0.0  0.0  2456124    672   ??  Ss    3:40PM   0:00.01 /sbin/la
root      3544   0.0  0.1  2450900   4700   ??  S     3:40PM   0:00.27 /usr/sbi
root      3543   0.0  0.0  2446148    820   ??  Ss    3:40PM   0:00.00 /usr/lib
...
root        54   0.0  0.6  2468840  25220   ??  Ss   火08AM    0:43.01 /usr/lib
root      3556   0.0  0.0  2434788    428 s000  R+    3:40PM   0:00.00 ps aux
$ 
そのうち、メモリのサイズ(RSS)が大きいプロセスを 10 個だけ表示するシェル・
スクリプトを作りなさい。
$ ps-rss-top10 
USER       PID  %CPU %MEM      VSZ    RSS   TT  STAT STARTED      TIME COMMAND
root       318   0.0  3.0   215076 127388   ??  Ss   火08AM    1:12.05 /Library/
root       104   0.0  0.9  2567852  37332   ??  Ss   火08AM    0:41.42 /System/L
_windowserver  1007   0.0  0.6  2775984  25560   ??  Ss   火05PM    0:31.43 /Sys
root        54   0.0  0.6  2468840  25220   ??  Ss   火08AM    0:43.01 /usr/libe
root      1599   0.0  0.6 11156056  24040   ??  Ss   水02PM    0:09.13 /System/L
_mysql     218   0.0  0.5  2510832  18940   ??  S    火08AM    0:57.74 /opt/loca
_securityagent  1019   0.3  0.4  2757796  15396   ??  S    火05PM    7:51.89 /Sy
root       305   0.0  0.3   152008  14292   ??  S    火08AM    0:31.75 /Library/
root      1010   0.0  0.2  2727284   7956   ??  Ss   火05PM    0:03.56 /System/L
root      1050   0.0  0.2  2777952   7676   ??  Ss   火05PM    0:00.66 /System/L
$ 
ヒント:1行目は、そのまま表示する。RSS の順(第6フィールド)に sort して
head する。
余裕があれば、VSZ の順、CPU 時間の順に表示するスクリプトを作りなさい。
類似のことを実行するプログラムとして top がある。
$ diff-backup kadai10.txt 
余裕があれば、比較しているファイルの名前を表示したり、ファイルごとに停
止する、引数を取る、diff に対するオプションを取る、などの工夫をしなさ
い。
$ diff-backup kadai10.txt kadai11.txt kadai12.txt 
ヒント:for 文で、引数のファイルについて、"$file"~ のような名前のファイ
ルが存在するかを調べる。存在すれば、diff コマンドで表示する。
% mv-lower [A-Z]* 
ヒント:ファイル名を echo して、tr で小文字にして、それを `` でシェル変数に入れる。元の名前から小文字 の名前に mv で変える。
余裕があれば、大文字と小文字を変換することで、ファイルが上書きされる時 には警告を出したり、ユーザに問い合わせたりするようにしなさい。
$ show-n-m 10 20 filename 
余裕があれば、-n オプションを付けなさい。これは、ファイルに行番号を振 るものである。nl コマンドを使うとよい。(cat -n が使えるシステムもある。)
$ countdown 5 
5
4
3
2
1
0
$ 
ヒント:sleep 1 で、1秒ごとに止める。
$ lv ~/.bashrc 
$ lv /usr/local/lib/standard/bashrc 
環境変数 PATHの値を観察しなさい。
$ echo $PATH 
環境変数 PATH に含まれているディレクトリには、どのようなコマンドがある
かを調べなさい。例えば、/usr/local/bin を調べるには、次のようにする。
$ ls /usr/local3/coins/macosx/bin 
path 以外にどのような
シェル変数と環境変数
が設定されているかを調べなさい。
ls -l の代わりに
ll というコマンドを使えるようにしなさい。
$ ls -l 
total 80
-rw-r--r--  1 yas  prof  36224  6 16 16:24 index.html
-rw-r--r--  1 yas  prof   4459  6 16 16:24 screen-tab.png
$ ll 
-bash: ll: command not found
          # この時点ではコマンドは見つからない
$ alias ll='ls -l' 
          # alias による ll コマンドの定義
$ ll 
total 80
-rw-r--r--  1 yas  prof  36224  6 16 16:24 index.html
-rw-r--r--  1 yas  prof   4459  6 16 16:24 screen-tab.png
$ 
$ alias 
$ alias ll 
名前='定義内容'」
を引数として与える。例:
$ alias ll='ls -l' 
$ unalias ll 
~/.bashrc に alias の定義を追加しても、既に実行しているシェルには反映さ れない。実行しているシェルに反映させるには、「.」コマンドを用いる。
 $ cat ~/.bashrc
 #
 # coins standard ~/.bashrc
 #
 if [ -f /usr/local/lib/standard/bashrc ]; then
	 . /usr/local/lib/standard/bashrc
 fi
 # add your own code below
 alias ll='ls -l'
          # ~/.bashrc に ll を追加した
 $ ll
 bash: ll: command not found
          # 追加しただけでは、コマンドは見つからない
 $ . ~/.bashrc
          # 「.」コマンドで、~/.bashrc を読み込む
 $ ll
 (ls -l の表示)
          # ll コマンドが有効になっている。
 $ 
echo でファイルに落すのではなく、alias コマンドでエ
イリアスを定義する。
~/.bashrc に追加する。
次の機能を確認しなさい。
jobs コマンド
fg コマンド
bg コマンド
%によるジョブの指定方法
stop コマンド (%による指定)
kill コマンド (%による指定)
(1) 練習問題(1909)  から
練習問題(1926)  まで
から1つ選んでシェル・スクリプトを作成しなさい。
作成したシェル・スクリプトを、ディレクトリ ~/bin に起きなさい。
作成したシェル・スクリプトについて、次のことを書きなさい。
(2) 共通科目情報処理の 情報処理実習用手引き の次の章を読みなさい。
(3) 筑波大学における情報システム利用のガイドライン を読みなさい。 そして、疑問に思ったことを3項目以上示しなさい。たとえば、「3.10節 (a)の 端末をロックの意味が分からない」などと書きなさい。
(4) [加点] bash のエイリアス、または関数を定義しなさい。エイリアス は、~/.bashrc に保存しなさい。定義したエイリアス、または、関数について、 次のことを書きなさい。