0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Gawk で通信する

0
Posted at

Gawk で通信する

AWK はテキストを加工するコマンドとして知られていますが、Gawk ならネットワーク通信もできます。

この記事の内容は次のとおりです。

  1. Gawk の通信は簡単
  2. HTTP なら簡単だが、現在は HTTPS が主流なので工夫が必要

筆者の環境は

cat /etc/os-release
PRETTY_NAME="Ubuntu 24.04.4 LTS"
NAME="Ubuntu"
VERSION_ID="24.04"
VERSION="24.04.4 LTS (Noble Numbat)"
VERSION_CODENAME=noble
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=noble
LOGO=ubuntu-logo

Gawk のネットワーク機能

この機能はGNU拡張です

Gawk では、ネットワーク接続の設定をネットワーク特殊ファイル名として記述します。

TCP 接続の書式は次のとおりです。

/inet/tcp/ローカルポート/接続先ホスト/接続先ポート

たとえば、ローカルホストの18080番ポートへ接続する場合は、次のように書きます。

socket = "/inet/tcp/0/127.0.0.1/18080"

ここでわかりにくいのは 0 でしょう。クライアント側のローカルポートに0を指定すると、空いているポートを OS が自動的に選びます。

この文字列は実際のファイルパスではありません。Gawk が文字列の形式を認識し、内部でソケットを作成します。

|& で送受信する

この機能はGNU拡張です

Gawk では、双方向通信に |& 演算子を使います。

送信は次のように書きます。

print "送信する文字列" |& socket

受信には getline を組み合わせます。

socket |& getline reply
print reply

まとめると、最小限の通信処理は次の形になります。

BEGIN {
    socket = "/inet/tcp/0/127.0.0.1/18080"

    print "hello" |& socket
    fflush(socket)

    if ((socket |& getline reply) > 0)
        print reply

    close(socket)
}

fflush(socket) は、出力バッファーに残っているデータをすぐに送信するための処理です。

例:メトロポリタン美術館 API を叩く

実用的な例として、API を叩いて情報を得るタスクを紹介します。

HTTP/1.x はテキストと解釈できるプロトコルです。HTTP リクエストを文字列として組み立て、送信する能力が Gawk にはあります。

現在の Web API の多くは HTTPS を使用しています。そのため、対応する必要があります。

HTTPS は、HTTP 通信を TLS で保護したものです。TLS には、通信内容の暗号化、改ざん検出、接続先サーバーの確認といった役割があります。

Gawk の /inet/tcp は TCP 通信を扱えますが、TLS を直接処理しません。そのため、HTTPS の API へ接続するときは、TLS を扱える別のプログラムを中継させます。

今回は socat を使います。

socat は、TCP 、 UDP 、ファイル、標準入出力、 TLS 接続など、二つのデータ経路を双方向に接続するコマンドです。

まず、別のターミナルで次の socat コマンドを起動しておきます。socat は終了せずに待ち受け続けるため、そのターミナルは開いたままにします。その後、別のターミナルから gawk スクリプトを実行します。

# 筆者の環境は Ubuntu
socat \
    TCP-LISTEN:18080,bind=127.0.0.1,reuseaddr,fork \
    OPENSSL:collectionapi.metmuseum.org:443,verify=1,snihost=collectionapi.metmuseum.org,cafile=/etc/ssl/certs/ca-certificates.crt

一例として、メトロポリタン美術館の葛飾北斎の作品の情報を得るスクリプトを書きます。

get_hokusai.awk
BEGIN {
    api_host = "collectionapi.metmuseum.org"
    proxy_host = "127.0.0.1"
    proxy_port = 18080
    path = "/public/collection/v1/objects/45434"

    socket = "/inet/tcp/0/" proxy_host "/" proxy_port

    # 読み取りタイムアウトは10秒
    PROCINFO[socket, "READ_TIMEOUT"] = 10000

    request = \
        "GET " path " HTTP/1.0\r\n" \
        "Host: " api_host "\r\n" \
        "User-Agent: gawk-example/1.0\r\n" \
        "Accept: application/json\r\n" \
        "Accept-Encoding: identity\r\n" \
        "Connection: close\r\n" \
        "\r\n"

    printf "%s", request |& socket
    fflush(socket)

    body_started = 0
    status_code = 0

    while ((result = (socket |& getline line)) > 0) {
        # HTTP の行末に含まれる CR を削除
        sub(/\r$/, "", line)

        if (!body_started) {
            if (line ~ /^HTTP\//) {
                status_line = line
                split(line, fields, /[[:space:]]+/)
                status_code = fields[2] + 0
            } else if (line == "") {
                # ヘッダー後の空行を検出
                body_started = 1
            }

            continue
        }

        # HTTP 本文だけを標準出力へ送る
        print line
    }

    if (result < 0) {
        print "受信エラー:", ERRNO > "/dev/stderr"
        close(socket)
        exit 1
    }

    close(socket)

    if (status_code < 200 || status_code >= 300) {
        print "HTTP エラー:", status_line > "/dev/stderr"
        exit 22
    }
}

次のような結果が返ってきます。

# gawk -f get_hokusai.awk | jq . のように jq を使うと見やすい
{
  "objectID": 45434,
  "isHighlight": false,
  "accessionNumber": "JP1847",
  "accessionYear": "1929",
  "isPublicDomain": true,
  "primaryImage": "https://images.metmuseum.org/CRDImages/as/original/DP130155.jpg",
  "primaryImageSmall": "https://images.metmuseum.org/CRDImages/as/web-large/DP130155.jpg",
# 以下略
}

Link

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?