Linuxで16進数と文字列を相互変換する方法|xxd・echo・printfで簡単に

Linux

Linuxを使っていて 「16進数(hex)を文字列に変換したい」 「文字列を16進数表記にしたい」 と思ったことはありませんか?

  • バイナリファイルをデバッグするとき
  • ネットワークプロトコルのデータを確認するとき
  • 文字コードの問題を切り分けたいとき

など、Linuxで16進数⇔文字列の変換は意外と出番が多いです。

この記事では、xxdechoprintf などを使って、Linuxで16進数と文字列を簡単に変換する方法をわかりやすく解説します。

スポンサーリンク

16進数と文字列変換の基本概念

なぜ16進数変換が必要?

バイナリデータの可視化

  • バイナリファイルは直接読めないため、16進数で内容を確認
  • ネットワークパケットの中身を解析
  • メモリダンプの内容確認

文字コードの調査

  • 文字化けの原因特定
  • エンコーディング方式の確認
  • バイト単位でのデータ比較

デバッグとトラブルシューティング

  • プログラムが出力する生データの確認
  • ファイル形式の検証
  • データ破損の有無チェック

16進数表現の基本

ASCII文字の16進数例:

  • ‘A’ = 0x41 (65)
  • ‘a’ = 0x61 (97)
  • ‘0’ = 0x30 (48)
  • スペース = 0x20 (32)
  • 改行 = 0x0A (10)

日本語文字の例(UTF-8):

  • ‘あ’ = 0xE3 0x81 0x82
  • ‘ん’ = 0xE3 0x82 0x93

文字列を16進数に変換する方法

xxdコマンドを使う方法

最もシンプルな変換:

echo -n "hello" | xxd -p

出力例:

68656c6c6f

オプションの詳細:

  • -n:echoが末尾に改行をつけないオプション
  • -p:16進数をプレーン形式(アドレス情報なし)で出力

日本語の変換例:

echo -n "こんにちは" | xxd -p

出力例:

e38193e38293e381abe381a1e381af

より詳細な表示形式

標準のxxd表示(アドレス付き):

echo -n "hello world" | xxd

出力例:

00000000: 6865 6c6c 6f20 776f 726c 64              hello world

16バイトごとに改行(デフォルト):

echo -n "This is a longer text for demonstration" | xxd

出力例:

00000000: 5468 6973 2069 7320 6120 6c6f 6e67 6572  This is a longer
00000010: 2074 6578 7420 666f 7220 6465 6d6f 6e73   text for demons
00000020: 7472 6174 696f 6e                          tration

printf と od を組み合わせる方法

od コマンドによる16進数表示:

printf "hello" | od -An -tx1

出力例:

 68 65 6c 6c 6f

オプションの説明:

  • -An:アドレス表示なし
  • -tx1:1バイトずつ16進数で表示

文字も同時に表示:

printf "hello" | od -tx1z

出力例:

0000000 68 65 6c 6c 6f                                   >hello<

hexdump コマンドを使う方法

hexdump による表示:

echo -n "hello" | hexdump -C

出力例:

00000000  68 65 6c 6c 6f                                    |hello|
00000005

カスタム形式での表示:

echo -n "hello" | hexdump -e '1/1 "%02x"'

出力例:

68656c6c6f

16進数を文字列に変換する方法

xxd -r による逆変換

基本的な逆変換:

echo -n "68656c6c6f" | xxd -r -p

出力:

hello

日本語の逆変換:

echo -n "e38193e38293e381abe381a1e381af" | xxd -r -p

出力:

こんにちは

echo -e によるエスケープシーケンス

\xXX 形式による変換:

echo -e "\x68\x65\x6c\x6c\x6f"

出力:

hello

改行文字も含む例:

echo -e "\x48\x65\x6c\x6c\x6f\x0a\x57\x6f\x72\x6c\x64"

出力:

Hello
World

printf による精密な制御

printf での16進数変換:

printf "\x68\x65\x6c\x6c\x6f\n"

変数を使った動的変換:

hex_string="68656c6c6f"
printf "${hex_string}" | xxd -r -p

実践的な活用例

ファイル全体の16進数変換

バイナリファイルを16進数表示:

xxd sample.bin

出力例:

00000000: 7f45 4c46 0201 0100 0000 0000 0000 0000  .ELF............
00000010: 0300 3e00 0100 0000 1010 0000 0000 0000  ..>.............

ファイルサイズが大きい場合の部分表示:

# 最初の64バイトのみ表示
xxd -l 64 large_file.bin

# 特定の位置から表示
xxd -s 100 -l 32 large_file.bin

16進数ファイルからバイナリファイルの復元

xxd形式のファイルから復元:

xxd -r hexdump.txt > restored.bin

プレーン16進数から復元:

xxd -r -p plain_hex.txt > restored.bin

ネットワークパケット解析

tcpdump出力の16進数部分を抽出:

# TCPパケットの16進数データ
echo "474554202f20485454502f312e310d0a486f73743a206578616d706c652e636f6d0d0a0d0a" | xxd -r -p

出力:

GET / HTTP/1.1
Host: example.com

Wiresharkからコピーした16進数データの変換:

# スペース区切りの16進数を処理
echo "47 45 54 20 2f 20 48 54 54 50" | tr -d ' ' | xxd -r -p

URL エンコード/デコード

URLエンコードされた文字列の解析:

# %E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF を変換
echo "E381AEE38293E381ABE381A1E381AF" | xxd -r -p

文字列からURLエンコード用の16進数生成:

echo -n "こんにちは" | xxd -p | sed 's/../%&/g'

出力:

%e3%81%93%e3%82%93%e3%81%ab%e3%81%a1%e3%81%af

文字エンコーディングとの組み合わせ

異なる文字エンコーディングでの変換

Shift_JIS エンコーディング:

echo -n "こんにちは" | iconv -f UTF-8 -t SHIFT_JIS | xxd -p

EUC-JP エンコーディング:

echo -n "こんにちは" | iconv -f UTF-8 -t EUC-JP | xxd -p

16進数からShift_JISに変換:

echo -n "82b1828293c982bf82cd82cd" | xxd -r -p | iconv -f SHIFT_JIS -t UTF-8

Base64との組み合わせ

文字列 → 16進数 → Base64:

echo -n "hello" | xxd -p | xxd -r -p | base64

Base64 → 16進数 → 文字列:

echo "aGVsbG8=" | base64 -d | xxd -p

高度な変換テクニック

スクリプトによる自動変換

hex_convert.sh(汎用変換スクリプト):

#!/bin/bash
# 16進数と文字列の相互変換スクリプト

show_help() {
    cat << EOF
使用法: $0 [オプション] <入力>

オプション:
    -s, --string-to-hex    文字列を16進数に変換
    -h, --hex-to-string    16進数を文字列に変換
    -f, --file             ファイルを処理
    --help                 このヘルプを表示

例:
    $0 -s "hello"          # 文字列を16進数に変換
    $0 -h "68656c6c6f"     # 16進数を文字列に変換
    $0 -f -s file.txt      # ファイル内容を16進数に変換
EOF
}

string_to_hex() {
    if [ "$FILE_MODE" = true ]; then
        xxd -p "$1" | tr -d '\n'
    else
        echo -n "$1" | xxd -p
    fi
    echo
}

hex_to_string() {
    if [ "$FILE_MODE" = true ]; then
        xxd -r -p "$1"
    else
        echo -n "$1" | xxd -r -p
    fi
    echo
}

# オプション解析
MODE=""
FILE_MODE=false

while [[ $# -gt 0 ]]; do
    case $1 in
        -s|--string-to-hex)
            MODE="s2h"
            shift
            ;;
        -h|--hex-to-string)
            MODE="h2s"
            shift
            ;;
        -f|--file)
            FILE_MODE=true
            shift
            ;;
        --help)
            show_help
            exit 0
            ;;
        -*)
            echo "未知のオプション: $1"
            show_help
            exit 1
            ;;
        *)
            break
            ;;
    esac
done

# 実行
case "$MODE" in
    "s2h")
        string_to_hex "$1"
        ;;
    "h2s")
        hex_to_string "$1"
        ;;
    *)
        echo "モードを指定してください (-s または -h)"
        show_help
        exit 1
        ;;
esac

大量データの効率的な処理

大きなファイルの部分的な変換:

# ファイルの特定部分(100バイト目から200バイト)を16進数表示
dd if=large_file.bin bs=1 skip=100 count=200 2>/dev/null | xxd

ストリーミング処理:

# パイプラインでの連続処理
tail -f logfile | xxd -p | while read hex; do
    echo "Hex: $hex"
    echo -n "$hex" | xxd -r -p
    echo "---"
done

正規表現との組み合わせ

16進数パターンの抽出:

# ログファイルから16進数パターンを抽出
grep -o '[0-9a-fA-F]\{2,\}' logfile.txt | while read hex; do
    echo "Found hex: $hex"
    echo -n "$hex" | xxd -r -p 2>/dev/null && echo
done

特定パターンの検索と変換:

# HTTPヘッダーの16進数表現を検索
echo "474554202f20485454502f312e31" | xxd -r -p | grep -o "HTTP/[0-9]\.[0-9]"

トラブルシューティング

よくあるエラーと対処法

不正な16進数文字列:

# エラーが発生する例
echo "invalid_hex" | xxd -r -p

# 有効な16進数かチェック
if [[ "$hex_string" =~ ^[0-9a-fA-F]+$ ]]; then
    echo -n "$hex_string" | xxd -r -p
else
    echo "無効な16進数文字列: $hex_string"
fi

文字エンコーディングの問題:

# 文字化けが発生した場合
echo -n "問題の文字列" | xxd -p
# → 出力された16進数を別のエンコーディングで試す
echo -n "e5958fe9a18c" | xxd -r -p | iconv -f UTF-8 -t SHIFT_JIS

改行文字の処理:

# 改行を含む変換
echo "hello world" | xxd -p  # 改行も16進数化される

# 改行を除去して変換
echo -n "hello world" | xxd -p  # 改行なしで変換

パフォーマンス最適化

大きなファイルの効率的な処理:

# バッファサイズを指定して高速化
xxd -l 1048576 large_file.bin  # 1MBずつ処理

# 並列処理
split -b 1M large_file.bin chunk_
for chunk in chunk_*; do
    xxd "$chunk" > "${chunk}.hex" &
done
wait

まとめ

基本コマンドまとめ

文字列 → 16進数:

echo -n "text" | xxd -p

16進数 → 文字列:

echo -n "hex" | xxd -r -p

ファイル全体の変換:

xxd filename.bin                # ファイルを16進数表示
xxd -r hexfile.txt > binary.bin  # 16進数ファイルをバイナリに復元

実用的な応用例

デバッグとトラブルシューティング:

  • バイナリファイルの内容確認
  • ネットワークパケットの解析
  • 文字エンコーディングの問題調査

データ処理と変換:

  • URLエンコード/デコードの補助
  • 異なる文字エンコーディング間の変換
  • Base64との組み合わせ処理

システム管理:

  • ログファイルの解析
  • 設定ファイルのバイナリ部分確認
  • メモリダンプの分析

重要なポイント

文字エンコーディングの注意:

  • UTF-8、Shift_JIS、EUC-JPなどで16進数表現が異なる
  • 文字化けが発生した場合は、エンコーディングを確認

改行文字の扱い:

  • echo -n で改行を除去
  • printf で厳密な制御
  • 改行文字も16進数で確認可能

効率性の考慮:

  • 大きなファイルは部分的に処理
  • ストリーミング処理の活用
  • 並列処理による高速化

これらの知識があれば、Linuxでの16進数と文字列の変換を自在に操れるようになります。

ログ解析、ネットワークデバッグ、文字化け調査など、様々な場面でぜひ活用してみてください!

コメント

タイトルとURLをコピーしました