pslaboが試したことの記録

はてなダイヤリーからはてなブログに引っ越してきました

この日記は現在実行中の減量記録を含む個人的なメモとして始めましたが、最近はコンピュータやガジェット、ハック、セキュリティネタのほうがメインになっております。

はてなダイヤリー時代はカテゴリ分けが適当だったのですが、これはそのうち直します。


bash で URL をパースして連想配列に代入する

1年くらい前にこんなのを作っていたのですけど、これはちょいと使い勝手が良くない気がしました。抜き出したい部分が増えるたびに新しいシェル変数が必要です。

pslabo.hatenablog.com


これは楽しくないので、パースした結果を連想配列に入れるように作り変えてみました。

連想配列bash 4.x 以降が必要です。正規表現を使えばもっと短いコードで済むわけですが、あえて正規表現なしでやってみるとやはり大変でした。

#!/bin/bash

declare -A url_parse_array

url_parse_array=(
    ["scheme"]=""
    ["uid"]=""
    ["pass"]=""
    ["hostname"]=""
    ["port"]=""
    ["resource"]=""
    ["query"]=""
    ["fragment"]=""
)

parse_url() {

# URI         = scheme ":" hier-part [ "?" query ] [ "#" fragment ]

# hier-part   = "//" authority path-abempty
#             / path-absolute
#             / path-rootless
#             / path-empty

#  authority   = [ userinfo "@" ] host [ ":" port ]
#   userinfo    = *( unreserved / pct-encoded / sub-delims / ":" )
#   host        = IP-literal / IPv4address / reg-name
#   port        = *DIGIT

    local target=$1

    # scheme
    # 最初の : より前の部分を抜いている
    # scheme://userinfo@host:port/path?query#fragment
    #  -> scheme
    url_parse_array["scheme"]=${target%%:*}

    # uid:pass を抜く
    # まずは // より後ろの文字列を抜く
    # scheme://userinfo@host:port/path?query#fragment
    #  -> userinfo@host:port/path?query#fragment
    local uid_url=${target#*//}
    # 次に @ より前の部分を抜く。これに該当する文字列は UID:PASS のはず。
    # userinfo@host:port/path?query#fragment
    #  -> userinfo
    local uid_pass=${uid_url%%@*}

    # URL から authority (ホスト名、ポート、パスのかたまり)を抜く
    # @ 以降の文字がこれに該当する。
    # userinfo@host:port/path?query#fragment
    #  -> host:port/path?query#fragment
    local authority=${uid_url#*@}

    # host:port/path?query#fragment
    #  -> path?query#fragment
    local hierpart_query_fragment=${authority#*/}
    local hierpart_query=${hierpart_query_fragment%#*}
    url_parse_array["hierpart"]=${hierpart_query%\?*}
    local query_fragment=${hierpart_query_fragment#*\?}
    local fragment=${hierpart_query_fragment#*\#}
    local query

    if [ "${fragment}" == "${hierpart_query_fragment}" ]; then
        url_parse_array["fragment"]=""
        query=${hierpart_query_fragment#*\?}
        if [ "${query}" != "${url_parse_array['hierpart']}" ] ; then
            url_parse_array["query"]=${query}
        elif [ "${query}" != "${query_fragment}" ]; then
            url_parse_array["query"]=${query}
        fi
    else
        url_parse_array["fragment"]=${fragment}
        query=${query_fragment%#*}

        if [ "${query}" != "${url_parse_array['hierpart']}" ]; then
            url_parse_array["query"]=${query}
        fi
    fi


    # uid:pass から uid を抜く
    local uid=${uid_pass%%:*}
    if [ "$uid" != "$authority" ]; then
        url_parse_array["uid"]=${uid}
    fi

    local pass=${uid_pass##*:}

    # uid:pass から pass を抜く
    if [ "$uid" != "$pass" ]; then
        url_parse_array["pass"]=${pass}
    fi

    # ホスト名を抜く(ホスト+ポートを取り出して、そこからホスト名だけ取り出す)
    local hostname_port=${authority%%/*}
    url_parse_array["hostname"]=${hostname_port%%:*}

    # ポート番号を抜く
    local port=${hostname_port#*:}
    if [ ${url_parse_array["hostname"]} != "$port" ]; then
        url_parse_array["port"]="$port"
    fi
}

parse_url $1

echo ${url_parse_array["scheme"]}
echo ${url_parse_array["uid"]}
echo ${url_parse_array["pass"]}
echo ${url_parse_array["hostname"]}
echo ${url_parse_array["port"]}
echo ${url_parse_array["hierpart"]}
echo ${url_parse_array["query"]}
echo ${url_parse_array["fragment"]}