0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

#0244(2025/09/14)catコマンドはプリントじゃない

Last updated at Posted at 2025-09-14

catコマンドはプリントじゃない ― ストリームを連結する“ポンプ”

catとは「ファイルや標準入力のバイト列を連結して標準出力へ流すコマンド」である。

catの本質と語源(con"cat"enate)

  • 本質: 読み取ったバイト列を解釈せず、入力→出力へそのまま転送する。
  • 語源: “concatenate”(連結)から。**表示(print)**は副産物で、出力先が端末(TTY)だと見えるだけ。
  • ユースケースの核: 「複数入力の連結」「ストリーム化してパイプに流す」「特殊ファイルの取り扱い(/dev/zero, FIFOなど)」。

よくある誤解とアンチパターン(比較表)

同じ階層(=解決したい課題が同じ)の書き方を表で比較します。

やりがちな書き方 何が問題か より良い書き方 備考
`cat file grep kw` 二重I/Oで無駄(UUOC: Useless Use of cat) grep kw file 例外: 複数プロセス出力の結合にはcatが有効(下記参照)。
`cat file sed 's/a/b/'` 同上 sed 's/a/b/' file -iで直接編集も可(バックアップ注意)。
`cat file awk '{...}'` 同上 awk '{...}' file awkは自前でファイルを読む。
`cat file wc -l` パイプ不要 wc -l < file 入力リダイレクトで同等、速い。
`cat file tail -n 1` 無駄な中継 tail -n 1 file head/tailはファイルを直接読める。
`cat large.gz zcat` 二重展開の混乱 zcat large.gz 圧縮は伸ばしてからstringsgrepへ。
catで行番号付け 用途ズレ nl file / cat -n file 目的が表示なら専用コマンドの方が表現力あり。

“良いcat”の使いどころ(実務に効く具体例)

1) 複数生成元の結合(プロセス置換)

cat <(jq -r '.items[] | .id' a.json) \
    <(jq -r '.items[] | .id' b.json) \
  | sort -u > ids.txt

2つのコマンド出力を順序を保って1本のストリームにまとめる。

2) 分割ファイルの連結

cat backup.part.* > backup.tar

分割アーカイブを連結して元に戻す。split/gsplitの逆操作。

3) **FIFO(名前付きパイプ)**の中継

mkfifo pipe
cat pipe | gzip -9 > out.gz &  # 中継(圧縮担当)
producer > pipe                # どこかのプロセスが供給

生データを別プロセスに受け渡すときの“ポンプ”役。

4) デバイスファイルの取り扱い

# 1MiBのゼロ埋めファイル
cat /dev/zero | head -c 1M > zeros.bin
# ランダムデータでテスト
cat /dev/urandom | head -c 256 > key.bin

ddでも可能だが、cat+headは直感的で簡潔

5) ストリームを途中で枝分かれ(tee連携)

make build 2>&1 | tee build.log | grep -i 'error'

リアルタイム表示しつつログ保存&フィルタ。cat単体では分岐できないが、パイプラインの起点/前段として有用。

6) “中身をいじらず運ぶだけ”が欲しい時

cat config.yml | ssh host 'cat > /etc/myapp/config.yml'

余計な改行やエスケープを入れない“素の転送”。scp代替にならないが、一時的な書き込みに便利。

catと近縁コマンドの役割比較(表)

同列の目的を持つコマンドを具体例つきで比較します(同じ課題を解く“選択肢”として捉える)。

コマンド 一言で 具体例(ひと目で用途がわかる) 落とし穴 / 補足
cat 連結/転送 cat a b > all
`cat <(cmd1) <(cmd2)
sort -u` 加工はしない。ポンプ役に徹する。
tac 逆順cat `tac access.log grep -m1 'ERROR'`(最後のエラーを速攻で) 行単位逆順。巨大ファイルはI/O多め。
tee 分岐 `make 2>&1 tee build.log grep -i error` -a追記。分岐はtee、連結はcat。
paste 横連結 paste -d, a.csv b.csv(列を並べてCSV化) 行数ズレは要注意。列操作はawk/cutも選択肢。
head 先頭を見る head -n 20 file
`zcat huge.gz
head -n 1` “確認/スニペット取得”に最適。
tail 末尾を見る tail -f app.log(追従)
tail -n +2 file(1行目除去)
ログローテは-Fが堅い。
less ページャ less -R +G build.log(色保持で末尾から閲覧) 対話ツール。スクリプト用途は非推奨。
nl 行番号付与 `nl -ba source.c sed -n '120,140p'` cat -nでも可。空行扱いはオプションで調整。
tr 文字置換/削除 tr -d '\r' < win.txt > unix.txt(CR削除) 正規表現は不可。単純変換のみ。
dd ブロックI/O dd if=/dev/zero of=file bs=1M count=1 status=none サイズ/アライメント厳密に制御。進捗status=progress
printf/echo 生成 `printf 'GET / HTTP/1.0\r\n\r\n' nc host 80` echoは実装差多い。正確さはprintf
sed/awk 加工 sed -E 's/(foo)/\U\1/g' file
awk -F, '$3>0{sum+=$3} END{print sum}' data.csv
テキスト加工の主戦力。大規模集計はawkが楽。
split 分割 split -b 100M big.bin part.cat part.* > big.bin 再結合は順序に注意(接頭辞の並び)。

実務Tips(性能・可搬性・安全)

  • UUOCは避ける: 直接ファイルを読めるコマンドにはそのまま渡す方が高速・明快。
  • ロケールで速度差: 大量テキストは LC_ALL=C でバイト比較に倒すと速いことがある(例: LC_ALL=C sort)。
  • 改行とバイナリ: 改行無しの巨大レコードやNULを含むデータは、cat通せるが後段が詰まることがある。grep -atr/odで前処理。
  • 権限と上書き: cat > /path/file上書き>>で追記、set -o noclobberで事故防止も検討。
  • 巨大ファイル: ネットワーク越しは逐次処理(ストリーミング)を活用。cat big | gzip | ssh host 'cat > big.gz' のように保存せず転送

パイプは1行ずつ渡すの? それともまとめて?

結論: パイプは「行」ではなく、ただのバイト列ストリームです。
cat data.txt | xxx のとき、catは読み取ったデータを**塊(ブロック)で write(2)し、受け手xxx任意サイズで read(2)**します。行単位で“渡す”仕組みはありません

  • 行っぽく見える理由: grepawkのように“行で処理する”コマンドが、受け取ったバイト列を自前で改行で区切って扱うから。読み取りはまとめてでも、解釈は行ベース
  • バッファリングの性質: 多くの実装は標準ライブラリのバッファリングに従います。出力先が端末(TTY)なら行バッファパイプ/ファイルならブロックバッファが一般的。そのためパイプではまとめて流れやすい
  • パイプの器(カーネルバッファ): サイズはOS依存(Linuxの既定は数十KiBが典型)。アプリ側は“連続したバイト列”として扱えば十分。
  • 典型的な挙動: yes | head -n1 は、headが1行読んだ瞬間パイプを閉じる→yesSIGPIPEで終了。行で止まるように見えても、実体はバイトストリームです。

バッファリングの比較と制御(表)

モード いつ起きる 利点 欠点 代表例 / 強制手段
行バッファ 出力先がTTY(端末)のとき 低遅延(行ごとに即時フラッシュ) スループットが出にくい / 行末まで出ない grep --line-bufferedstdbuf -oL cmdawk '{...; fflush()}'
ブロックバッファ 出力先がパイプ/ファイルのとき 高スループット バッファが溜まるまで遅延 既定動作が多い。調整: stdbuf -o 4096 cmd(ブロック/サイズ指定)
アンバッファ 明示指定時 ほぼ即時 I/O回数増で重くなる stdbuf -o0 cmdpython -uunbuffer cmd(expect)

リアルタイムに見たいログは、次のように“行バッファ化”すると快適です:

tail -f app.log | grep --line-buffered -i 'error'
python producer.py | stdbuf -oL consumer

まとめ

  • catプリントコマンドではない。本質はストリームの連結と転送
  • “表示したい”ならless/nl/grep等、目的特化の道具を選ぶ。
  • “データを運ぶ・束ねる”場面では、catは最短で確実なポンプになる。
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?