コンテンツにスキップ

I/O (入出力) 管理@Linuxカーネル

はじめに

本サイトにつきまして、以下をご認識のほど宜しくお願いいたします。


01. I/Oの意味合い

I/Oの意味合いの種類

I/Oは、文脈によって意味合いが異なる。

文脈 意味合い
シェルの場合 標準入力、標準出力、標準エラー出力
ファイルシステムの場合 ファイルへの読み書き
ストレージの場合 ストレージへの読み書き
ネットワークの場合 インバウンド通信、アウトバウンド通信


IOPS:I/O per second

ストレージへのI/O (数/毎秒) を表す。

I/O自体が文脈によって意味合いが異なるが、IOPSはストレージの文脈でしか使わない。


02. 標準入出力

stdin (標準入力)

▼ 標準入力とは

キーボードやプログラムからのコマンドに対して、データを入力するためのインターフェースのこと。

プロセスごとに存在する。

stdin_stdout_stderr


stdout (標準出力)

▼ 標準出力とは

エラー以外のデータをプログラムや外部デバイスに出力するためのインターフェースのこと。

プロセスごとに存在する。

stdin_stdout_stderr

▼ 標準出力に全て出力

コマンド処理の後に、『2>&1』を追加すると、標準エラー出力に対する出力を標準出力にリダイレクトすることにより、処理の全ての結果を標準出力に出力できるうになる。

*例*

$ echo "text" 2>&1

また、プロセスの標準出力は/proc/<プロセスID>/fdディレクトリのファイルディスクリプタ番号 (1番) で確認できる。プロセスIDはpsコマンドで事前に確認する。

*例*

PHP-FPMの稼働するアプリケーションの例

$ ps -aux

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.6  83736 25408 ?        Ss   01:56   0:03 php-fpm: master process (/usr/local/etc/php-fpm.conf)
www-data  2739  3.6  0.7 247968 29296 ?        Sl   13:24   1:36 php-fpm: pool www
www-data  2815  3.6  0.7 247968 29288 ?        Sl   13:43   0:55 php-fpm: pool www
www-data  2902  3.6  0.7 247968 29304 ?        Sl   14:05   0:07 php-fpm: pool www
root      2928  0.0  0.0   9732  3316 pts/0    R+   14:08   0:00 ps -aux

# 標準出力を確認
$ cat /proc/1/fd/1

▼ 標準出力とファイルに出力

パイプラインでteeコマンドを繋ぐと、標準出力とファイルの両方に出力できる。

$ echo "text" | tee stdout.log


stderr (標準エラー出力)

▼ 標準エラー出力とは

コマンドからターミナルに対して、エラーデータを出力するためのインターフェースのこと。

プロセスごとに存在する。

▼ 標準エラー出力に全て出力

コマンド処理の後に、『1>&2 (または>&2)』を追加すると、標準出力に対する出力を標準エラー出力にリダイレクトする。

1は標準出力であり、2は標準エラー出力、を表す。

これにより、処理の全ての結果を標準エラー出力に出力できるうになる。

$ echo "text" 1>&2

# または

$ echo "text" >&2

また、プロセスの標準出力は/proc/<プロセスID>/fdディレクトリのファイルディスクリプタ番号【2番) で確認できる。プロセスIDはpsコマンドで事前に確認する。

*例*

PHP-FPMの稼働するアプリケーションの例

$ ps -aux

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.6  83736 25408 ?        Ss   01:56   0:03 php-fpm: master process (/usr/local/etc/php-fpm.conf)
www-data  2739  3.6  0.7 247968 29296 ?        Sl   13:24   1:36 php-fpm: pool www
www-data  2815  3.6  0.7 247968 29288 ?        Sl   13:43   0:55 php-fpm: pool www
www-data  2902  3.6  0.7 247968 29304 ?        Sl   14:05   0:07 php-fpm: pool www
root      2928  0.0  0.0   9732  3316 pts/0    R+   14:08   0:00 ps -aux

# 標準エラー出力を確認
$ cat /proc/1/fd/2


02-02. リダイレクト

リダイレクトとは

<>』『<<>>』の記号のこと。ファイルの内容を特定のプロセスの標準入力に転送する。

あるいは反対に、特定のプロセスの標準出力/標準エラー出力をファイルに転送する。

プロセスの標準入力に対する転送は、多くの場合にユーティリティのパラメーターにファイルを渡すことと同じである。


標準入力に対するリダイレクト例

▼ catプロセスに対するリダイレクト

catプロセスの標準入力にstdin.txtファイルの内容をリダイレクトする。

catコマンドにファイルを渡すことと同じである。

$ cat < stdin.txt

Hello World


ファイルに対するリダイレクト例

2>

リダイレクト前にstdout.txtファイルを新しく作成し、echoコマンドの標準出力をこれにリダイレクトする。

$ echo 'Hello World' 2> stdout.txt

>|

リダイレクト前にstdout.txtファイルを新しく作成し、echoコマンドの標準出力をこれにリダイレクトする。

また、すでにファイルが存在している場合は、ファイルを上書き (再作成) する。

$ echo 'Hello World' >| stdout.txt

>>

echoコマンドの標準出力を既存のstdout.txtファイルにリダイレクトし、加えて追記する。

$ echo 'Hello World' >> stdout.txt


02-03. パイプライン

パイプラインとは

|』の縦棒記号のこと。特定のプロセスの標準出力/標準エラー出力を他のプロセスの標準入力に繋げる。

pipeline

シェルは、プロセスの処理結果をパイプラインに出力する。

その後、パイプラインから出力内容をそのまま受け取り、別のプロセスに再び入力する。

pipeline_shell


標準入力に対する入力例

▼ awkプロセスに対する入力

コマンドの出力結果に対して、awkコマンドを実行する。

*例*

検索で取得されたファイルのサイズを合計する。

$ find ./* -name "*.js" -type f -printf "%s\n" \
    | awk "{ sum += $1; } END { print sum; }"

$ find ./* -name "*.css" -type f -printf "%s\n" \
    | awk "{ sum += $1; } END { print sum; }"

$ find ./* -name "*.png" -type f -printf "%s\n" \
    | awk "{ sum += $1; } END { print sum; }"

*例*

パケットのうちで、443番ポートに送信しているもののみを取得し、出力結果の3列目のみをフィルタリングする。

$ tcpdump dst port 443 \
    | awk -F ' ' '{print $3}'

*.*.*.*
*.*.*.*
...

echoコマンドに対する入力

終了ステータスをechoコマンドに渡し、値を出力する。

$ <任意のコマンド> | echo $?

▼ grepプロセスに対する入力

コマンドの出力結果をgrepコマンドに渡し、フィルタリングを実行する。

*例*

検索されたファイル内で、加えて文字列を検索する。

$ find ./* \
  -type f | xargs grep "<検索文字>"

▼ killプロセスに対する入力

コマンドの出力結果に対して、killコマンドを実行する。

*例*

フィルタリングされたプロセスを削除する。

$ sudo pgrep \
  -f <コマンド名> | sudo xargs kill -9

▼ lessプロセスに対する入力

コマンドの出力情報をページングして取得する。

ファイルの行数が多い場合に役立つ。

キー 説明
Enter 1行送り
Space 一ページ送り
Ctrl + f 一ページ送り
Ctrl + b 一ページ戻り
/文字列 以降の文字を検索し、ハイライトする。

*例*

巨大な.yamlファイルをページングして出力する。

$ cat foo.yaml | less

▼ sortプロセスに対する入力

コマンドの出力結果に対して、並び順を変更する。

*例*

表示された環境変数をAZ昇順に並び替える。

$ printenv | sort -f

*例*

表示された表を重複を削除して (uniqと同じ) AZ昇順に並び替える。

$ cat table.txt | sort -f -u

▼ uniqプロセスに対する入力

コマンドの出力結果に関して、行が重複する場合は1個だけ残して削除する。

隣り合っている重複しか削除できないため、あらかじめsortコマンドを実行しておく必要がある。

$ tcpdump dst port 443 \
    | awk -F ' ' '{print $3}' >> source_ips.txt

# 必ずsortの結果を渡す
$ cat source_ips.txt \
    | sort | uniq


03. 印刷デバイスへのデータ出力

アプリケーションから印刷デバイスへデータを出力する時、まず、CPUはスプーラにデータを出力する。

Spoolerは、全てのデータをまとめて出力するのではなく、一時的にストレージ (Spool) にためておく。

その後、少しずつ印刷デバイスにデータを出力 (Spooling) し、印刷デバイスにデータを印刷させる。

スプーリング