Awk

意外的拆分行為

  • November 27, 2018

我在這裡閱讀了有關 Awk 拆分行為的資訊:

$$ … $$split函式的fs參數(參見字元串函式)應被解釋為擴展的正則表達式。這些可以是ERE標記或任意表達式,並且應以與or運算符 右側相同的方式進行解釋。~``!~

和:

如果右手操作數是除詞法標記 ERE之外的任何表達式,則表達式的字元串值應被解釋為擴展的正則表達式,包括上述轉義約定。

http://pubs.opengroup.org/onlinepubs/9699919799/utilities/awk.html#tag_20_06_13_04

但是,我注意到了一個意外的結果,程式碼如下:

BEGIN {
 print split("te.st", q, ".")
}

我希望.代表任何字元,結果是6. 但是我所有的測試都返回了2。執行此程式碼給出了預期6

BEGIN {
 print split("te.st", q, /./)
}

經測試:

  • 呆呆
  • gawk –posix
  • 舊 1.3.4
  • 舊 1.3.3
  • nawk(原始 awk)

我誤解了文件還是這是一個錯誤?

這不是錯誤;只是在試圖編纂現有實踐時標準不夠明確。

mawk(1) 手冊更明確:

split(expr, A, sep)工作方式如下:

(2) 如果sep = " "(單個空格),<SPACE>則從 的前後修剪exprsep變為<SPACE>。mawk 定義 <SPACE>為正則表達式/[ \t\n]+/。否則sep被視為正則表達式,除了長度為 1 的字元串的元字元被忽略,例如, split(x, A, "*")並且split(x, A, /*/)是相同的。

此外,來自目前來源的 GNU awk 手冊:

split(s, a [, r [, seps] ])

拆分的行為與上述的欄位拆分相同。特別是,如果r是單字元字元串,則該字元串充當分隔符,即使它恰好是正則表達式元字元。

這是來自 susv4標準的描述:

擴展的正則表達式可用於分隔欄位,方法是直接或作為使用選項的結果將包含表達式的字元串分配給內置變數FS 。**FS-F sepstring變數的預設值應為單個<space>。以下描述了FS**行為:

  1. 如果FS為空字元串,則行為未指定。
  2. 如果FS單個字元

一種。如果FS是 <space>,跳過前導和尾隨 <blank> 和 <newline> 字元;欄位應由一組或多組 <blank> 或 <newline> 字元分隔。

灣。否則,如果FS是任何其他字元 c,則欄位應由每次出現的 c 分隔。 3. 否則,FS的字元串值應被認為是擴展的正則表達式。與擴展正則表達式匹配的序列的每次出現都應分隔欄位。

您的範例與 2.b 匹配。

即使明確提到FS,在所有 awk 實現中使用任何參數代替它作為第三個參數的行為也是相同的split,包括在該參數是空格的情況下。

行為不太可能改變,因為FS變數只是一個字元串(awk沒有正則表達式對象,例如javascriptor perl;您不能將正則表達式分配給變數,例如a=/./or $a=qr/./);它是split函式(隱式或顯式呼叫)確實解釋了它的參數,如上所述。

這種行為的起源可能是與“舊”awk 的兼容性,其中FS(或 的第三個參數split)始終被視為單個字元。範例(在 unix v7 上):

$ awk 'BEGIN{FS="."; print split("foo.bar.baz", a, "bar"); print a[2] }'
3
ar.
$ awk 'BEGIN{FS="."; print split("foo.bar.baz", a, /bar/); print a[2] }'
awk: syntax error near line 1
awk: illegal statement near line 1
Bus error - core dumped

引用自:https://unix.stackexchange.com/questions/483870