2013-11-25 135 views
0
awk -i inplace ' 
    BEGIN {FS=" "} 
    BEGINFILE {changed=0} 
    { print;if ($1 == "namespace" && !changed) {print "foo";changed=1} } 
' * 

有沒有更優雅的方式來做到這一點?我錯過了一些內置的構造?我正在運行GNU Awk 4.1.0(我非常喜歡-i就地)。awk每個文件更改一次

+0

你可以肯定地寫它使其稍短,但我想邏輯會是類似的。 – devnull

+0

我對短版本很好奇。我總是渴望學習:) – chx

回答

1
awk -i inplace '$1=="namespace" && !seen[ARGIND]++ {$0=$0 ORS "foo"} 1' * 

FS=" "是默認的,沒有必要明確指定它。

+1

這非常棘手。 ARGIND是文件名ARGV中的索引,因此它對每個文件進行更改,並且我假定一個未初始化的變量是空的,否定它變爲真,ish,遞增和否定將是false-ish,因此每個文件確實觸發一次。 – chx

+0

這不是棘手,只是習慣用法。以這種方式使用一個名爲'seen []'的數組是一種非常常見的AWK習慣用法,它只能在第一次出現任何東西時進行操作。是的,ARGIND是當前正在處理的文件的ARGV數組中的僅有gawk的索引。您可以使用FILENAME,但如果同一個文件在arg列表中多次出現,則會有不同的語義。 'seen [x] ++'是自從'seen [x]'開始爲'zero-or-null'以來第一​​次被評估爲false',然後後遞增,因此隨後的每一次'seen [x] ++'都是真的。 '!seen [x] ++'是相反的 - 真正的第一次然後是假的。 –

1

你可以說:

... -F' ' '$1 == "namespace" && !a {$0=$0 RS "foo";a=1}1' file 

甚至:

... -F' ' '$1 == "namespace" && !_ {$0=$0 RS "foo";_=1}1' file 

如上評論中提及,這是非常類似你寫不同的是它採用了可變RS什麼插入文本。


爲了給多個文件做到這一點,你需要重新設置變量:

​​

... -F' ' 'FNR==1 {a=0} $1 == "namespace" && !a {$0=$0 RS "foo";a=1}1' * 
+0

我看到了,您正在使用[表達式模式](http://www.gnu.org/software/gawk/manual/gawk.html#Expression-Patterns),它們對我而言是新的。但是最後的結果是什麼? – chx

+1

OMG 1是一個表達式,模式可以是空的?所以這基本上是'{print}'的縮寫。超級棘手。 – chx

+0

@chx右'1'是'print'的縮寫。您可能也會看到一些使用'42'的! – devnull