bashの組み込みTCPソケット(/dev/tcp)でポート疎通確認とHTTP監視を実装するシェルスクリプト設計

宮崎智広 この記事の監修:宮崎智広(Linux実務・教育歴20年以上・受講者3,100名超)
HOME > Linux技術 リナックスマスター.JP(Linuxマスター.JP) > シェルスクリプト > bashの組み込みTCPソケット(/dev/tcp)でポート疎通確認とHTTP監視を実装するシェルスクリプト設計
シェルスクリプトからTCP接続で死活監視したいのに、curlが入っていない、netcatもない、telnetも削除されている——最小構成のコンテナや、パッケージマネージャを使えない本番サーバーの復旧作業では、外部コマンドに頼れない場面があります。

bash には /dev/tcp という組み込みのソケット機能があり、外部コマンドなしにTCP接続の確立とデータの送受信ができます。curl も nc も telnet も不要で、bash が動く環境であれば使えます。

この記事では、/dev/tcp の使い方から、タイムアウト付きポート疎通確認、HTTP GETによるステータスコード取得、複数ホスト一括監視スクリプトの設計まで、RHEL 9.4 / Rocky Linux 9.3 での実行例を交えて解説します。

この記事のポイント

・/dev/tcp/ホスト/ポート へのリダイレクトでTCP接続を確立し、外部コマンド不要でポート疎通確認できる
・exec {FD}<>/dev/tcp/ホスト/ポート でFDを開き、printf/read でHTTP GETを送受信できる
・タイムアウトは timeout コマンドまたは read -t N で制御する
・curl/nc/telnet がない最小コンテナや復旧作業中のサーバーで特に有用


「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

/dev/tcpとは何か(bash組み込みのソケット通信機能)

/dev/tcp は bash に組み込まれた仮想デバイスファイルです。実際にはファイルシステム上に存在しませんが、bash がリダイレクト先として認識し、TCP接続を確立するソケットとして機能します。

記法は /dev/tcp/ホスト/ポート番号 です。たとえば /dev/tcp/192.0.2.10/443 とすると、bash がそのホストのポート443番にTCP接続を試みます。同様に /dev/udp も存在しますが、UDP は接続確立の確認ができないため、疎通確認には /dev/tcp が主に使われます。

利用できる条件
・bash 2.04 以降で使用可能(RHEL 7/8/9・Ubuntu 20.04以降はすべて対応)
・コンパイル時の --disable-net-redirections オプションで無効化されている場合は使えません(標準パッケージでは有効です)
・dash / sh(POSIX sh)では使えません。スクリプトの先頭は #!/bin/bash である必要があります

/dev/tcpでポート疎通確認を実装する基本

1. 最もシンプルな疎通確認(1行)

# 書式: echo > /dev/tcp/<ホスト>/<ポート> # 疎通できれば終了コード 0、できなければ非0 echo > /dev/tcp/192.0.2.10/443 echo $? # 0(接続成功) echo > /dev/tcp/192.0.2.10/9999 echo $? # 1(接続失敗:ポートが開いていない)

echo の出力先(標準出力)を /dev/tcp/ホスト/ポート にリダイレクトすることで、TCP 3ウェイハンドシェイクを試みます。接続確立の成否だけを確認する場合はこの1行で十分です。

2. 終了コードと if 文を使った疎通確認

実際のスクリプトでは、接続結果に応じて処理を分岐させます。

#!/bin/bash HOST="192.0.2.10" PORT=443 if echo > /dev/tcp/"$HOST"/"$PORT" 2>/dev/null; then echo "[OK] $HOST:$PORT は接続可能です" else echo "[NG] $HOST:$PORT に接続できません" >&2 fi

2>/dev/null でエラーメッセージ(bash: connect: Connection refused 等)を捨てています。判定には終了コードだけを使うため、出力を抑制してもロジックに影響はありません。

3. 実サーバーでの動作確認(RHEL 9.4)

[root@sv-prod-01 ~]# echo > /dev/tcp/sv-web-01.example.com/80 2>/dev/null && echo "OK" || echo "NG" OK [root@sv-prod-01 ~]# echo > /dev/tcp/sv-web-01.example.com/9999 2>/dev/null && echo "OK" || echo "NG" NG [root@sv-prod-01 ~]# echo > /dev/tcp/192.0.2.99/22 2>/dev/null && echo "OK" || echo "NG" NG

ポート80(HTTP)は到達可能、9999番は閉鎖、192.0.2.99は到達不可という結果です。

タイムアウト付きポート確認の設計

/dev/tcp の接続試行は、デフォルトでは OS の TCP タイムアウト(通常75秒~)まで待ち続けます。監視スクリプトで使う場合は必ずタイムアウトを設定してください。

1. timeoutコマンドを使う方法(最も簡単)

#!/bin/bash HOST="192.0.2.10" PORT=443 TIMEOUT=3 # 3秒でタイムアウト if timeout "$TIMEOUT" bash -c "echo > /dev/tcp/"$HOST"/"$PORT"" 2>/dev/null; then echo "[OK] $HOST:$PORT (timeout=${TIMEOUT}s)" else EXIT_CODE=$? if [ "$EXIT_CODE" -eq 124 ]; then echo "[TIMEOUT] $HOST:$PORT はタイムアウトしました" >&2 else echo "[NG] $HOST:$PORT に接続できません" >&2 fi fi

timeout コマンドの終了コードは 124 がタイムアウト、それ以外の非0が接続失敗です。この区別を判定ロジックに組み込むことで、「タイムアウト(ネットワーク遅延・フィルタリング)」と「即時拒否(ポートが閉じている)」を切り分けられます。

2. exec + FDを使うタイムアウト設計(外部コマンド完全不要)

timeout コマンドも使えない場合は、exec でFDを開きながら read -t でタイムアウトを設定する方法があります。

#!/bin/bash tcp_check() { local host="$1" local port="$2" local timeout="${3:-3}" # FDを開く(exec が成功すれば接続確立) exec {FD}<>"/dev/tcp/$host/$port" 2>/dev/null || return 1 # 何か送信してサーバー応答を read で一行読む(タイムアウト付き) read -r -t "$timeout" -u "$FD" response 2>/dev/null || true exec {FD}>&- # FDを閉じる return 0 } if tcp_check "192.0.2.10" 80 3; then echo "[OK] 接続成功" else echo "[NG] 接続失敗またはタイムアウト" >&2 fi

この方法では exec {FD}<>/dev/tcp/... が成功すれば接続確立(= ポートが開いている)を意味します。読み取りはオプションで、SSH や HTTP サーバーのバナー取得にも使えます。

/dev/tcpでHTTP GETを送信してレスポンスを確認する

ポートが開いているだけでなく、HTTP の応答コード(200 OK / 500 Internal Server Error 等)まで確認したい場合は、/dev/tcp に HTTP リクエストを直接送信できます。

#!/bin/bash http_status_check() { local host="$1" local port="${2:-80}" local path="${3:-/}" local timeout="${4:-5}" # TCP接続確立(FDを双方向で開く) exec {FD}<>"/dev/tcp/$host/$port" 2>/dev/null || { echo "[NG] 接続失敗: $host:$port" >&2 return 1 } # HTTP GET リクエストを送信(HTTP/1.0 はレスポンス後に接続を閉じる) printf "GET %s HTTP/1.0 Host: %s Connection: close " "$path" "$host" >&"$FD" # レスポンスの1行目(ステータスライン)を読む read -r -t "$timeout" -u "$FD" status_line 2>/dev/null exec {FD}>&- # 改行コードを除去してステータスコードを取得 status_line="${status_line%$' '}" local status_code status_code=$(echo "$status_line" | awk '{print $2}') echo "[INFO] $host:$port$path -> HTTP $status_code ($status_line)" # 200番台であれば正常 if [[ "$status_code" =~ ^2 ]]; then return 0 else return 1 fi } http_status_check "sv-web-01.example.com" 80 "/health"

[root@sv-prod-01 ~]# bash http_check.sh [INFO] sv-web-01.example.com:80/health -> HTTP 200 (HTTP/1.1 200 OK) [root@sv-prod-01 ~]# echo $? 0

curl が使える場合は curl のほうが簡単ですが、最小環境でのヘルスチェックスクリプトを1本にまとめたい場合に有効です。

複数ホスト・複数ポートを一括監視するスクリプト設計

実務では複数サービスを定期的に確認したいケースが多いです。ポート疎通確認と内部リンクを組み合わせた設計例を示します。

#!/bin/bash set -euo pipefail TIMEOUT=3 LOG_FILE=/var/log/port_check.log check_port() { local host="$1" local port="$2" local label="$3" local ts ts=$(date '+%Y-%m-%d %H:%M:%S') if timeout "$TIMEOUT" bash -c "echo > /dev/tcp/"$host"/"$port"" 2>/dev/null; then echo "$ts [OK] $label ($host:$port)" | tee -a "$LOG_FILE" else echo "$ts [NG] $label ($host:$port)" | tee -a "$LOG_FILE" >&2 fi } # 監視対象一覧 check_port "sv-db-01.example.com" 3306 "MySQL" check_port "sv-web-01.example.com" 80 "HTTP" check_port "sv-web-01.example.com" 443 "HTTPS" check_port "sv-cache-01.example.com" 6379 "Redis" check_port "sv-mq-01.example.com" 5672 "RabbitMQ"

[root@sv-prod-01 ~]# bash /usr/local/bin/port_check.sh 2026-09-27 10:30:01 [OK] MySQL (sv-db-01.example.com:3306) 2026-09-27 10:30:01 [OK] HTTP (sv-web-01.example.com:80) 2026-09-27 10:30:02 [OK] HTTPS (sv-web-01.example.com:443) 2026-09-27 10:30:04 [NG] Redis (sv-cache-01.example.com:6379) 2026-09-27 10:30:04 [OK] RabbitMQ (sv-mq-01.example.com:5672)

tee -a でターミナル出力とログ記録を同時に行います。cron に登録する場合は MAILTO=root と組み合わせると NG 行を管理者メールに通知できます。

nc・curl・telnetとの使い分け

/dev/tcp はシェル組み込みの機能であるため、外部コマンドがない環境で強みを発揮します。一方で用途によって使い分けが必要です。
Linuxで使えるポート確認コマンドの全体像については、Linux ポート確認の全コマンドで詳しく解説しています。
方法 主な用途 外部コマンド HTTPS対応
/dev/tcp ポート疎通確認・HTTP通信(bash組み込み) 不要 不可(TLS非対応)
nc(netcat) ポート疎通・データ転送・バナー取得 必要 nc -zs(一部対応)
curl HTTPステータス確認・API呼び出し 必要 可(--insecure も可)
telnet テキストプロトコルの手動確認 必要(非推奨) 不可
openssl s_client TLS/SSL接続・証明書確認 必要 可
/dev/tcpを優先すべき場面
・コンテナイメージを最小サイズに保ちたい(追加パッケージをインストールしたくない)
・復旧作業中でパッケージマネージャが使えない状態
・デプロイスクリプトの中で外部依存なしにヘルスチェックを行いたい

curl/ncを優先すべき場面
・HTTPS(TLS)でのステータス確認が必要な場合
・レスポンスボディの解析が必要な場合
・通常の監視スクリプトで外部コマンドが使える場合(curl の方が可読性が高い)

本記事のまとめ

/dev/tcp は bash 組み込みのソケット機能で、外部コマンドなしにTCPポートの疎通確認と簡単なHTTP通信が実現できます。curl や nc に頼れない最小環境・復旧作業中のサーバーで特に威力を発揮します。
やりたいこと コマンド・書き方
ポート疎通確認(1行) echo > /dev/tcp/ホスト/ポート 2>/dev/null
タイムアウト付き確認 timeout 3 bash -c "echo > /dev/tcp/..."
FDを開いて読み書き exec {FD}<>/dev/tcp/ホスト/ポート
HTTP GETでステータス取得 printf "GET / HTTP/1.0 ..." >&$FD
FDを閉じる exec {FD}>&-
接続確認の分岐 if timeout N bash -c ... 2>/dev/null; then
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、/dev/tcp を活用したポート監視・デプロイスクリプト設計など実務で役立つシェルスクリプト設計を体系的に学べるシェルスクリプト実践ガイドもぜひご覧ください。
>> シェルスクリプト実践ガイドを見る

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録
宮崎 智広

この記事を書いた人

宮崎 智広(みやざき ともひろ)

株式会社イーネットマーキュリー代表。現役のLinuxサーバー管理者として20年以上の実務経験を持ち、これまでに累計3,100名以上のエンジニアを指導してきたLinux教育のプロフェッショナル。「現場で本当に使える技術」を体系的に伝えることをモットーに、実践型のLinuxセミナーの開催や無料マニュアルの配布を通じてLinux人材の育成に取り組んでいる。

趣味は、キャンプにカメラ、トラウト釣り。好きな食べ物は、ラーメンにお酒。休肝日が作れない、酒量を減らせないのが悩み。最近、ドラマ「フライトエンジェル」を観て涙腺が崩壊しました。