Help us understand the problem. What is going on with this article?

UNIX講習会#2 パイプ・リダイレクト・プロセス置換

More than 3 years have passed since last update.

一部うまく表示できていない部分があるので,詳細はこちらからどうぞ.


UNIXの哲学

これがUNIXの哲学である。

一つのことを行い、またそれをうまくやるプログラムを書け。

協調して動くプログラムを書け。

標準入出力(テキスト・ストリーム)を扱うプログラムを書け。標準入出力は普遍的インターフェースなのだ。

— M. D. マキルロイ、UNIXの四半世紀

Wikipediaからコピペ


UNIXの哲学

  1. 小さいものは美しい。
  2. 各プログラムが一つのことをうまくやるようにせよ。
  3. できる限り原型(プロトタイプ)を作れ。
  4. 効率よりも移植しやすさを選べ。
  5. 単純なテキストファイルにデータを格納せよ。
  6. ソフトウェアの効率をきみの優位さとして利用せよ。
  7. 効率と移植性を高めるためにシェルスクリプトを利用せよ。
  8. 束縛するインターフェースは作るな。
  9. 全てのプログラムはフィルタとして振る舞うようにせよ。

ガンカーズ: 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を含む行を抜き出している
  • 仲間にgrepegrepがあり,こちらは正規表現が使える
  • ファイル名を省略,もしくは-を指定すると標準入力から入力する
    • これはこの後で出てくるソフトウエアでも共通
    • 自分で各プログラムもそうすることを推奨する

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の内容を標準出力に出力し,その結果からをfgrepappserverを含む行だけ抜き出している

パイプを使う 2

  • パイプはいくつでもつなぐことができる
  • 多くのプログラムにおいて入力ファイル名を省略するか-を指定すると標準入力からの入力になる

課題

  • /etc/groupの中にusを含む行が何行あるかを数えなさい

解答

$ cat /etc/group|fgrep us|wc -l Enter
      10
  • パイプでcatfgrepwcをつないでいる

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 
_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 
==> /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言語の関数の説明や設定ファイルの書き方などあらゆる項目が解説されている
  • セクションごとに何を解説しているかが違う
    1. General commands
    2. System calls
    3. Library functions (C and others)
    4. Special files
    5. File formats and conventions
    6. Games and screensavers
    7. Miscellanea
    8. System administration commands and daemons

man

  • セクション番号を指定して呼び出すときにはman SECTION NAMEとする
  • たとえばprintfコマンドの解説を見たいときにはman 1 printfとするが,C言語のprintf関数の説明を見たければman 3 printfとする
  • Linux と OS X では同じコマンドでもオプションが違うものが多いので,必ず使用するマシンの上で確認する

まとめ

困ったらmanを読め

informationsea
Github: https://github.com/informationsea / Twitter: https://twitter.com/informationsea
https://informationsea.info
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした