cutは行から列(フィールド)や文字位置を抜き出すコマンド、trは文字を置き換え・削除・圧縮するコマンド、wcは行数・単語数・バイト数を数えるコマンドです。 3つをパイプ(|)でつなぐと、「CSVの3列目に何種類の値があるか」「ログにIPアドレスごとのアクセスが何件あるか」といった集計を1行で書けます。

この記事では、3コマンドのオプションを早見表にまとめ、同じサンプルファイルに対する実行結果をすべての例に付けました。 連続スペースで cut の列がずれる、日本語で -c が思った文字数にならない、末尾に改行がないと wc -l が1少ない、といったつまずきも実際に再現して、直し方を並べています。CSV・ログ・/etc/passwd を題材にしたワンライナー集、awk に切り替える目安、macOS との差も載せました。

検証環境は Ubuntu 24.04 LTS、GNU coreutils 9.4(cut・tr・wc)、bash 5.2.21、GNU Awk 5.2.1、ロケールは C.UTF-8 です。macOS(BSD版)の欄は手元で動かしていないため「未実行」と明記しています。

cut・tr・wcの早見表

やりたいことから選ぶ

やりたいこと コマンド
CSVの2列目を抜き出す cut -d, -f2 items.csv
2列目と4列目を抜き出す cut -d, -f2,4 items.csv
3列目から最後まで cut -d, -f3- items.csv
各行の先頭13バイト cut -c1-13 access.log
連続スペースを1つに詰めてから列を取る tr -s " " < cols.txt | cut -d" " -f2
小文字を大文字にする tr a-z A-Z
カンマを改行にする tr "," "\n"
特定の文字を消す tr -d "-"
数字以外を全部消す tr -cd "0-9\n"
Windowsの改行(CR)を消す tr -d "\r"
行数を数える wc -l items.csv
行数を数字だけで取る wc -l < items.csv
文字数(日本語も1文字)を数える wc -m
列の値が何種類あるか cut -d, -f3 items.csv | sort -u | wc -l

cut のオプション

オプション 働き 例
-f リスト フィールド(列)番号で選ぶ。番号は1から -f2 -f1,3 -f2-4
-d 文字 区切り文字を指定(1文字だけ。既定はタブ) -d, -d: -d" "
-c リスト 文字位置で選ぶ(GNU 9.4 ではバイト単位で動く) -c1-10
-b リスト バイト位置で選ぶ -b1-3
-s 区切り文字を含まない行を出力しない -s -d, -f2
--complement 指定した列「以外」を出力(GNU) --complement -f1
--output-delimiter=文字列 出力の区切りを変える(GNU) --output-delimiter=" : "
-z 行の区切りを改行でなく NUL にする(GNU) find -print0 と組み合わせ

リストの書き方は -f・-c・-b で共通です。

書き方 意味
N N番目だけ
N,M N番目とM番目
N-M N番目からM番目まで
N- N番目から最後まで
-M 最初からM番目まで

tr のオプション

オプション 働き 例
(なし)tr SET1 SET2 SET1 の文字を、同じ位置の SET2 の文字に置き換える tr a-z A-Z
-d SET1 SET1 の文字を削除する tr -d "\r"
-s SET1 SET1 の文字が連続していたら1つに圧縮する tr -s " "
-c SET1 SET1「以外」の文字を対象にする(補集合) tr -cd "0-9\n"
-t SET1 を SET2 の長さに切り詰めてから置き換える tr -t abcde xy

SET に書ける主な記法です。

記法 意味
a-z A-Z 0-9 範囲
[:lower:] [:upper:] 小文字・大文字
[:digit:] [:alpha:] [:alnum:] 数字・英字・英数字
[:space:] [:blank:] 空白類(改行含む)・スペースとタブ
[:punct:] 記号
\n \t \r 改行・タブ・復帰(CR)

wc のオプション

オプション 数えるもの items.csv での結果
-l 行数(改行文字の数) 6
-w 単語数(空白区切り) 6
-c バイト数 168
-m 文字数(ロケールに従う) 112
-L 最も長い行の表示幅 28
(なし) 行数・単語数・バイト数の3つ 6 6 168
--total=only 合計だけを出す(GNU 9.4 で確認) 複数ファイル指定時
--files0-from=F NUL 区切りのファイル名一覧から読む(GNU) find -print0 と組み合わせ

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「Linux cut・tr・wcの使い方|列の抜き出しと行数カウント早見表」

この記事で使うサンプルファイル

次の4つを使います。コピーして貼り付ければ、同じ結果を手元で確かめられます。

cat > items.csv <<'EOF'
id,name,category,price,stock
1,ノート,文具,180,40
2,ボールペン,文具,120,150
3,マグカップ,食器,980,12
4,付箋,文具,250,0
5,トレー,食器,1500,7
EOF

cat > access.log <<'EOF'
192.168.1.10 - - [03/Oct/2026:09:00:01 +0900] "GET /index.html HTTP/1.1" 200 1024
192.168.1.11 - - [03/Oct/2026:09:00:05 +0900] "GET /items HTTP/1.1" 200 2048
192.168.1.10 - - [03/Oct/2026:09:01:12 +0900] "POST /login HTTP/1.1" 302 0
192.168.1.12 - - [03/Oct/2026:09:02:30 +0900] "GET /missing HTTP/1.1" 404 512
192.168.1.10 - - [03/Oct/2026:09:03:44 +0900] "GET /items HTTP/1.1" 200 2048
192.168.1.11 - - [03/Oct/2026:09:04:02 +0900] "GET /admin HTTP/1.1" 500 128
EOF

cat > passwd.sample <<'EOF'
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
sato:x:1000:1000:Sato,,,:/home/sato:/bin/bash
suzuki:x:1001:1001::/home/suzuki:/bin/zsh
tanaka:x:1002:1002::/home/tanaka:/bin/bash
EOF

printf 'NAME     QTY   STATUS\nnote       40   ok\npen       150   ok\ncup        12   low\n' > cols.txt

passwd.sample は /etc/passwd と同じ形式(コロン区切りの7列)の練習用ファイルです。本物の /etc/passwd でも同じコマンドが使えます。

cutで列や文字位置を抜き出す

区切り文字と列番号で抜き出す(-d と -f)

cut -d, -f2 items.csv
name
ノート
ボールペン
マグカップ
付箋
トレー

-d, で「区切りはカンマ」、-f2 で「2列目」を指定しています。複数列や範囲も指定できます。

cut -d, -f2,4 items.csv
name,price
ノート,180
ボールペン,120
マグカップ,980
付箋,250
トレー,1500
cut -d, -f2-4 items.csv | head -3
cut -d, -f3-  items.csv | head -2
cut -d, -f-2  items.csv | head -2
name,category,price
ノート,文具,180
ボールペン,文具,120
category,price,stock
文具,180,40
id,name
1,ノート

-d を省くと区切りはタブになります。 TSV(タブ区切り)ならそのまま cut -f2 で取れます。

printf "a\tb\tc\n" | cut -f2
b

列の順番は入れ替えられない

cut -d, -f4,2 items.csv | head -2
name,price
ノート,180

-f4,2 と書いても、出力は元の並び(2列目→4列目)のままです。順番を入れ替えたいときは awk を使います(後述)。

出力の区切りを変える・指定列以外を出す(GNU)

cut -d, -f2,4 --output-delimiter=" : " items.csv | head -3
cut -d, --complement -f1,5 items.csv | head -2
name : price
ノート : 180
ボールペン : 120
name,category,price
ノート,文具,180

--complement は「1列目と5列目を除いた残り」を出します。列数が多い表から不要な列だけ落とすときに短く書けます。

コロン区切り・スペース区切り

cut -d: -f1,7 passwd.sample
root:/bin/bash
daemon:/usr/sbin/nologin
www-data:/usr/sbin/nologin
sato:/bin/bash
suzuki:/bin/zsh
tanaka:/bin/bash
cut -d" " -f1,9 access.log
192.168.1.10 200
192.168.1.11 200
192.168.1.10 302
192.168.1.12 404
192.168.1.10 200
192.168.1.11 500

アクセスログは、スペース区切りで数えると1列目がIPアドレス、9列目がステータスコードです。スペースが1つずつ規則的に入っているので、cut でそのまま取れます。

文字位置で抜き出す(-c)

cut -c1-13 access.log | head -2
192.168.1.10 
192.168.1.11 

桁がそろった固定幅のデータに向いています。日本語を含むときの注意は「つまずき2」で扱います。

区切り文字が無い行の扱い(-s)

echo "no delimiter here" | cut -d, -f2
echo "no delimiter here" | cut -s -d, -f2
no delimiter here

区切り文字を含まない行は、そのまま全体が出力されます。 見出しやコメント行が混ざって困るときは -s を付けると、その行は出力されなくなります(2つ目の結果は空です)。

cut のエラーメッセージと直し方

メッセージ 原因 直し方
cut: you must specify a list of bytes, characters, or fields -f・-c・-b のどれも指定していない -f2 などを付ける
cut: the delimiter must be a single character -d に2文字以上を渡した(-d",," や全角文字) 1バイトの文字にする/awk を使う
cut: fields are numbered from 1 -f0 を指定した 列番号は1から数える
cut: nofile.csv: No such file or directory ファイル名が違う ls で確かめる

いずれも実際に出したメッセージです。たとえば -d に2文字を渡すと次のようになります。

cut -f2 -d",," items.csv
cut: the delimiter must be a single character
Try 'cut --help' for more information.

trで文字を置き換える・消す・詰める

tr はファイル名を引数に取らず、標準入力だけを読みます。 ファイルを処理するときは < かパイプで渡します。

tr a-z A-Z items.csv
tr: extra operand ‘items.csv’
Try 'tr --help' for more information.

正しくは tr a-z A-Z < items.csv です。

置き換える

echo "Hello World" | tr a-z A-Z
echo "Hello World" | tr "[:lower:]" "[:upper:]"
echo "hello" | tr "el" "ip"
HELLO WORLD
HELLO WORLD
hippo

tr は「文字列」ではなく「1文字ずつ」の置き換えです。 3つ目の例は「el を ip に」ではなく、「e→i、l→p」という対応なので、l が2つとも p になり hippo になります。単語単位で置き換えたいときは sed 's/el/ip/' を使います。

区切り文字の変換にもよく使います。

echo "a,b,c" | tr "," "\n"
echo "$PATH" | tr ":" "\n" | head -3
a
b
c
/home/claude/.npm-global/bin
/root/.local/bin
/root/.cargo/bin

$PATH を1行ずつに分けると、どのディレクトリが入っているか見やすくなります(中身は環境によって変わります)。

SET2 が SET1 より短いときは、SET2 の最後の文字が繰り返し使われます。-t を付けると、対応する分だけ置き換えます。

echo "abcde" | tr "abcde" "xy"
echo "abcde" | tr -t "abcde" "xy"
xyyyy
xycde

消す(-d)

echo "tel: 03-1234-5678" | tr -d "-"
echo "a1b2c3" | tr -d "[:digit:]"
printf "line1\r\nline2\r\n" | tr -d "\r" | od -An -c
tel: 0312345678
abc
   l   i   n   e   1  \n   l   i   n   e   2  \n

3つ目は、Windows で作ったファイルの行末にある \r(CR)を取り除く定番の形です。od -An -c で1文字ずつ表示すると、\r が消えて \n だけになったことを確かめられます。

指定した文字「以外」を対象にする(-c)

echo "tel: 03-1234-5678" | tr -cd "0-9\n"
echo "a1b2c3" | tr -c "0-9\n" "_"
0312345678
_1_2_3

-cd "0-9\n" は「数字と改行以外を消す」という意味です。\n を入れ忘れると行末の改行も消えるので、セットに含めておきます。

連続を1つに詰める(-s)

echo "aaabbbccc   x" | tr -s "a-z "
printf "a\n\n\nb\n" | tr -s "\n"
echo "one two  three" | tr -s " " "\n"
abc x
a
b
one
two
three

2つ目は空行をまとめて消す形、3つ目は「スペースを改行に置き換えたうえで、連続した改行を1つにする」形です。単語を1行に1つずつ並べたいときに使えます。

wcで行数・単語数・文字数を数える

基本の3つの数字

wc items.csv
  6   6 168 items.csv

左から行数・単語数・バイト数・ファイル名です。個別に知りたいときはオプションを付けます。

wc -l items.csv
wc -w access.log
wc -c items.csv
wc -m items.csv
wc -L items.csv
6 items.csv
60 access.log
168 items.csv
112 items.csv
28 items.csv

-c はバイト数、-m は文字数です。 items.csv には日本語(UTF-8 で1文字3バイト)が入っているので、168 バイトで 112 文字になります。

複数ファイルと合計

wc -l items.csv access.log passwd.sample
wc --total=only -l items.csv access.log
  6 items.csv
  6 access.log
  6 passwd.sample
 18 total
12

複数ファイルを渡すと、最後に total の行が付きます。合計だけ欲しいときは --total=only(GNU coreutils 9.4 で確認)か、wc -l *.csv *.log | tail -1 を使います。

数字だけを取り出す

wc -l items.csv
wc -l < items.csv
cat items.csv | wc -l
6 items.csv
6
6

ファイル名を引数で渡すと「数字+ファイル名」、標準入力から渡すと「数字だけ」になります。 シェル変数に入れるときに差が出ます。

n=$(wc -l items.csv);   echo "rows=$n"
n=$(wc -l < items.csv); echo "rows=$n"
rows=6 items.csv
rows=6

数値として比較・計算に使うなら、wc -l < ファイル の形にしておくとそのまま使えます。

ほかのコマンドの結果を数える

ls | wc -l                       # ファイル・ディレクトリの数
grep " 200 " access.log | wc -l  # 条件に合う行の数
grep -c " 404 " access.log       # grep だけで数える
7
3
1

grep ... | wc -l は grep -c と同じ結果になります。パイプの最後に wc -l を付ける形は、どんなコマンドの出力にも使えるので覚えておくと応用がききます。

つまずき1:連続スペースでcutの列がずれる

cols.txt は、列をそろえるためにスペースが複数入っています。

cat cols.txt
NAME     QTY   STATUS
note       40   ok
pen       150   ok
cup        12   low

ここから2列目(QTY)を取ろうとして -d" " -f2 を使うと、次のようになります。

cut -d" " -f2 cols.txt




4行とも空になりました。cut は「区切り文字1つごとに1列」と数えるため、スペースが2つ続くと、その間に空の列があるとみなします。 NAME の次のスペースと、その次のスペースの間が「2列目(空)」です。

直し方:tr -s で連続スペースを1つに詰めてから cut に渡します。

tr -s " " < cols.txt
tr -s " " < cols.txt | cut -d" " -f2
NAME QTY STATUS
note 40 ok
pen 150 ok
cup 12 low
QTY
40
150
12

ls -l、ps、df など、桁ぞろえのためにスペースを入れて出力するコマンドは、どれも同じ方法で扱えます。行の先頭にもスペースがある場合は、詰めたあとも先頭に1つ残るので、列番号が1つ後ろにずれます。

echo "  lead  space" | tr -s " " | cut -d" " -f2
lead

先頭の空白まで気にせず扱いたいときは、awk が向いています。awk は連続した空白をまとめて1つの区切りとして扱い、先頭の空白も読み飛ばします。

awk '{print $2}' cols.txt
QTY
40
150
12

つまずき2:日本語で-cと-bの結果が変わらない・ずれる

「-c は文字単位、-b はバイト単位」と説明されることが多いのですが、GNU coreutils 9.4 の cut で試すと、-c もバイト単位で動きました。

echo "日本語ABC" | cut -c1-3
echo "日本語ABC" | cut -b1-3
echo "日本語ABC" | LC_ALL=ja_JP.utf8 cut -c1-3
日
日
日

UTF-8 の日本語は1文字3バイトなので、-c1-3 は「先頭3文字」ではなく「先頭3バイト=1文字」になります。ロケールを ja_JP.utf8 にしても同じでした。バイトの途中で切ると、文字として成り立たないバイト列が出力されます。

echo "日本語ABC" | cut -b1-4 | od -An -c
 346 227 245 346  \n

4バイト目(346)は2文字目の先頭バイトだけが残った状態で、画面では文字化けして見えます。

文字数とバイト数の違いは wc で確かめられます。

echo "日本語ABC" | wc -c -m
      7      13

出力は「文字数、バイト数」の順で、7文字(改行込み)・13バイトです。

直し方:日本語を文字単位で切りたいときは、awk の substr か grep -o を使います。

echo "日本語ABC" | awk '{print substr($0,1,3)}'
echo "日本語ABC" | grep -o "^..."
日本語
日本語

(GNU Awk 5.2.1、UTF-8 ロケールでの結果です。)

tr も同じくバイト単位で動くため、日本語の置き換えには向きません。

echo "あいう" | tr "あ" "ア"
echo "あいう" | sed "y/あいう/アイウ/"
アやゆ
アイウ

tr では「い」「う」まで別の文字に変わってしまいました。「あ」と「ア」の3バイトを1バイトずつ対応させて置き換えるため、同じバイトを含むほかの文字にも影響が出ます。日本語の1文字置き換えは sed 'y/…/…/' にすると意図どおりになります。

全角の区切り文字も cut の -d には渡せません。

echo "名前:値:備考" | cut -d":" -f2
cut: the delimiter must be a single character

全角コロンは3バイトなので「1文字ではない」と判断されます。この場合は awk -F":" '{print $2}' を使います。

やりたいこと 英数字だけ 日本語を含む
先頭N文字を取る cut -c1-N awk '{print substr($0,1,N)}'
1文字ずつ置き換える tr sed 'y/…/…/'
全角の区切りで分ける 該当なし awk -F":"
文字数を数える wc -c でも同じ wc -m
カンマなど半角区切りで列を取る cut -d, -f cut -d, -f(そのまま使える)

最後の行のとおり、区切り文字が半角なら、列の中身が日本語でも cut -f は問題なく使えます。 items.csv の例がそれにあたります。

つまずき3:末尾に改行がないとwc -lが1少ない

printf "a\nb\nc" > nonl.txt
wc -l nonl.txt
cat nonl.txt | od -An -c
2 nonl.txt
   a  \n   b  \n   c

見た目は3行ですが、wc -l は 2 と答えます。wc -l が数えているのは「行」ではなく「改行文字(\n)の数」だからです。 最後の c のあとに改行がないので、改行は2つしかありません。エディタの設定や、プログラムから書き出したファイルで起こります。

直し方:最後の行に改行がなくても数えたいときは、次のどれかを使います。

grep -c "" nonl.txt
awk 'END{print NR}' nonl.txt
sed -n '$=' nonl.txt
3
3
3

末尾に改行があるかどうかは、最後の1バイトを見ると確かめられます。

tail -c1 nonl.txt  | wc -l    # 0 なら末尾に改行なし
tail -c1 items.csv | wc -l    # 1 なら末尾に改行あり
0
1

同じ理由で、echo -n "" は 0 行、echo "" は 1 行になります。

echo -n "" | wc -l; echo "" | wc -l
0
1

つまずき4:CSVの中にカンマがあると列がずれる

echo '1,"Tokyo, Japan",100' | cut -d, -f2
"Tokyo

cut は引用符を特別扱いしません。値の中にカンマや改行を含む CSV は、cut では正しく分けられないので、Python の csv モジュールなど CSV を理解する道具を使います。

echo '1,"Tokyo, Japan",100' | python3 -c 'import csv,sys; [print(r[1]) for r in csv.reader(sys.stdin)]'
Tokyo, Japan

値にカンマが入らないとわかっている CSV なら、cut でそのまま扱えます。空の列は空のまま出力されます。

echo "a,,c" | cut -d, -f2,3
,c

パイプでつなぐワンライナー集

ここからは、3コマンドと sort・uniq・head・grep を組み合わせた例です。すべてサンプルファイルで実行した結果を付けています。

CSV(items.csv)

# 1. カテゴリごとの件数(1行目の見出しは tail -n +2 で除く)
tail -n +2 items.csv | cut -d, -f3 | sort | uniq -c
      3 文具
      2 食器
# 2. カテゴリが何種類あるか
tail -n +2 items.csv | cut -d, -f3 | sort -u | wc -l
2
# 3. 列の数を数える(見出し行のカンマを改行に変えて数える)
head -1 items.csv | tr "," "\n" | wc -l
5
# 4. 列名に番号を振る(-f に渡す番号を調べる)
head -1 items.csv | tr "," "\n" | cat -n
     1  id
     2  name
     3  category
     4  price
     5  stock
# 5. 名前を1行にカンマ区切りでまとめる
tail -n +2 items.csv | cut -d, -f2 | paste -sd, -
ノート,ボールペン,マグカップ,付箋,トレー
# 6. 価格の合計(+ でつないで bc に渡す)
cut -d, -f4 items.csv | tail -n +2 | paste -sd+ - | bc
3030
# 7. 見出し行のカンマの数を数える(列数 - 1)
head -1 items.csv | tr -cd "," | wc -c
4

アクセスログ(access.log)

# 8. IPアドレスごとのアクセス数(多い順)
cut -d" " -f1 access.log | sort | uniq -c | sort -rn
      3 192.168.1.10
      2 192.168.1.11
      1 192.168.1.12
# 9. ステータスコードごとの件数
cut -d" " -f9 access.log | sort | uniq -c
      3 200
      1 302
      1 404
      1 500
# 10. パスごとのアクセス数(" で区切って2番目=リクエスト行を取り、その2番目がパス)
cut -d'"' -f2 access.log | cut -d" " -f2 | sort | uniq -c | sort -rn
      2 /items
      1 /missing
      1 /login
      1 /index.html
      1 /admin
# 11. 時:分 だけを取り出す([ と ] で囲まれた部分から)
cut -d"[" -f2 access.log | cut -d"]" -f1 | cut -d: -f2,3 | head -3
09:00
09:00
09:01
# 12. ログに出てくる単語の頻度(小文字にそろえ、英字以外を改行に)
tr "[:upper:]" "[:lower:]" < access.log | tr -cs "a-z" "\n" | sort | uniq -c | sort -rn | head -5
      6 oct
      6 http
      5 get
      2 items
      1 post
# 13. 日付と行数を1行で出す
echo "$(date +%F) $(wc -l < access.log) lines"
2026-10-03 6 lines

10 と 11 のように、区切り文字を変えながら cut を2〜3回つなぐと、1文字区切りの制約があっても複雑な行から必要な部分を取り出せます。

/etc/passwd 形式(passwd.sample)

# 14. ログインシェルごとの人数
cut -d: -f7 passwd.sample | sort | uniq -c | sort -rn
      3 /bin/bash
      2 /usr/sbin/nologin
      1 /bin/zsh
# 15. ログインできるユーザー名を1行に並べる
grep -v nologin passwd.sample | cut -d: -f1 | tr "\n" " "; echo
root sato suzuki tanaka 
# 16. ユーザー名とUIDをタブ区切りにする
cut -d: -f1,3 passwd.sample | tr ":" "\t"
root    0
daemon  1
www-data    33
sato    1000
suzuki  1001
tanaka  1002
# 17. bash を使うユーザーの数
grep "/bin/bash$" passwd.sample | wc -l
3

awkに切り替える目安

cut・tr・wc は「速く書けて読みやすい」のが良さです。次のような場面では awk のほうが短く書けます。

場面 cut・tr・wc awk
区切りが1文字で、列をそのまま取る 向いている:cut -d, -f2 awk -F, '{print $2}'
連続スペース区切り tr -s " " | cut -d" " -f2 向いている:awk '{print $2}'
列の順番を入れ替える できない 向いている:awk -F, '{print $4","$2}'
最後の列を取る rev | cut -d" " -f1 | rev 向いている:awk '{print $NF}'
条件で行を選ぶ(価格が250以上など) できない 向いている:awk -F, 'NR>1 && $4>=250'
列どうしを計算する・合計する paste と bc を組み合わせる 向いている:awk '{s+=$4} END{print s}'
区切りが2文字以上・全角・正規表現 できない 向いている:awk -F":" …
日本語を文字単位で切る 向かない(バイト単位) 向いている:substr($0,1,3)
行数を数えるだけ 向いている:wc -l awk 'END{print NR}'

実際に動かした例です。

# 価格が250以上の商品名と価格
awk -F, 'NR>1 && $4>=250 {print $2, $4}' items.csv

# 価格×在庫の合計
awk -F, 'NR>1 {s+=$4*$5} END{print s}' items.csv

# 最後の列(転送バイト数)
awk '{print $NF}' access.log | head -2
rev access.log | cut -d" " -f1 | rev | head -2
マグカップ 980
付箋 250
トレー 1500
47460
1024
2048
1024
2048

目安は「区切りが1文字で、取るだけなら cut。空白が不規則・条件や計算が入る・順番を変えるなら awk」です。迷ったら、まず cut で書いてみて、tr -s や rev を足したくなったところで awk に切り替えると、どちらの書き方も身に付きます。

Linux(GNU)とmacOS(BSD)の違い

macOS の cut・tr・wc は BSD 由来です。下の表の macOS 列は今回は手元で実行していません(未実行)。一般に知られた仕様として整理したものなので、使う前に man cut・man tr・man wc で確かめてください。

項目 Linux(GNU coreutils 9.4・実行済み) macOS(BSD・未実行)
cut -c と日本語 バイト単位で動いた(-c1-3 で「日」) ロケールに従い文字単位で動く
cut -d に全角文字 the delimiter must be a single character ロケール上の1文字なら受け付ける
cut --complement / --output-delimiter 使える 無い
空白の連続を区切りにする cut -w 無い ある(新しめの版)
tr と日本語 バイト単位(「あ→ア」でほかの文字も変わった) 文字単位で置き換える
wc -l の出力 6 items.csv(左詰め) 6 items.csv(先頭に空白が入る)
wc -l < file 6 先頭に空白が付く(tr -d " " や $(( )) で除く)
wc --total / --files0-from 使える 無い
長いオプション(--help など) 使える 基本的に無い

両方で動かすスクリプトでは、短いオプション(-d・-f・-s、tr -d・-s・-c、wc -l・-c・-m)だけを使い、wc の結果は n=$(( $(wc -l < file) )) のように算術展開を通すと、先頭の空白の有無に左右されなくなります。

よくある質問

Q. cut で最後の列だけを取るにはどうすればよいですか? A. cut には「最後」を表す書き方がありません。列数が決まっていれば番号で指定し、行によって列数が変わるなら awk '{print $NF}'(区切りがカンマなら awk -F, '{print $NF}')を使います。rev | cut -d" " -f1 | rev と、行を反転して1列目を取る方法でも同じ結果になることを確かめました。

Q. tr で「abc」という文字列を「xyz」に置き換えられますか? A. tr は1文字ずつの対応(a→x、b→y、c→z)で置き換えるので、「abc」という並びだけを置き換えることはできません。文字列の置き換えは sed 's/abc/xyz/g' を使います。

Q. wc -l の結果と、エディタで見た行数が合いません。 A. 最後の行の末尾に改行がないと、wc -l は1少なく数えます。tail -c1 ファイル | wc -l が 0 なら末尾に改行がありません。行数を正確に知りたいときは grep -c "" ファイル を使います。

Q. cut の区切りに「2文字以上」や「連続する空白」を指定できますか? A. GNU の cut では -d は1文字(1バイト)だけです。連続する空白は tr -s " " で詰めてから渡し、2文字以上の区切りや全角文字は awk -F"区切り" を使います。

まとめ

  • cut は -d 区切り -f 列番号 が基本。 範囲は 2-4・3-・-2。区切りは1文字だけで、列の順番は入れ替えられない
  • tr は1文字ずつの置き換え(tr a-z A-Z)、削除(-d)、圧縮(-s)。 ファイルは < かパイプで渡す
  • wc は -l 行数、-w 単語数、-c バイト数、-m 文字数。 数字だけ欲しいときは wc -l < ファイル
  • 連続スペースは tr -s " " で詰めてから cut に渡す。 不規則な空白は awk が向いている
  • GNU の cut -c と tr はバイト単位で動く。 日本語を文字単位で扱うなら awk の substr や sed の y
  • wc -l は改行文字の数。 末尾に改行がないと1少ない。grep -c "" なら最終行も数える
  • cut | sort | uniq -c | sort -rn は集計の定番。 条件や計算が入ったら awk に切り替える

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「Linux cut・tr・wcの使い方|列の抜き出しと行数カウント早見表」

株式会社RJCでは、cut・tr・wcのようなテキスト処理コマンドの使い方を仲間と学び合っています。こうした知識を共有しながら、日々技術を磨いています。

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?