2016-08-25 9 views
4

編者按
這個問題有一個陷入困境的編輯歷史善意的,但誤導編輯(其中引進無關,「漂亮」格式依託在空格和|字符分隔列)暫時混淆了這個問題(自恢復)。
OP的前提是輸入是選項卡 -delimited,即使這並不直接反映在此處顯示的示例輸入中。
如何在沒有在AWK不失格式替換整列

我有一個輸入文件有6列,它們是製表符分隔的。我想用值'81115'替換第5列中的所有值,同時保持格式不變。

輸入文件:

203   ADD    24  IAC    81216   IT  
204   ATT    24  IAC    81216   IT 

所需的輸出文件:

203   ADD    24  IAC    81115   IT 
204   ATT    24  IAC    81115   IT 

我的解決方案#1

我使用下面的命令:

awk '{$5 = v} 1' v="81115" file > file.NEW 

使用上述命令,第5列正在被替換,但列不再以製表符分隔。

輸出文件:

203 ADD 24 IAC 81115 IT 

204 ATT 24 IAC 81115 IT 

我的解決方案#2

爲了保持我曾嘗試使用下面的命令試圖格式化:

awk -v replace="81115" -F '\t' -v OFS='\t' {$5=replace}1' file > file.NEW 

OR

awk -F"\t" -v OFS="\t" '{$5=81115}1' file > file.NEW 

OR

awk -F '\t' '{$5="81115";}1' OFS='\t' file > file.NEW 

以上所有的命令都保持格式不變,但與在端值81115添加新柱;即列7被追加。

輸出文件:

203   ADD    24  IAC    81216   IT   81115 

204   ATT    24  IAC    81216   IT   81115 

任何人都可以提出一個替代的解決方案或改變上述命令?

+1

嘗試:'awk -v new =「81115」'BEGIN {OFS = FS =「\ t」} {$ 5 = new} 1'file' – sat

+4

您所有的解決方案#2版本都可以在這裏使用。解決方案#1也可以,只需添加'-v OFS =「\ t」'。我使用MAWK和GAWK進行了測試。測試你的輸入文件是否真的是製表符分隔的。 –

+0

alternate ..'perl -pe's/^(\ S + \ s +){4} \ K \ S +/81115 /'file> file.NEW' ..或者如果第五列始終是'81216'且在文件,爲什麼不是一個簡單的'sed's/81216/81115 /'file> file.NEW' – Sundeep

回答

1

對於保留格式的列內更新,您需要使用拆分功能。請注意,具有第四個參數的拆分函數僅受GNU awk支持。

試試這個:

awk '{split($0, a, FS, seps)   # split based on FS 
     a[5]="81115";     # Update the 5th column 
     for (i=1;i<=NF;i++)    # print the data back 
     printf("%s%s", a[i], seps[i]) # keeping the separators 
     print ""}'      # print a new line 

一行代碼:

awk '{split($0, a, FS, seps); a[5]="81115"; for (i=1;i<=NF;i++) printf("%s%s", a[i], seps[i]); print ""}' /tmp/data 

幸得https://stackoverflow.com/a/39326264/2032943

+1

++,但請添加註釋,說明您的解決方案需要_GNU_ awk(每個POSIX,'split()'函數不支持第四個參數,Mawk和BSD/macOS Awk都不支持它)。 – mklement0

+1

用該建議更新了答案。 –

0

注:
- 如果您必須保留從確切分隔字符串輸入您有GNUawk,請參閱@Sundeep's helpful answer,或者對於覆蓋全部字段的解決方案,請參見Jay Rajput's helpful answer
- This answers試圖診斷OP的問題,幷包含一個解決方案,將輸入轉換爲一致的製表符分隔的輸出。

你的第一個嘗試輸出不保留標籤,因爲,在沒有設置OFS的,輸出字段分隔符,awk中由空間每個分離輸出領域。
(通過分配到字段,因爲你與$5 = ...做,輸入線是隱含重建,使用的OFS值(默認的空間)作爲分隔符拼湊的(經修飾)字段回到一起,以形成輸出線。)

你其他的嘗試都顯得合理,這表明輸入文件可能不被結構化的,你覺得是這樣。

使用cat -et來驗證你的輸入文件中的所有列確實是每個製表符分隔:^I代表的cat -et輸出選項卡。

如果輸入文件包含製表符和空間(S)的混合 - 分隔欄和/或如果某些字段多個標籤他們之間,你需要依靠awk默認解析按照預期將輸入拆分爲字段,即通過任意運行非空白空格
然後你使用標籤作爲分隔符僅輸出,通過設置OFS

awk -v replace='81115' -v OFS='\t' '{$5=replace}1' file 

請注意沒有-F選項,以便依靠awk的默認現場分裂行爲。

雖然這不一定會保持確切的輸入格式,但您將獲得一致製表符分隔的輸出。

+0

可能會加上''sed -E's/^((\ S + \ s +){4})\ S +/\ 181115 /'文件'的'gensub'等同於保留空間格式... – Sundeep

+0

@Sundeep:'gensub '需要_GNU_'awk',如果你可以使用它,那麼@ JayRajput的答案是最好的方法。 – mklement0

+1

我對語法不是很熟悉,但'awk'{$ 0 = gensub(/ ^((\ S + \ s +){4})\ S + /,「\\ 181115」,「g」,$ 0)}'文件似乎比使用拆分更簡單 – Sundeep

0

基於給定的樣本輸入的最簡單的解決方案是一個簡單的搜索和使用sed,其中假定第五列具有唯一的81216相同值替換和值不1-4列的任何地方發生

$ sed 's/81216/81115/' file 
203   ADD    24  IAC    81115   IT  
204   ATT    24  IAC    81115   IT 


如果在第5列的任何值已被替換,

sed -E 's/^((\S+\s+){4})\S+/\181115/' file 

如果\s\S無法識別,使用

sed -E 's/^(([^[:space:]]+[[:space:]]+){4})[^[:space:]]+/\181115/' file 


類似的解決方案可以用GNU awk可以使用其具有gensub功能

awk '{$0 = gensub(/^((\S+\s+){4})\S+/, "\\181115", "1", $0)}1' file 

或者與可變的,

awk -v replace='81115' '{$0 = gensub(/^((\S+\s+){4})\S+/, "\\1"replace, "1", $0)}1' file 


所有上述解決方案保存輸入文件空間格式化