テキスト処理コマンド(ツール)のAWK(オーク)を勉強して、これまで疑問に思っていたことが解決しました。これで、少し賢くなりました。

1 文字列を1文字ずつに分解
学んだことは、AWKのフィールドセパレータ(フィールド区切り文字)についてです。
文字列の1文字ずつを区切って、それぞれをフィールドにできないだろうかというのが、これまでずっと抱いていた疑問です。私はその方法があることを知りませんでした。これが、あるんですねぇ。できるんですよ!
答えは、「カラ文字("")をフィールドセパレータにすればよい。」です。なるほど、ってなりました。方法があることが分かったので、うれしくなりました。
ところが、ここでつまづきました。実地にやってみると、できない、実行がされないのです。
あれこれともがき苦しんだ末に、生成AIのGeminiに相談しました。そうすると、実に明快な回答をしてくれました。そのすばらしい解説ぶり、理解しやすい説明に感心してしまいました。
そこで、私の質問と、Geminiの解説を、ここにそっくりそのまま掲載して、皆様にご紹介します。
2【Geminiへの質問】
AWKでフィールドセパレータを指定する-Fオプションの記述方法が、よく分かりません。
(1) $ echo "a:i:u:e:o" | awk -F":" '{print $2,$3}'
(2) $ echo "a:i:u:e:o" | awk -F ":" '{print $2,$3}'
上記(1)(2)どちらの記述でも実行できます。
つまり、Fの後ろの半角スペースの有無は影響しません。
ところが、
(3) $ echo "aiueo" | awk -F"" '{print $2,$3}'
(4) $ echo "aiueo" | awk -F "" '{print $2,$3}'
となると、Fの後ろの半角スペースの有無で結果が異なります。
(3)では実行されないのに対し、(4)では想定どおりの実行がされます。
つまり、Fの後ろの半角スペースが必要とされます。
これは、どういう理由からでしょうか。
3【Geminiの回答】
非常に鋭い着眼点ですね。 結論から申し上げますと、これはAWK自体の挙動というよりは、「シェル(Bashなど)がコマンドに引数を渡す際のルール」と「AWKが引数を解釈する順番」のミスマッチが原因です。
一言で言うと、(3)のケースでは「プログラムそのもの('{print ...}')が区切り文字として誤って解釈されてしまっている」ために実行されません。
なぜそうなるのか、シェルの裏側の動きを図解的に解説します。
原因のメカニズム
シェルがコマンドを実行する際、""(空のクォート)は「空文字」を意味しますが、シェルはこれを解釈した後、クォート自体を取り除いてコマンドに渡します。
【1】 成功するケース (4) -F "" の動き
コマンド: awk -F "" '{print $2,$3}'
この時、シェルは以下の 3つのパーツ に分けてAWKに渡します。
1 awk (コマンド)
2 -F (オプション)
3 (空文字:""の中身)
4 '{print $2,$3}' (プログラム)
AWKはこれを受け取り、以下のように解釈します。
・ 「お、-Fが来たな。次の引数を区切り文字にしよう」
・ → 次の引数は「空文字」だ。OK、区切り文字は「なし(1文字ずつ)」に設定する。
・ → その次の引数がプログラムだな。実行しよう。
・ 結果:成功
【2】 失敗するケース (3) -F"" の動き
コマンド: awk -F"" '{print $2,$3}'
ここで問題が起きます。シェルは -F"" を見ると、"" は「中身がない」ので消滅させ、前の文字と結合します。その結果、AWKに渡されるのは以下の 2つのパーツ だけになります。
1 awk (コマンド)
2 -F (オプション。「""」が消えて単なる -F だけが残る)
3 '{print $2,$3}' (プログラム)
AWKはこれを受け取り、以下のように解釈します。
・ 「お、-Fが来たな。次の引数を区切り文字に設定しなきゃ」
・ → (-Fの後ろに文字がくっついていないので、次のパーツを見に行きます)
・ → 「次の引数は '{print $2,$3}' だな。よし、これを区切り文字にしよう!」
・ → 「さて、プログラムを実行するか……あれ? もう引数がないぞ? プログラムはどこだ?」
・ 結果:エラー(または予期せぬ動作)
つまり、(3)では実行したいプログラムのコードが、区切り文字の設定として吸い込まれてしまっているのです。
補足:なぜ (1) -F":" は動くのか?
(1) の $ awk -F":" の場合、シェルはクォートを外して -F: というひとかたまりの文字列をAWKに渡します。
AWKのオプション解析ルールでは、「オプション文字(F)の直後に文字がある場合、それを値として採用する」という決まりがあります。 そのため、: が即座に区切り文字として認識され、後ろのプログラム部分には影響が出ないため、正常に動作します。
まとめ
・ -F の後ろに文字がある場合(例: -F:)
その文字が区切り文字になり、正常動作します。
・ -F の後ろが空文字の場合(例: -F"")
シェルが "" を消してしまうため、AWKは「-F だけ」を受け取ります。
AWKは「値が足りない」と判断し、次の引数(プログラム部分)を区切り文字として奪ってしまいます。
・ スペースを入れた場合(例: -F "")
「-F」と「空文字」が別々の引数として渡されるため、正しく空文字が区切り文字として認識されます。
別の書き方(推奨)
もし「空文字指定(1文字ずつ分割)」を、スペースの有無を気にせず安全に書きたい場合は、-v オプションを使って変数 FS (Field Separator) を直接指定する方法もおすすめです。
echo "aiueo" | awk -v FS="" '{print $2, $3}'
これなら、-F のスペース問題に悩まされることはありません。
それではまた次の記事で
goosyun
