[英]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.