如何替换整个列而不丢失awk中的格式

如何替换整个列而不丢失awk中的格式,awk,replace,Awk,Replace,编者按: 这个问题有一个麻烦的编辑历史,因为一个善意但误导的编辑(引入了不相关的、依赖空格和|字符分隔列的“漂亮”格式)暂时混淆了这个问题(自恢复以来)。 OP的前提是输入是以制表符分隔的,即使这并没有直接反映在这里显示的示例输入中。 我有一个有6列的输入文件,它们是用制表符分隔的。我想用value'81115'替换第5列中的所有值,同时保持格式不变 输入文件: 203 ADD 24 IAC 81216

编者按
这个问题有一个麻烦的编辑历史,因为一个善意但误导的编辑(引入了不相关的、依赖空格和
|
字符分隔列的“漂亮”格式)暂时混淆了这个问题(自恢复以来)。
OP的前提是输入是以制表符分隔的,即使这并没有直接反映在这里显示的示例输入中。

我有一个有6列的输入文件,它们是用制表符分隔的。我想用value
'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  
203 ADD 24 IAC 81115 IT 

204 ATT 24 IAC 81115 IT 
所需的输出文件:

203           ADD              24       IAC              81216            IT     
204           ATT              24       IAC              81216            IT  
203           ADD              24       IAC              81115            IT  
204           ATT              24       IAC              81115            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              81216            IT     
204           ATT              24       IAC              81216            IT  
203           ADD              24       IAC              81115            IT  
204           ATT              24       IAC              81115            IT  
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

上述所有命令都保持格式不变,但在末尾添加了一个值为
81115
的新列;i、 例如,第7列被追加

输出文件:

203           ADD              24       IAC              81216            IT            81115

204           ATT              24       IAC              81216            IT            81115

有人能建议对上述命令的替代解决方案或更改吗

对于保留格式的列内更新,需要使用拆分功能。请注意,只有GNU awk才支持带有forth参数的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)#基于FS的分割
a[5]=“81115”#更新第5列
对于(i=1;i注:
-如果必须从输入中保留精确的分隔符字符串,并且您有GNU
awk
,请参阅,或者,有关涵盖所有字段的解决方案,请参阅。
-这将尝试诊断OP的问题,并包含一个解决方案,该解决方案将输入转换为一致的制表符分隔的输出

您的第一次尝试不会在输出中保留制表符,因为在没有设置OFS
的情况下,输出字段分隔符Awk会将每个输出字段分隔一个空格。
(通过分配给字段,就像您对
$5=…
所做的那样,使用
OFS
(默认为空格)的值作为分隔符,隐式地重新生成输入行,以将(修改过的)字段拼合在一起形成输出行。)

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

使用
cat-et
验证输入文件中的所有列是否确实由选项卡分隔:
^I
表示
cat-et
输出中的选项卡

如果您的输入文件包含由制表符和空格分隔的混合列和/或某些字段之间有多个制表符,您需要依靠
awk
的默认解析来按预期将输入拆分为字段,即通过任何非空空格。
然后,通过设置“仅限OFS”
,仅在输出上使用制表符作为分隔符:

awk -v replace='81115' -v OFS='\t' '{$5=replace}1' file
请注意,缺少
-F
选项,因此依赖于Awk的默认字段拆分行为


虽然这不一定会保持精确的输入格式,但您将获得一致的制表符分隔输出。

基于给定样本输入的最简单解决方案是使用
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 

类似的解决方案可用于具有
gensub
功能的
GNU awk

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 


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

请尝试:
awk-v new=“81115”'BEGIN{OFS=FS=“\t”}{$5=new}1'文件
您的所有解决方案#2版本在这里都可以正常工作。解决方案#1也可以,只需添加
-v OFS=“\t”
to it。我使用MAWK和GAWK进行了测试。测试您的输入文件是否真的是以制表符分隔的。alternate..
perl-pe的/^(\s+\s+{4}\K\S+/81115/'file>file.NEW
。或者如果第5列在文件中总是
81216
并且是唯一的,为什么不使用一个简单的
sed'S/81216/81115/'file>file.NEW
等等-你说你的字段是用制表符分隔的,但是你用
S和空格分隔。这是正确的吗?如果你的示例输入/输出是为了显示u这是您的文件在表格格式中的外观,而不是您的实际文件-不要这样做,请向我们显示实际文件,而不是它们的一些图形表示。如果这些确实是您的实际文件-您所说的分隔字段的选项卡在哪里?如果您的任何解决方案2脚本在行尾追加字段,则是因为e您的输入文件没有制表符分隔。@埃德蒙顿:完全同意您的看法,上次问题编辑导致了这种情况。我最初更新了问题,使其具有制表符分隔,并拒绝了当前存在的问题,但不知何故它进入了。请参阅此编辑历史++,但请添加一条说明,说明您的解决方案需要GNU
awk
(根据POSIX,
split()
函数不支持第4个参数,Mawk和BSD/macOS Awk都不支持该参数)。可以添加
gensub
相当于
sed-E/^((\s+\s+{4})\S+/\181115/'文件
要保留空格格式…@Sundeep:
gensub
需要GNU
awk
,如果你能使用它,那么@JayRajput的答案是最好的方法。我不太熟悉语法,但
awk'{$0=gensub(/^((\S+\S+{4})\S+/,“\\181115”,“g”,“$0)}1'文件
似乎比使用split@Sundeep:好的方面:您的解决方案更简单,而且似乎有效(除了我建议使用
“1”
而不是
“g”