You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

按参考行格式对齐文本列的AWK实现问题求助

问题描述

有一个以单个空格分隔列的文本文件,示例内容如下:

ATOM 9803 C2' 5AD 303 72.790 69.600 43.700 +0.140 0.00 PROT C 0
ATOM 9804 H2'' 5AD 303 73.450 68.960 44.300 +0.090 0.00 PROT H 0
ATOM 15 HE1 MET 1 110.230 70.830 15.490 +0.090 0.00 PROT H 0 
ATOM 16 HE2 MET 1 111.230 72.300 15.480 +0.090 0.00 PROT H 0
ATOM 17 HE3 MET 1 112.070 70.760 15.610 +0.090 0.00 PROT H 0
ATOM 24 CB GLU 2 107.460 66.320 18.200 -0.180 0.00 PROT C 0 
ATOM 251 HB1 GLU 2 106.550 65.940 17.700 +0.090 0.00 PROT H 0

需要按照以下参考行指定的列间距整理列:

AAAA  9999  AAAA  AAA 999      99.999   99.999  99.999 +9.999 9.99      AAAA A 9

最终期望输出:

ATOM  9803  C2'   5AD 303      72.790   69.600  43.700 +0.140 0.00      PROT C 0 
ATOM  9804  H2''  5AD 303      73.450   68.960  44.300 +0.090 0.00      PROT H 0 
ATOM  15    HE1   MET 1        110.230  70.830  15.490 +0.090 0.00      PROT H 0    

尝试的AWK脚本无法正常工作,会用参考行内容替换所有原行内容,脚本如下:

reference_line="AAAA  9999  AAAA  AAA 999      99.999   99.999  99.999 +9.999 9.99      AAAA A 9"

awk -v ref_line="$reference_line" '
    BEGIN { OFS = "" }
    NR == 1 { print; next }
    {
        for (i = 1; i <= NF; i++) {
            if (i == 2) {
                $i = substr(ref_line, 11, 5)
            } else if (i == 3) {
                $i = substr(ref_line, 17, 4)
            } else if (i == 4) {
                $i = substr(ref_line, 22, 4)
            } else if (i == 6) {
                $i = substr(ref_line, 32, 5)
            } else if (i == 7) {
                $i = substr(ref_line, 39, 7)
            } else if (i == 8) {
                $i = substr(ref_line, 47, 8)
            } else if (i == 9) {
                $i = substr(ref_line, 56, 8)
            } else if (i == 10) {
                $i = substr(ref_line, 65, 8)
            } else if (i == 11) {
                $i = substr(ref_line, 74, 8)
            } else if (i == 12) {
                $i = substr(ref_line, 83)
            }
        }
        print
    }' out.txt > rearranged_out.txt
解决方案

原脚本错误地用参考行的子串覆盖了原字段内容,正确的做法是根据参考行定义的列宽,将原字段格式化到对应宽度后拼接。以下是修正后的AWK脚本:

awk '
BEGIN {
    # 参考行对应的格式化模板,每个格式符对应一列的宽度和对齐方式
    fmt = "%-6s%-6s%-6s%-5s%-8s%-9s%-9s%-9s%-9s%-8s%-5s%-2s%s\n"
}
{
    # 按模板格式化当前行的所有字段
    printf fmt, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13
}' out.txt > rearranged_out.txt

脚本说明

  • 格式化模板fmt中的每个%-Ns表示左对齐(-)、占N个字符宽度的字符串:
    • %-6s:对应第1、2、3列,占6字符宽度(含后续空格)
    • %-5s:对应第4列,占5字符宽度
    • %-8s:对应第5、10列,占8字符宽度
    • %-9s:对应第6-9列,占9字符宽度
    • %-5s:对应第11列,占5字符宽度
    • %-2s:对应第12列,占2字符宽度
    • %s:对应最后一列,直接输出内容
  • 用printf按模板输出每行,确保列间距和参考行完全一致。

内容的提问来源于stack exchange,提问作者Gilli

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 16:35:54