繁体   English   中英

awk打印行原样(带空格)

[英]awk print line as is (with spaces)

我试图根据特定条件修改一行,然后打印到新文件中。 不幸的是,文件必须对列之间的多个空格敏感。 典型的行如下所示:

ATOM     301 H    UREA    24    5.966    3.408    1.877   1.00   0.00 UREA  N

这是我使用的命令:

awk '{if ($4 == "UREA" && $2%2 == 1) sub("H","TH",$3);print $0;}' origin.dat > final.dat

基本上,我希望awk打印完全相同的行(具有相同的空格数),但要替换第三列。 它显示的是:

ATOM 301 TH UREA 24 5.966 3.408 1.877 1.00 0.00 UREA H

我知道我可以使用printf或很长的print statemnt,但是文件具有的列数可能很麻烦。 是否有一种优雅的方法可以照原样替换后打印行? 谢谢!

如果您修改位置参数,Awk将重新组装该行。 但是,如果它是具有固定宽度的列的文件,则您应该能够找出要修改的行中的哪些位置,因此您无需修改​​位置参数。

这不是特别优雅,但是可以保留您的间距:

awk '$4 == "UREA" && $2%2 == 1 { print substr($0, 1, 13) "TH" substr($0, 15) }'

如果您使用的是GNU awk (可能还有其他一些版本),则支持使用固定宽度字段而不是基于定界符的字段。 仔细阅读man awk以获取更多信息,但您的awk调用将类似于:

awk 'BEGIN{FIELDWIDTHS="10 5 8 3 ..."}{....}'

使用空格分隔的数字列表在程序的开头设置FIELDWIDTHS变量,会导致awk根据这些值而不是空格(或其他定界符)来分割每行...

编辑:这是一个使用原始数据的示例,尽管我不得不猜测某些字段宽度,因为问题没有指定它们,并且我懒于计算它们,假设键入的内容恰好代表实际数据...我已经假设所有空格都在前一个字段的后面,实际上可能并非如此...

$ echo "ATOM     301 H    UREA    24    5.966    3.408    1.877   1.00   0.00 UREA  N" |\
  awk 'BEGIN{OFS=""; FIELDWIDTHS="9 4 5 8 100"} $4 ~ /^UREA/ && $2 % 2 {sub("H ", "TH", $3); print}'
ATOM     301 TH   UREA    24    5.966    3.408    1.877   1.00   0.00 UREA  N

当您访问第三个字段$3 ,原始格式会丢失。 根据您其他字段中的值,以下方法可能会产生不希望的结果,但是解决问题的一种方法是对整个记录执行sub操作:

awk '$4=="UREA" && $2%2{sub(/H/,"TH");print}' file

请记住, sub仅执行一次替换,因此,如果第一列或第二列可以包含“ H”,则只会有副作用。 例如,根据awk的版本,您可以使用单词边界使正则表达式更具体。 请注意,我已经将/H/用作sub的第一个参数,而不是"H" ,因为这样可以避免将awk转换为正则表达式。

顺便说一句,我删除了您对if的用法,因为awk程序的结构是condition { action } 我还从您的条件中删除了== 1 ,因为数字% 2为true(1)或false(0)。

输出:

ATOM     301 TH    UREA    24    5.966    3.408    1.877   1.00   0.00 UREA  N

修改字段将导致使用OFS值作为分隔符来重新编译记录。 您需要修改整个记录,而不是使用RE间隔:

$ awk '$4=="UREA" && $2%2{$0=gensub(/((\S+\s+){2})\S+/,"\\1TH","")}1' file
ATOM     301 TH    UREA    24    5.966    3.408    1.877   1.00   0.00 UREA  N

上面的代码对gensub(),\\ S和\\ s使用GNU awk。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM