如何在不丢失awk

时间:2016-08-25 09:58:34

标签: awk replace

编者注:
这个问题有一个困难的编辑历史,因为一个善意但误导的编辑(它引入了无关的,“漂亮的”格式依赖于空格和|字符来分隔列)暂时混淆了这个问题(自恢复后)。
OP的前提是输入是 tab -delimited,即使它没有直接反映在此处显示的示例输入中。 功能

我有一个包含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

有人可以建议替代解决方案或更改上述命令吗?

3 个答案:

答案 0 :(得分:1)

对于保留格式的列内更新,您需要使用拆分功能。请注意,只有GNU awk支持带有第四个参数的split函数。

试试这个:

 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 :(得分:0)

注意:
- 如果必须保留输入中的完全分隔符字符串,则 GNU awk,请参阅@Sundeep's helpful answer,或者,对于涵盖所有字段的解决方案,请参阅Jay Rajput's helpful answer - 答案尝试诊断OP的问题,并包含一个解决方案,将输入转换为一致的制表符分隔输出。

您的第一次尝试不会保留输出中的标签,因为在没有设置OFS输出字段分隔符的情况下,Awk将分隔输出字段空间每个。
(通过分配到字段,就像使用$5 = ...一样,输入行是隐式重建,使用OFS的值(空格)默认情况下)作为分隔符将(修改的)字段重新组合在一起以形成输出行。)

您的其他尝试看起来都很合理,这表明您的输入文件的结构可能不像您认为的那样。

使用cat -et验证输入文件中的所有列确实是由每个标签分隔开来的:^I代表cat -et输出中的标签。

如果您的输入文件包含 mix 的制表符和空格分隔列和/或某些字段之间有多个制表符你需要依靠awk默认解析来按预期将输入分成字段,即任何非空白空格。<登记/> 然后仅使用OFS >将标签用作 on output 的分隔符:

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

请注意缺少-F选项,以便依赖Awk的默认字段拆分行为。

虽然这不一定能保持确切的输入格式,但您将获得始终制表符分隔的输出。

答案 2 :(得分:0)

基于给定样本输入的最简单的解决方案是使用sed进行简单搜索和替换,假设第5列只有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 

或者使用变量,

UPDATE table_1
SET col_1 = 
      CASE WHEN table_1.col_pk IS NULL THEN value1
           ELSE value2
      END
FROM table_1
LEFT JOIN table_2 ON table_1.col_pk = table_2.col_pk


以上所有解决方案都保留了输入文件空间格式