OFS の値を区切り記号として使用して awk がレコードを再コンパイルしない限り、フィールドに値を割り当てることはできません。代わりに、正規表現を使用してレコード全体を記述し、関心のあるフィールドが存在する場所に存在するレコードの一部を置き換えます。たとえば、GNU awk を使用する場合 (他の awk では、match()/substr() および [[:space:]] を使用):
$ cat foo
foo bar quux # single space, single tab
foo bar quux # single space, double space, triple space
$ awk '{ print gensub(/^(\s*(\S+\s+){1})\S+(.*)/,"\\1blah\\3","") }' foo
foo blah quux # single space, single tab
foo blah quux # single space, double space, triple space
置き換えたいフィールドの前にある多くのフィールドに合わせて1
inを変更します。{1}
$ awk '{ print gensub(/^(\s*(\S+\s+){2})\S+(.*)/,"\\1blah\\3","") }' foo
foo bar blah # single space, single tab
foo bar blah # single space, double space, triple space
$ awk '{ print gensub(/^(\s*(\S+\s+){3})\S+(.*)/,"\\1blah\\3","") }' foo
foo bar quux blah single space, single tab
foo bar quux blah single space, double space, triple space
gawk には、split() のように機能する patsplit() という名前の関数も含まれていますが、結果の文字列にフィールドを格納するだけでなく、フィールド間のスペースも 2 番目の配列に格納するため、これらの配列でループを使用して取得できます。それがより明確な場合は、元のスペース:
$ awk '{ nf = patsplit($0,fld,/\S+/,sep); fld[2]="blah"; for (i=1;i<=nf;i++) printf "%s%s", sep[i-1], fld[i]; print "" }' foo
foo blah quux # single space, single tab
foo blah quux # single space, double space, triple space
$ awk '{ nf = patsplit($0,fld,/\S+/,sep); fld[3]="blah"; for (i=1;i<=nf;i++) printf "%s%s", sep[i-1], fld[i]; print "" }' foo
foo bar blah # single space, single tab
foo bar blah # single space, double space, triple space
patsplit() が各レコードを分割する方法は次のとおりです。
$ awk '{ nf = patsplit($0,fld,/\S+/,sep); print "\n" $0; for (i=0;i<=nf;i++) print "<" i ":" fld[i]
":" sep[i] ">" }' foo
foo bar quux # single space, single tab
<0::>
<1:foo: >
<2:bar: >
<3:quux: >
<4:#: >
<5:single: >
<6:space,: >
<7:single: >
<8:tab:>
foo bar quux # single space, double space, triple space
<0:: >
<1:foo: >
<2:bar: >
<3:quux: >
<4:#: >
<5:single: >
<6:space,: >
<7:double: >
<8:space,: >
<9:triple: >
<10:space:>