LPIC Level1 復習ラジオ 12:テキスト処理コマンド
音声
目次
テキスト処理コマンドの使い分け
Linuxでは、小さなコマンドをパイプで組み合わせ、必要な列を取り出し、並べ替え、重複を整理し、文字を変換できます。
今回は、cut、sort、uniq、trの四つを扱います。
| コマンド | 主な用途 | 処理の単位 |
|---|---|---|
cut |
行から必要なフィールド、文字位置、バイト位置を取り出す | 各行 |
sort |
行を並べ替える、並び順を確認する、重複をまとめる | 行 |
uniq |
隣り合う同一行をまとめる、重複行や一意行を抽出する | 隣接する行 |
tr |
文字を置換する、削除する、連続する文字を圧縮する | 文字 |
標準入力・標準出力とパイプ
四つのコマンドは、ファイルや標準入力からデータを受け取り、処理結果を標準出力へ書き出すフィルターとして利用できます。
command1 | command2 | command3
パイプ|は、左側の標準出力を右側の標準入力へ渡します。
cut -d: -f7 /etc/passwd | sort | uniq -c
この例では、/etc/passwdからログインシェルのフィールドを取り出し、同じ値を隣接させ、使用数を数えます。
練習用データを作る
printf '%s\n' orange apple banana apple orange > fruits.txt
printfを使うと、短い練習データを安全に作れます。
cat fruits.txt
sort fruits.txt
sort fruits.txt | uniq -c
元ファイルを変更せず、処理結果だけが標準出力へ表示されることを確認します。
cut
cutは、各入力行から指定した部分を選び、標準出力へ表示するコマンドです。
cut [オプション] [ファイル...]
位置やフィールドの番号は、1から数えます。
区切り文字とフィールドを指定する
cut -d: -f1 /etc/passwd
cut -d: -f1,3,7 /etc/passwd
cut -d: -f3- /etc/passwd
| オプション | 意味 |
|---|---|
-d 文字 | フィールドの区切り文字を指定する。標準はタブ |
-f リスト | 表示するフィールドを指定する |
-s | 区切り文字を含まない行を表示しない |
--complement | 指定したフィールドや位置以外を表示する |
-f1,3,7は第1、第3、第7フィールド、-f3-は第3フィールドから行末までを表します。
cut -d: -f1,7 /etc/passwd
cut -d: -f1 --complement /etc/passwd
cut -d: -f2 -s data.txt
文字位置やバイト位置を指定する
cut -c1-5 file.txt
cut -c1,3,5 file.txt
cut -b1-8 file.txt
-c:文字位置を指定する-b:バイト位置を指定する
ASCII文字では一文字と一バイトが一致することが多い一方、日本語などのマルチバイト文字では一致しません。文字として切り出したいのか、バイトとして切り出したいのかを区別します。
cutが向いているデータ
/etc/passwdのように、各行の区切り文字が明確で、単純な形式のデータに向きます。
引用符で囲まれたカンマや、フィールド内の改行を含む本格的なCSVは、単純なcut -d,では正しく扱えない場合があります。その場合はCSV対応ツールやプログラムを使用します。
sortの基本
sortは、入力行を比較して並べ替え、標準出力へ表示します。ファイルを指定しない場合は標準入力を読み取ります。
sort [オプション] [ファイル...]
文字列として並べ替える
sort fruits.txt
sort -r fruits.txt
sort -f names.txt
| オプション | 意味 |
|---|---|
-r | 逆順に並べる |
-f | 大文字と小文字の違いを無視して比較する |
-b | 比較キー先頭の空白を無視する |
-u | 比較結果が等しい行を一つだけ出力する |
数値として並べ替える
sort numbers.txt
sort -n numbers.txt
sort -nr numbers.txt
標準のsortは文字列として比較します。そのため、10が2より前に並ぶ場合があります。数値として比較する場合は-nを使います。
printf '%s\n' 2 10 3 | sort
printf '%s\n' 2 10 3 | sort -n
人が読みやすいサイズや版番号を並べる
sort -h sizes.txt
sort -V versions.txt
-h:2K、10M、1Gなどを人間向け数値として比較する-V:file2、file10や版番号に近い形で比較する
並び順を確認する
sort -c names.txt
sort -C names.txt
-cは並びが崩れている最初の位置を診断し、-Cはメッセージを出さず終了ステータスで確認します。
sortのキー・区切り文字・ロケール
特定フィールドをキーにする
sort -t: -k3,3n /etc/passwd
sort -t, -k2,2 sales.csv
sort -t, -k2,2nr sales.csv
| 指定 | 意味 |
|---|---|
-t 文字 | フィールド区切り文字を指定する |
-k 開始,終了 | 比較に使うキーの範囲を指定する |
n | そのキーを数値として比較する |
r | そのキーを逆順にする |
-k2,2は第2フィールドだけをキーにします。-k2とすると、第2フィールドの先頭から行末までがキーになります。この違いは試験でも実務でも重要です。
複数キーを指定する
sort -t: -k4,4 -k3,3n /etc/passwd
最初に第4フィールドで比較し、同じ場合は第3フィールドを数値として比較します。
ロケールによる違い
sortの文字列比較は、通常LC_COLLATEなどのロケール設定の影響を受けます。同じスクリプトで一定の並び順が必要な場合は、LC_ALL=Cを付けてバイト値に基づく順序へ固定する方法があります。
LC_ALL=C sort names.txt
結果をファイルへ保存する
sort names.txt > sorted_names.txt
sort -o names.txt names.txt
同じファイルへ保存する場合、sort names.txt > names.txtとはしません。シェルが先に出力先を空にするためです。GNU sortでは、-oを使って出力先を指定できます。
uniq
uniqは、隣り合う同一行を一つにまとめるコマンドです。
uniq [オプション] [入力ファイル [出力ファイル]]
隣接している行だけを比較する
printf '%s\n' apple banana apple | uniq
printf '%s\n' apple banana apple | sort | uniq
一つ目の例では、同じappleが離れているため削除されません。全体の重複をまとめたい場合は、通常は先にsortして同じ行を隣接させます。
主なオプション
sort fruits.txt | uniq
sort fruits.txt | uniq -c
sort fruits.txt | uniq -d
sort fruits.txt | uniq -u
sort -f names.txt | uniq -i
| オプション | 意味 |
|---|---|
-c | 各行の出現回数を行頭に付ける |
-d | 複数回現れた行だけを一グループにつき一行表示する |
-u | 一度だけ現れた行だけを表示する |
-i | 大文字と小文字の違いを無視して比較する |
-f 数値 | 先頭から指定数のフィールドを比較対象外にする |
-s 数値 | 先頭から指定数の文字を比較対象外にする |
出現回数の多い順に並べる
sort fruits.txt | uniq -c | sort -nr
uniq -cで件数を付け、最後のsort -nrで件数を数値の降順に並べます。
sort -uとの関係
sort -u fruits.txt
sort fruits.txt | uniq
単純な重複行の削除では似た結果になります。ただし、比較オプションやキーを組み合わせると判定基準が異なる場合があります。基本学習では、並べ替えながら一意化するならsort -u、隣接行の重複状態を調べるならuniqと整理します。
tr
trは、標準入力から読み取った文字を変換、削除、圧縮し、標準出力へ書き出します。
tr [オプション] 文字集合1 [文字集合2]
trは通常、処理対象のファイル名を引数として受け取りません。リダイレクトやパイプで標準入力へ渡します。
tr 'a-z' 'A-Z' < file.txt
cat file.txt | tr 'a-z' 'A-Z'
文字を変換する
printf '%s\n' hello | tr 'a-z' 'A-Z'
printf '%s\n' 123-456-789 | tr '-' ':'
第1の文字集合に含まれる文字を、対応する第2の文字集合の文字へ置き換えます。
文字を削除する
tr -d '0-9' < file.txt
tr -d '\r' < windows.txt > unix.txt
-dは、第1の文字集合に含まれる文字を削除します。\rを削除する例は、CRLF形式のテキストから復帰文字を取り除く用途で使われます。
連続する文字を一つにまとめる
tr -s ' ' < file.txt
tr -s '\n' < file.txt
-sは、指定した文字が連続している部分を一文字に圧縮します。複数の連続空白や空行をまとめる場合に使えます。
改行と空白を変換する
tr '\n' ' ' < lines.txt
tr ' ' '\n' < words.txt
trは文字単位で動作するため、改行を空白へ、空白を改行へと変換できます。
trの文字クラスと注意点
文字クラスを使う
tr '[:lower:]' '[:upper:]' < file.txt
tr -d '[:digit:]' < file.txt
tr -s '[:space:]' ' ' < file.txt
| 文字クラス | 主な対象 |
|---|---|
[:lower:] | 小文字 |
[:upper:] | 大文字 |
[:digit:] | 数字 |
[:alpha:] | 英字などのアルファベット文字 |
[:alnum:] | 英字と数字 |
[:space:] | 空白、タブ、改行などの空白文字 |
[:print:] | 表示可能な文字 |
範囲指定のa-zより、文字クラスの方が意図を明確にできる場合があります。動作はロケールの影響を受けることがあるため、スクリプトで厳密な結果が必要な場合は実行環境でも確認します。
文字列置換ではない
printf '%s\n' cat | tr 'cat' 'dog'
trは「catという単語をdogへ置換する」コマンドではありません。cをdへ、aをoへ、tをgへ対応させる文字単位の変換です。単語やパターン単位の置換には、後の学習で扱うsedなどを使います。
補集合を使う
tr -cd '[:digit:]\n' < file.txt
-cは指定集合の補集合を対象にし、-dと組み合わせると、指定した文字以外を削除できます。この例では数字と改行以外を削除します。
コマンドを組み合わせる
ログインシェルの利用数を集計する
cut -d: -f7 /etc/passwd | sort | uniq -c | sort -nr
cutで第7フィールドを取り出すsortで同じシェルを隣接させるuniq -cで件数を数えるsort -nrで件数の多い順に並べる
大文字と小文字を統一して単語数を数える
tr '[:upper:]' '[:lower:]' < words.txt |
tr -s '[:space:]' '\n' |
sort |
uniq -c |
sort -nr
大文字を小文字へ変換し、空白文字を改行へ変換して一行一語に近い形へ整え、同じ語を集計します。句読点などを厳密に扱うには、追加の処理が必要です。
UIDを数値順に確認する
cut -d: -f1,3 /etc/passwd | sort -t: -k2,2n
利用者名とUIDを取り出し、コロン区切りの第2フィールドを数値として並べます。
結果を保存しながら確認する
cut -d: -f7 /etc/passwd |
sort |
uniq -c |
sort -nr |
tee shell_counts.txt
teeを使うと、画面へ表示しながらファイルにも保存できます。リダイレクトとパイプの詳しい整理は第18回で扱います。
よくある間違いと確認手順
| 間違いやすい点 | 確認すること |
|---|---|
cut -fでコロン区切りを処理できない |
標準の区切りはタブ。-d:を指定する |
sortで10が2より前に並ぶ |
文字列比較になっていないか。数値なら-nを使う |
sort -k2の範囲が想定より広い |
第2フィールドだけなら-k2,2と指定する |
uniqで離れた重複行が消えない |
uniqは隣接行だけを比較する。必要なら先にsortする |
tr file.txt ...のように使ってしまう |
trは標準入力を読む。< file.txtやパイプを使う |
trで単語を置換しようとする |
trは文字単位。文字列置換には別のコマンドを使う |
| 並び順が別環境で変わる | ロケールを確認し、必要ならLC_ALL=Cを指定する |
| 入力ファイルへ直接リダイレクトして内容が消える | 別ファイルへ出力するか、sort -oなどを使う |
小さなデータで段階的に確認する
cut -d: -f7 /etc/passwd
cut -d: -f7 /etc/passwd | sort
cut -d: -f7 /etc/passwd | sort | uniq -c
cut -d: -f7 /etc/passwd | sort | uniq -c | sort -nr
長いパイプラインで結果がおかしい場合は、左側から一段ずつ実行し、どの処理から想定と違ったかを確認します。
manページを確認する
man cut
man sort
man uniq
man tr
info coreutils 'cut invocation'
info coreutils 'sort invocation'
info coreutils 'uniq invocation'
info coreutils 'tr invocation'
30秒チェック
- コロン区切りの第1フィールドを取り出す
cutの指定は何でしょうか。 - 数値を昇順に並べる
sortのオプションは何でしょうか。 sort -k2とsort -k2,2は、キーの範囲がどう違うでしょうか。uniqが重複として検出できるのは、どのような行でしょうか。uniq -c、-d、-uは、それぞれ何を表示するでしょうか。trへファイル内容を渡す方法を一つ答えてください。tr -dとtr -sの違いは何でしょうか。- 並び順をロケールに左右されにくい形へ固定する代表的な指定は何でしょうか。
答えを表示
cut -d: -f1 ファイル-n-k2は第2フィールドの先頭から行末まで、-k2,2は第2フィールドだけ- 隣り合っている同一行
-cは出現回数付き、-dは重複した行、-uは一度だけ現れた行tr ... < ファイル、またはcat ファイル | tr ...など-dは文字を削除し、-sは連続する同じ文字を一つにまとめるLC_ALL=C sort ...
要約
cutは、各行から指定したフィールド、文字位置、バイト位置を取り出します。cut -d: -f1はコロン区切りの第1フィールドを表示し、フィールド番号は1から始まります。sortは行を並べ替え、-nは数値順、-rは逆順、-uは一意化です。sort -t: -k3,3nのように、区切り文字、キー範囲、比較方法を指定できます。-k2は第2フィールドから行末まで、-k2,2は第2フィールドだけをキーにします。sortの文字列比較はロケールの影響を受け、必要に応じてLC_ALL=Cで固定します。uniqは隣接する同一行を比較するため、全体の重複整理では通常先にsortします。uniq -cは件数、-dは重複行、-uは一度だけ現れた行を表示します。trは標準入力を文字単位で変換し、-dは削除、-sは連続文字の圧縮です。- 長いパイプラインは、左側から一段ずつ実行して結果を確認します。