在unix中,只修改大文件的一列,并保持字段分隔符不变

在unix中,只修改大文件的一列,并保持字段分隔符不变,unix,tabs,awk,field,Unix,Tabs,Awk,Field,我有一个很大的文件(超过10000列)。我想更改第二列中的3个条目,并保持其他内容不变,包括字段分隔符 例如: ab123\t123\t0.1 ab234\t120\t0.5 我想检查第二列是否有条目120,并将其更改为1201,其他内容保持不变 我试过awk。它可以正常工作,但会替换以空格分隔的选项卡 awk '{ if ( $2 == 120 ) { $2 = 1201 }; print}' file 如何在不丢失制表符分隔版本的情况下执行此操作?要将FS(字段分隔符)和OFS(输出字段

我有一个很大的文件(超过10000列)。我想更改第二列中的3个条目,并保持其他内容不变,包括字段分隔符

例如:

ab123\t123\t0.1
ab234\t120\t0.5
我想检查第二列是否有条目120,并将其更改为1201,其他内容保持不变

我试过awk。它可以正常工作,但会替换以空格分隔的选项卡

awk '{ if ( $2 == 120 ) { $2 = 1201 }; print}' file

如何在不丢失制表符分隔版本的情况下执行此操作?

要将
FS
(字段分隔符)和
OFS
(输出字段分隔符)设置为制表符:

awk '$2==120{$2=1201}1' FS='\t' OFS='\t' file
OFS
是这里的重要变量,因为
awk
使用它的值来分隔输出上的字段

编辑:

awk
的结构是
conditional{block}
,如果条件值为TRUE,则执行块。因此,使用
$2==120{$2=1201}
时,如果第二个字段是值120,而块是
{$2=1201}
则条件是
$2==120
,将值1201分配给第二个字段。
awk
中的默认块是
{print$0}
,因此:

awk '$2==120{$2=1201}{print $0}'
可以重新编写为:

awk '$2==120{$2=1201}1'
其中1是始终计算为TRUE的条件,因为我们没有指定块,所以执行默认的
{print$0}

对于多个条件,只需添加更多结构,即:

这更像是一种
if
if
结构,因为两个块都可以执行,而
if
else
将使用
next
语句跳转到文件中的下一行,即:

如果在这里执行第一个块,则第二个字段的值为1201,我们抓取下一行,否则第二个字段的值为1202。因此,第二个字段将始终采用新值,
1201
1202

一个
if
elif
将是:

awk '$2==120{$2=1201;next}$3==130{$3==1301}1'

在这里,第二个字段可能会接受一个新值,如果它接受了,第三个字段将不会被更新,即使条件为真,因为它永远不会被计算。只有当第一个条件为FALSE,第二个条件为TRUE时,才能更新第三个字段

谢谢@sudo_O,你能给我解释一下它的功能吗。我做什么?你不需要if条件吗?还有,我如何将其扩展到多个条件?类似于“if-else if”的东西?也是@sudo_O,有没有办法检查字段分隔符是否由制表符分隔,而不是目视检查?@user1007742我不太清楚你的意思,如果您想直观地看到文件中的选项卡,那么您可以执行
cat-T file
,这会将选项卡显示为
^I
。您好@sidharth c nadhan,谢谢。这不是在整个文件中搜索和替换,而不是只在第二列中搜索和替换吗?在regex中,120之前只允许有一组空格。这样可以确保它只替换第二列中的内容。
 sed -r 's/^ *[^ ]+ +120\b/\01/' file
awk '$2==120{$2=1201;next}$3==130{$3==1301}1'
 sed -r 's/^ *[^ ]+ +120\b/\01/' file