エスケープシーケンスを評価するためにコマンドラインに引数を渡すことができますgawk
。
質問:
$ gawk 'BEGIN { print ARGV[1]; }' '\t'
\t
代わりに、実際のタブ文字を取得したいと思います。
~からgawk
文書:
文字列定数と正規表現定数の場合、前のリストのエスケープシーケンスは常に最初に処理されます。 awkがプログラムを読むと、非常に初期にこれが起こります。
コマンドライン引数で文字エスケープを解釈するには?
最終目標は、myscript.awk --sep '\t'
区切り文字がフォーマット文字列なので、リテラルタブを渡すことはオプションではありません。私もbashでこれを行う簡単な方法に精通していますが、[g]awkで行う方法に興味があります。
答え1
コマンドライン引数のエスケープされていないバージョンを印刷する方法は?
print ARGV[1]
問題は、エスケープされていないコマンドラインパラメータが必要ないことです。あなたはそれを説明したいと思います。 (2文字の文字列バックスラッシュ、小文字T)を渡し、\t
それをバックスラッシュに変換しようとしています。これは手動で行う必要があります。タブに変換するのは\t
簡単です。gsub(/\\t/, "\t")
ただし、8進数エスケープをサポートし、認識できない文字の前のバックスラッシュを削除したい場合は、これはawkで面倒です。
split ARGV[1], a, "\\";
s = a[1]; delete a[1];
for (x in a) {
if (skip_next) {
skip_next = 0;
} else if (x == "") {
s = s "\\";
skip_next = 1;
} else if (x ~ /^[0-7][0-7][0-7]/) {
s = s sprintf("%c", 64*substr(x,1,1) + 8*substr(x,2,1) + substr(x,3,1));
sub(/^.../, x);
} else if (x ~ /^[0-7][0-7]/) {
s = s sprintf("%c", 0 + 8*substr(x,1,1) + substr(x,2,1));
sub(/^../, x);
} else if (x ~ /^[0-7]/) {
s = s sprintf("%c", 0 + substr(x,1,1));
sub(/^./, x);
} else {
sub(/^a/, "\a", x) ||
sub(/^b/, "\b", x) ||
sub(/^n/, "\n", x) ||
sub(/^r/, "\r", x) ||
sub(/^t/, "\t", x) ||
sub(/^v/, "\v", x);
}
s = s x;
}
printf
(警告:テストされていないコード!)この複雑なコードを使用する代わりに、サブシェルから呼び出すことができます。文字列が複数行であっても、これは簡単ではありません。
s = ARGV[1]
gsub(/'/, "'\\''", s)
cmd = "printf %b '" s "'."
s = ""
while ((cmd | getline line) > 0) s = s line "\n"
sub(/..$/, "", s)
awkスクリプトを作成するときは、"\t"
これはタブ文字を含む文字列であることに注意してください。 awkの構文は次のとおりです。バックスラッシュは文字列リテラルで特別な意味を持ちます。注:文字列リテラル、一つでもないひも。文字列にバックスラッシュが含まれている場合、これは別の文字にすぎません。ソースコードスニペットは"\t"
4文字で構成され、値がタブ文字を含む単一文字文字列である式です。ソースコードの断片が2+2
3文字で構成され、値が数値の式であるのと同じです4
。
awkスクリプトでは、区切り文字パラメータをリテラル文字列として使用することをお勧めします。これにより、使いやすくなります。インタフェースでは、呼び出し側は引数からバックスラッシュをエスケープする必要があります。区切り文字をタブ文字として指定するには、実際のタブ文字を渡します。
答え2
まず、実際にタブをに渡しませんawk
。シェルが引数を評価することを覚えておいてください。今後これは引用符で渡され、awk
引用符'\t'
と\
リテラル内で評価されます\t
。
$ set -x
$ gawk 'BEGIN { print ARGV[1]; }' '\t'
+ gawk 'BEGIN { print ARGV[1]; }' '\t'
\t
上記のようにタブを渡さないため、gawk
タブが印刷されるとほとんど期待できません。これをタブを通過する以下のバージョンと比較してみてください。
$ gawk 'BEGIN { print ARGV[1]; }' "$(printf '\t')"
++ printf '\t'
+ gawk 'BEGIN { print ARGV[1]; }' ' ' ## note the tab
## This line contains a printed tab
あるいは、タブを変数として渡すこともできます。
gawk -v t='\t' 'BEGIN {print t}'
ここでは、'\t'
拡張はシェルではなくawkによって実行されるため、タブは正しく解釈されます。
答え3
解決策はを使用することですgetline
。
ファイルから:
BEGIN {
sep = ARGV[1]
gsub(/'/, "'\\''", sep);
gsub(/%/, "%%", sep);
"printf -- '" sep "'" | getline sep;
printf sep;
}