特定の列を表示するコマンドは、入力形式で選びます。区切りが一文字で引用規則のない単純データなら cut、連続空白や条件・計算があるなら awk、RFC 形式の CSV なら CSV parser、目視用に整列するだけなら column です。「3列目」という言葉だけでは、区切り、空フィールド、引用された区切り、末尾空白の扱いが決まらないため、最初に数行を sed -n '1,5p' と od -An -t x1 で確認します。 確認ポイント:cutはdelimiter分割であり、引用符やdelimiter内包fieldを持つCSV parserではありません。
cutとawkをdelimiterの性質で使い分ける
次のファイルはコロン区切りで、最後の一行だけ区切りを含みません。-d: が区切り、-f1,3 が第1列と第3列です。GNU cut では区切りは一バイトの文字を指定し、文字列 :: や正規表現は指定できません。
work=$(mktemp -d) || exit 1
trap 'rm -r -- "$work"' EXIT
printf 'name:city:score\nAki:Tokyo:90\nBo:Osaka:85\nno delimiter here\n' >"$work/report data.txt"
cut -d: -f1,3 -- "$work/report data.txt"
出力は name:score、Aki:90、Bo:85、no delimiter here の4行です。区切りがない行は既定で行全体がそのまま出ます。欠損行を捨てるなら -s を加え、cut -s -d: -f1,3 とすると最初の3行だけになります。「区切りなしを空の第3列として出す」動作ではないため、混在データで件数が必要なら、捨てる前に awk -F: 'NF<3 {print NR ":" $0}' で不正行を別に報告します。
範囲は -f2、-f1,3、-f2-4、-f3- のように指定します。出力区切りは既定で入力と同じです。GNU の --output-delimiter=, を使えば選んだフィールド間だけをカンマへ変えられますが、フィールド値中のカンマを引用して CSV にする機能ではありません。
cut -s -d: -f2 -- "$work/report data.txt"
cut -s -d: -f1,3 --output-delimiter=' | ' -- "$work/report data.txt"
第2列は city、Tokyo、Osaka です。次は name | score、Aki | 90、Bo | 85 です。--output-delimiter は GNU 拡張なので、移植用には cut の出力をそのまま使うか awk の OFS を明示します。
一バイト区切りと空フィールド
cut は区切りが連続すると、その間を空フィールドとして数えます。全角読点「、」や複数文字 :: を一つの delimiter にする用途には向きません。UTF-8 の「、」は複数バイトなので GNU cut の -d で一バイト区切りとして扱えず、エラーになる実装があります。複数文字や文字クラスが必要なら awk、厳密な構造形式なら専用 parser を使います。
printf 'A::90\nB:Osaka:80\n' >"$work/empty-field.txt"
cut -d: -f2 -- "$work/empty-field.txt" | sed -n l
printf 'A::90\n' | cut -d: -f2,3
sed -n l で行末を可視化した結果は一行目が $(空の第2列)、二行目が Osaka$ です。次の cut は空の第2列も保持するため :90 を出します。空を詰めて「90を第2列」とは数えません。入力スキーマが空フィールドを許すかを先に決め、列番号を固定します。
連続空白は awk の既定分割を使う
空白整形された表は、スペースが何個あるか一定とは限りません。cut -d ' ' -f2 は各スペースを別 delimiter とするため、連続スペースで空フィールドを返します。awk の既定 FS=" " は先頭・末尾空白を無視し、スペース、タブ、改行を含む空白の連続を区切りとして扱う特別な規則です。
printf 'Aki Tokyo 90\nBo\tOsaka\t85\n' >"$work/space table.txt"
awk '{print $2}' "$work/space table.txt"
awk 'BEGIN {OFS=":"} {print $1,$3}' "$work/space table.txt"
出力は最初が Tokyo、Osaka、次が Aki:90、Bo:85 です。awk -F'[[:space:]]+' は見た目が似ても、正規表現 FS では先頭空白が空の第1フィールドを作り得るなど既定 FS=" " と細部が異なります。単なる空白列なら awk '{print $N}'、明示 delimiter なら awk -F: ... と分けます。
awk -F で条件付きの列を出す
awk -F: 'BEGIN {OFS=":"} NF==3 && $3+0 >= 90 {print $1,$3}' "$work/report data.txt"
printf 'awk_rc=%d\n' "$?"
出力はヘッダーを除けば Aki:90 で、終了値は0です。ただし awk は一致が0件でも通常0で終了します。0件を失敗にするなら awk -F: '$3+0>=90 {print $1; found=1} END{exit !found}' のように終了状態を設計します。$3+0 は非数値も0として扱うので、厳密な入力では $3 ~ /^[0-9]+$/ を先に検証します。引用した shell 変数を awk プログラムへ直接連結せず、awk -v min="$min" ... と値として渡します。
単純分割は CSV parser ではない
CSV はカンマ区切りに見えても、引用符内のカンマ、二重引用符のエスケープ、フィールド内改行を許します。cut -d, や awk -F, は引用状態を解釈しないため、一般の CSV parser ではありません。次の例では note 列の値が Tokyo, Japan ですが、単純分割は途中で切れます。
cat >"$work/data.csv" <<'CSV'
id,name,note
1,Aki,"Tokyo, Japan"
2,Bo,"said ""hello"""
CSV
cut -d, -f3 -- "$work/data.csv"
awk -F, '{print $3}' "$work/data.csv"
どちらも note の後、1件目を "Tokyo までしか出せず、2件目の引用解除も行いません。単純な -F, が使えるのは「値にカンマ、引用符、改行が絶対に入らない」とスキーマで保証された疑似CSVだけです。CSV なら、たとえば Python 3 標準 csv module で列を選びます。
python3 - "$work/data.csv" <<'PY'
import csv, sys
with open(sys.argv[1], newline='', encoding='utf-8') as f:
for row in csv.reader(f):
if len(row) < 3:
raise SystemExit('short row')
print(row[2])
PY
正確な出力は note、Tokyo, Japan、said "hello" です。文字コード、delimiter、quotechar が別仕様なら reader の引数をその仕様に合わせます。ファイル全体の dialect を推測だけで決めず、提供元の定義を確認します。
column は表示整形に限定する
column -t -s: は区切りデータを空白で揃え、人が端末で読む表にします。util-linux の版により -N、-J など利用可能な機能が異なるため column --version を確認します。整形後は空白幅や長い文字の表示幅が変わり、元の delimiter や空フィールド情報を失うことがあるため、後段の機械処理へ渡しません。
column -t -s: "$work/report data.txt"
先頭3行は概ね name city score、Aki Tokyo 90、Bo Osaka 85 と整列します。区切りなし行の扱いや空白幅は column の版・端末幅・文字幅判定で変わり得るため、これを exact data output として比較しません。抽出と検証は cut/awk/parser の構造化段階で終え、column は最後の目視表示だけにします。
ファイル名、失敗条件、検証
- パスは
-- "$file"または awk へ引用した一引数で渡し、cat $file | ...の未引用展開を避ける。 - 区切りなし行を残すなら cut 既定、除外するなら
-s。除外件数を事前に awk で数える。 - 連続空白は awk の既定 FS、単一バイト delimiter は cut、引用規則のある CSV は CSV parser を選ぶ。
- 抽出結果の行数と既知の先頭・末尾レコードを確認し、列ずれや短い行を検出する。
- 本文の操作は読み取りのみで原本を変更しないため、ロールバックは不要。検証ファイルだけを trap で片付ける。

コメント