read – シェルスクリプトで入力を受け取るコマンド

入出力制御・TTY
スポンサーリンク

read コマンドは、標準入力から 1行の入力を読み取り、変数に格納 するためのシェル組み込みコマンドです。
対話的にユーザー入力を受け付けたり、スクリプト内で入力値を処理する際に利用されます。

構文(Syntax)

read [オプション] [変数...]

主なオプション一覧

オプション説明使用例
(なし)入力を1行読み取り、指定した変数に格納read name
-p "PROMPT"入力前にメッセージを表示read -p "Enter your name: " name
-s入力を非表示(パスワード入力向け)read -s password
-t N入力を待つ秒数を指定(タイムアウト)read -t 5 name
-n NN文字だけ読み取るread -n 1 key
-rバックスラッシュをエスケープ文字として扱わないread -r line
-a ARRAY入力を配列に格納read -a items
-d DELIM区切り文字を指定(デフォルトは改行)read -d : input

実行例

基本的な入力の読み取り

read name
echo "Hello, $name"

実行例:

Alice   ← ユーザー入力
Hello, Alice

プロンプト付きで入力

read -p "Enter your name: " name
echo "Welcome, $name"

パスワードを非表示で入力

read -s -p "Password: " password
echo
echo "Password entered (hidden)"

5秒以内に入力がなければタイムアウト

read -t 5 -p "Enter your name: " name

1文字だけ入力を取得

read -n 1 -p "Press any key: " key
echo "You pressed '$key'"

改行やエスケープをそのまま読み取る

read -r line

配列として入力を格納

read -a items
echo "First item: ${items[0]}"

入力例:

apple banana cherry

出力例:

First item: apple

区切り文字(:)までを入力として取得

echo "abc:def:ghi" | read -d : var
echo "$var"

出力例:

abc

エラー例(タイムアウト)

read -t 2 name

出力例:

(2秒経過後に終了、変数は空)

csvファイルの取り扱い

read コマンドを使うことでcsvファイルに記載された情報による処理の繰り返し実行に対応できます。

1) 基本:カンマ区切り(引用・カンマ埋め込みなし想定)

#!/usr/bin/env bash
# basic_csv_read.sh
# 例: ./basic_csv_read.sh sample.csv

set -o errexit -o nounset -o pipefail

csv_file="${1:-sample.csv}"

# ヘッダーを読み飛ばしたいときは tail -n +2 を使う
tail -n +2 "$csv_file" | while IFS=, read -r id name age; do
  # 空行スキップ
  [[ -z "${id}${name}${age}" ]] && continue
  printf 'id=%s, name=%s, age=%s\n' "$id" "$name" "$age"
done
  • 前提:"Alice, Bob" のようなフィールド内カンマ二重引用符が無いCSV向け。

2) 可変列数を配列で受ける(列数がバラつくCSV向け)

#!/usr/bin/env bash
# csv_to_array.sh
# 例: ./csv_to_array.sh sample.csv

set -o errexit -o nounset -o pipefail
csv_file="${1:-sample.csv}"

# ヘッダー飛ばし
{ read -r _header; cat; } < "$csv_file" | \
while IFS=, read -r -a cols; do
  [[ ${#cols[@]} -eq 0 ]] && continue
  echo "列数=${#cols[@]} / 先頭=${cols[0]}"
  # 例: 3列目を安全に参照
  if (( ${#cols[@]} >= 3 )); then
    echo "3列目=${cols[2]}"
  fi
done
  • read -a で配列に展開できます(ただし引用・埋め込みカンマは未対応)。

3) RFC4180 風:ダブルクォート対応(埋め込みカンマ・二重の二重引用符 “” を扱う)

Bash だけで素朴にパースする小さな関数。改行を含むフィールドは未対応ですが、一般的な "a, b","x""y" を処理できます。

#!/usr/bin/env bash
# csv_read_rfcish.sh
# 例: ./csv_read_rfcish.sh sample_quoted.csv

set -o errexit -o nounset -o pipefail

csv_read_line() { # usage: csv_read_line array_name ; reads 1 logical line from stdin
  local __arr_name=$1
  local line
  IFS= read -r line || return 1

  local -a fields=()
  local field="" c next in_quotes=0
  local i=0 len=${#line}

  while (( i < len )); do
    c=${line:i:1}
    if (( in_quotes )); then
      if [[ $c == '"' ]]; then
        next=${line:i+1:1}
        if [[ $next == '"' ]]; then
          field+='"'         # 連続する "" はエスケープされた "
          ((i++))
        else
          in_quotes=0        # クォート終了
        fi
      else
        field+="$c"
      fi
    else
      case "$c" in
        '"') in_quotes=1 ;;  # クォート開始
        ',') fields+=("$field"); field="" ;;
        $'\r') ;;            # CR 無視(Windows 改行対策)
        *) field+="$c" ;;
      esac
    fi
    ((i++))
  done
  fields+=("$field")

  # nameref 経由で呼び出し側の配列に代入(bash 4.3+)
  local -n __ref=$__arr_name
  __ref=("${fields[@]}")
  return 0
}

csv_file="${1:-sample_quoted.csv}"

# ヘッダーを先に1行読む(必要なければ削除)
{
  IFS= read -r header || true
  echo "HEADER: $header"
  while csv_read_line cols; do
    # 空行スキップ
    [[ ${#cols[@]} -eq 1 && -z ${cols[0]} ]] && continue
    printf 'Row:'
    for ((i=0; i<${#cols[@]}; i++)); do
      printf ' [%d]=<%s>' "$i" "${cols[$i]}"
    done
    printf '\n'
  done
} < "$csv_file"
テスト用 sample_quoted.csv
id,name,comment
1,"Alice","Hello, world"
2,"Bob","He said ""Good luck!"" yesterday"
3,"Carol","no quotes"

4) CSVを書き出す(値を安全にエスケープして出力)

#!/usr/bin/env bash
# csv_write.sh
# 例: ./csv_write.sh > out.csv

set -o errexit -o nounset -o pipefail

csv_escape() {
  local s=$1
  s=${s//\"/\"\"}  # " を "" に
  if [[ "$s" == *[,\"$'\n'$'\r']* ]]; then
    printf '"%s"' "$s"
  else
    printf '%s' "$s"
  fi
}

# 見出し
printf '%s,%s,%s\n' "id" "name" "note"

# データ例
id=1;   name='Alice'; note='Hello, world'
printf '%s,%s,%s\n' \
  "$(csv_escape "$id")" \
  "$(csv_escape "$name")" \
  "$(csv_escape "$note")"

id=2;   name='Bob';   note='He said "Good luck!"'
printf '%s,%s,%s\n' \
  "$(csv_escape "$id")" \
  "$(csv_escape "$name")" \
  "$(csv_escape "$note")"

補足(実務Tips)

  • 行末 \r が混ざるCSV(Windows由来)は、読み取り時に read -r しつつ上の実装のように \r を無視するか、事前に dos2unix 等で正規化すると安定します。
  • 完全なCSV互換(改行入りフィールドなど)を厳密にやるなら、mlr, awk(FPAT), python -c 'import csv' などの専用パーサを併用するのが安全です。

関連コマンド

  • echo : 変数やメッセージの出力
  • printf : 書式付きの出力
  • select : シェル組み込み、メニュー形式で選択を受け付け

備考

  • read は多くのシェル(bash, zsh, ksh, dash)において シェル組み込み コマンドです。
  • read で指定した変数は、そのシェルの環境でのみ有効。外部コマンドではありません。
  • パスワード入力のように非表示にする場合は -s を利用しますが、シェルの種類によって挙動が異なる場合があります。

参考

使い方のテクニック紹介

スポンサーリンク
Bash玄

はじめまして!Bash玄です。

エンジニアとしてシステム運用に携わる中で、手作業の多さに限界を感じ、Bashスクリプトを活用して業務を効率化したのがきっかけで、この道に入りました。「手作業は負け」「スクリプトはシンプルに」をモットーに、誰でも実践できるBashスクリプトの書き方を発信しています。

このサイトでは、Bashの基礎から実践的なスクリプト作成まで、初心者でもわかりやすく解説しています。少しでも「Bashって便利だな」と思ってもらえたら嬉しいです!

# 好きなこと
- シンプルなコードを書くこと
- コマンドラインを快適にカスタマイズすること
- 自動化で時間を生み出すこと

# このサイトを読んでほしい人
- Bashに興味があるけど、何から始めればいいかわからない人
- 定型業務を自動化したい人
- 効率よくターミナルを使いこなしたい人

Bashの世界に一歩踏み出して、一緒に「Bash道」を極めていきましょう!

Bash玄をフォローする

コメント