一部うまく表示できていない部分があるので,詳細はこちらからどうぞ.
UNIXの哲学
これがUNIXの哲学である。
一つのことを行い、またそれをうまくやるプログラムを書け。
協調して動くプログラムを書け。
標準入出力(テキスト・ストリーム)を扱うプログラムを書け。標準入出力は普遍的インターフェースなのだ。
— M. D. マキルロイ、UNIXの四半世紀
Wikipediaからコピペ
UNIXの哲学
- 小さいものは美しい。
- 各プログラムが一つのことをうまくやるようにせよ。
- できる限り原型(プロトタイプ)を作れ。
- 効率よりも移植しやすさを選べ。
- 単純なテキストファイルにデータを格納せよ。
- ソフトウェアの効率をきみの優位さとして利用せよ。
- 効率と移植性を高めるためにシェルスクリプトを利用せよ。
- 束縛するインターフェースは作るな。
- 全てのプログラムはフィルタとして振る舞うようにせよ。
ガンカーズ: UNIXの哲学
Wikipediaからコピペ
すなわち
- UNIXのプログラムは基本的に単純なことだけを行うように書かれていることが多い
- たとえばソートだけとか,最初の何行かを抜き出すだけとか
- パイプやプロセス置換で組み合わせることでより複雑なことができるようになる
標準入出力
- コマンドライン上で動くプログラムは標準入力,標準出力,標準エラー出力が存在する
- 標準入力も標準出力も標準ではターミナルに接続されている
- リダイレクト・パイプを利用するとこで接続先を変更
cat で標準入力・標準出力を試す
- cat は何も引数を指定しなければ標準入力から標準出力にデータをそのまま受け渡す
$ cat Enter
AAA Enter
AAA Control-D
$ - AAAは標準入力から
catに渡され,AAAは標準出力から出力されている - Control-Dは標準入力の終わりを指示する
cat でリダイレクトを試す 1
- リダイレクトを使うと標準入出力をファイルに書き換えられる
$ cat > hello.txt Enter
Hello, world Enter
Control-D
$ cat hello.txt Enter
Hello, world- 一つ目のコマンドで
catの標準出力をhello.txtに置き換えている - そのため,
Hello, world!が2回表示されない
cat でリダイレクトを試す 2
- リダイレクトを使うと標準入出力をファイルに書き換えられる
$ cat < hello.txt Enter
Hello, world- 今度は
catの標準入力をhello.txtに置き換えている - ただ,私は
<をあまり使わない- 通常,コマンドは基本的に左から右に流れる
- パイプでも
mvでもcpでも左から右に行く - 原則に反するのでミス防止のため使わない
- なので,
<を使わず,catで出力させて,後述するパイプにつなげることが多い
リダイレクトあれこれ
-
>>でファイルを上書きでなく追記になる -
2>で標準エラー出力をリダイレクトできる- 標準エラー出力はこの後に出てくるパイプを利用していても通常はターミナルにつながっているので,エラーを画面上で確認できる
-
&>で標準出力と標準エラー出力を同時にリダイレクトできる -
このあたりの仕様は使うシェルによって違うので要確認
パイプと相性の良いソフトウエアたち
-
パイプのありがたみを理解するために先に組み合わせて便利なプログラムを紹介する.
-
fgrep: 特定の文字を含む行を抜き出す -
tail: ファイルの末尾を出力する -
head: ファイルの先頭を出力する -
wc: 行数や文字数を数える
fgrep
$ fgrep ssh /etc/group Enter
_sshd:*:75:
com.apple.access_ssh:*:399:-
/etc/groupの中にあるsshを含む行を抜き出している - 仲間に
grepやegrepがあり,こちらは正規表現が使える - ファイル名を省略,もしくは
-を指定すると標準入力から入力する- これはこの後で出てくるソフトウエアでも共通
- 自分で各プログラムもそうすることを推奨する
head/tail
$ head -n 3 /etc/group Enter
##
# Group Database
#
$ tail -n 2 /etc/group Enter
com.apple.access_screensharing:*:398:
com.apple.access_ssh:*:399:- ファイルの先頭と末尾を出力できる
-
-n Xで何行出力するかを指定できる- 省略した場合には10行
wc
$ wc /etc/group Enter
115 154 2317 /etc/group
$ wc -l /etc/group Enter
115 /etc/group
$ wc -w /etc/group Enter
154 /etc/group
$ wc -c /etc/group Enter
2317 /etc/group- Word Count の略
- 行数,単語数,文字数を数える
-
-lをつけるて行数を数えることが多い
-
パイプを使う 1
- パイプはあるプログラムの標準出力と標準入力を接続する
-
|の前後のプログラムをつなぐ
$ cat /etc/group|fgrep appserver Enter
_appserverusr:*:79:
_appserveradm:*:81:- この例では
cat /etc/groupで/etc/groupの内容を標準出力に出力し,その結果からをfgrepでappserverを含む行だけ抜き出している
パイプを使う 2
- パイプはいくつでもつなぐことができる
- 多くのプログラムにおいて入力ファイル名を省略するか
-を指定すると標準入力からの入力になる
課題
-
/etc/groupの中にusを含む行が何行あるかを数えなさい
解答
$ cat /etc/group|fgrep us|wc -l Enter
10- パイプで
catとfgrepとwcをつないでいる
tee
- リダイレクトで結果を保存したい
- でも,画面にも出力したい
- こういう場合には
teeを使うと実現できるtee 出力先
$ grep ssh /etc/group|tee result.txt
_sshd:*:75:
com.apple.access_ssh:*:399:-
result.txtに画面に出力されたものと同じ結果が出力されている
フィルタ
- 標準入力から何かデータを受け取り,標準出力に出力するプログラムをフィ
ルタと呼ぶ - UNIXではあらゆるソフトウエアがフィルタとして動作するように設計されて
いる - 自分で書くソフトウエアもフィルタとして動作することが望ましい
プロセス置換
- パイプの弱点
- 1対1の関係しか作れない
- 2つの入力から1つの出力をするのはできない
- プロセス置換を使うと2つ以上の入力から1つの出力を得ることができる
- ファイルを指定するかわりにどのプログラムを実行するかを指定できる
プロセス置換:例
$ cat <(fgrep ssh /etc/group) <(fgrep core /etc/passwd)
_sshd:*:75:
com.apple.access_ssh:*:399:
_coreaudiod:*:202:202:Core Audio Daemon:/var/empty:/usr/bin/false
_coremediaiod:*:236:236:Core Media IO Daemon:/var/empty:/usr/bin/false-
/etc/groupからsshを含む行を抜き出し,/etc/passwdからはcoreを
含む行を抜き出し,その二つをcatで結合している - 注意:
/etc/groupや/etc/passwdはユーザー情報が含まれるので安易に公開してはならない- OS Xでは問題ない場合が多いが推奨はしない
課題
-
/etc/groupからuを含む行を抜き出し,/etc/passwdからAを含む行を抜き出し,それぞれの先頭10行を表示させる - ヒント
-
headは複数のファイルを指定できる
-
解答
$ head <(fgrep u /etc/group) <(fgrep A /etc/passwd)
==> /dev/fd/11 <==
# Group Database
# Note that this file is consulted directly only when the system is running
# in single-user mode. At other times this information is provided by
# See the opendirectoryd(8) man page for additional information about
nogroup:*:-1:
... 以下省略-
==> /dev/fd/11 <==の部分は通常はファイル名を表示するが,プロセス置換を用いるとこのような表示になる.実装上の問題なので特に気にしなくて良い
コマンド置換
- 他にありがちな課題としてコマンドの引数を他のコマンドを実行した結果か
ら指定したい場合がある - この場合にはバッククオートが使える
- 日本語キーボードの場合にはShift-@で入力
$ cat `echo ~/.profile`
# MacPorts Installer addition on 2015-02-14_at_23:33:49: adding an appropriate PATH variable for use with MacPorts.
export PATH="/opt/local/bin:/opt/local/sbin:$PATH"
# Finished adapting your PATH environment variable for use with MacPorts.
-
echoは引数をそのまま標準出力に出力するだけのコマンド
課題
-
/etc/shellsに書かれているパス(ただし#で始まるコメント行は除く)についてls -lhを用いてファイルサイズを表示させなさい
解答
$ ls -lh `fgrep / /etc/shells`
-r-xr-xr-x 1 root wheel 614K 10 27 13:01 /bin/bash
-rwxr-xr-x 2 root wheel 361K 9 10 2014 /bin/csh
-r-xr-xr-x 1 root wheel 1.3M 9 10 2014 /bin/ksh
-r-xr-xr-x 1 root wheel 614K 10 27 13:01 /bin/sh
-rwxr-xr-x 2 root wheel 361K 9 10 2014 /bin/tcsh
-rwxr-xr-x 1 root wheel 538K 9 10 2014 /bin/zsh-
fgrep / /etc/shellsで/を含む行だけを抜き出してコメントを排除している
まとめ
- プログラムは標準入力,標準出力,標準エラー出力をもつ
- これらは普段はターミナルに接続されているが,リダイレクトやパイプで接続先を変更できる
- プロセス置換を用いると複数のプログラムの標準出力を一つのプログラムのファイル入力に接続できる
- コマンド置換を用いると,あるプログラムの標準出力を他のプログラムの引数として利用できる
おまけ?
- コマンドの使い方に困ったときには
manを使う - 使い方は
man コマンド名
man: 例
$ man mv
MV(1) BSD General Commands Manual MV(1)
NAME
mv -- move files
SYNOPSIS
mv [-f | -i | -n] [-v] source target
mv [-f | -i | -n] [-v] source ... directory
DESCRIPTION
In its first form, the mv utility renames the file named by the source
manの読み方
-
SYNOPSISに使い方の例が書いてある-
[]で囲まれた部分はオプションであり必須ではない - 下線が引いてあるところはユーザーが変更すべきところ
-
-
DESCRIPTION以下に詳しい説明がある - 人に聞く前に
manを読みましょう
man
-
manはコマンドの説明だけでなく,C言語の関数の説明や設定ファイルの書き方などあらゆる項目が解説されている - セクションごとに何を解説しているかが違う
- General commands
- System calls
- Library functions (C and others)
- Special files
- File formats and conventions
- Games and screensavers
- Miscellanea
- System administration commands and daemons
man
- セクション番号を指定して呼び出すときには
man SECTION NAMEとする - たとえば
printfコマンドの解説を見たいときにはman 1 printfとするが,C言語のprintf関数の説明を見たければman 3 printfとする - Linux と OS X では同じコマンドでもオプションが違うものが多いので,必ず使用するマシンの上で確認する
まとめ
困ったらmanを読め