【问题标题】:How to right pad a field with spaces using AWK如何使用 AWK 用空格右填充字段
【发布时间】:2018-06-23 19:06:35
【问题描述】:

我有一个文件,我正试图从使用 AWK 中删除客户名称。 该文件是一个固定宽度的文件,每一列都有含义。

该文件由多行组成,格式相同,与以下非常相似:

1234-123   123456 12345678901234CUSTOMER NAME TO REMOVE12345-1234 TRN   123-123   12345678901-1234  TRN 12345678        
1234-123   123456 12345678901234CUSTOMER NAME TO REMOVE12345-1234 TRN   123-123   12345678901-1234  TRN 12345678        
1234-123   123456 12345678901234CUSTOMER NAME TO REMOVE12345-1234 TRN   123-123   12345678901-1234  TRN 12345678        
1234-123   123456 12345678901234CUSTOMER NAME TO REMOVE12345-1234 TRN   123-123   12345678901-1234  TRN 12345678

我需要用一个假想的名称交换客户名称,以便所需的输出是:

1234-123   123456 12345678901234SENTINAL PRIME         12345-1234 TRN   123-123   12345678901-1234  TRN 12345678        
1234-123   123456 12345678901234OPTIMUS PRIME          12345-1234 TRN   123-123   12345678901-1234  TRN 12345678        
1234-123   123456 12345678901234BUMBLE BEE             12345-1234 TRN   123-123   12345678901-1234  TRN 12345678        
1234-123   123456 12345678901234IRON HIDE              12345-1234 TRN   123-123   12345678901-1234  TRN 12345678

我有一个我想使用的转换器名称列表,存储在一个名为 transformer.names 的文件中。

SENTINEL PRIME
OPTIMUS PRIME
BUMBLEBEE
IRONHIDE

但是,为了使原始文件的每一行保持相同的宽度,我需要用空格右填充变压器名称,因为我拥有的变压器名称都是不同的长度。

似乎可以使用 AWK 将这些名称正确填充到一定长度,但我还没有设法弄清楚(或找到足够清晰的答案)让我理解。

以下是我当前的 AWK 脚本。

#!/usr/bin/awk -f
BEGIN {
}
{
  getline line < "transformer.names"
  print substr($0, 0, 30) line substr($0, 62, 120)
}

我用这个命令运行它:

my_program.awk my-file.txt

我想我可以用这样的一行来代替上面的打印行,但是我还没有设法让它工作。

printf "-%32s|", substr($0, 0, 30) line substr($0, 62, 120)

任何提示都会很棒!

【问题讨论】:

  • 能否请您提供更多示例以供输入,这将有助于我们为您提供帮助。
  • 完成。干杯:)

标签: awk


【解决方案1】:

您需要将%Ns 应用于您想要填充的特定字段而不是整行,并且您需要将减号(用于leftpad / rightalign)作为说明符的一部分,并且printf 不会自动添加print 这样的行/记录分隔符,因此您需要添加:

 printf "%s%-32s%s\n", substr($0, 1, 30), newname, substr($0, 62, 120)
 # note commas; this is a format string containing three specifiers, 
 # and separate three data values used for those three specifiers

或者,您可以填充字段并然后连接:

 print substr($0,1,30) sprintf("%-32s", newname) substr($0,62,120) 
 # no commas except within the sprintf (and the substr's) 

如果您的数据文件的行数比“transformernames”文件的行数多,那么您需要缓冲名称并反复循环它们,如 Ravinder 所示。

另外,substr awk 中的位置从 1 开始;如果您指定 0 或负数,则将其视为 1,但我认为实际说出您的意思更清楚,所以我修复了这个问题。 62 不是您发布的示例数据中客户名称后面部分的正确起始位置,但您说数据仅与真实数据“非常相似”,所以我不知道是 56 还是 62 或其他是正确的。

【讨论】:

    【解决方案2】:

    您能否尝试关注并让我知道这是否对您有帮助。因此,它将具有所有转换器名称,并且假设它的值小于 Input_file 行,那么它将阻止打印行开始。

    awk '
    FNR==NR{
      a[FNR]=$0;
      count=FNR;
      next}
    {
      val=val==count?1:++val;
      print substr($0,1,32) a[val]"\t\t"substr($0,56)
    }' transformer.names  Input_file
    

    解释:现在也为上面的代码添加解释。

    awk '
    FNR==NR{                                          ##Checking condition here FNR==NR which will be TRUE when first Input_file is being read.
      a[FNR]=$0;                                      ##Creating an array named a whose index is FNR and value is current line.
      count=FNR;                                      ##Creating variable count whose value is FNR value(current line number value of first Input_file).
      next}                                           ##next will skip further statements from here onward.
    {                                                 ##This block will execute when 2nd Input_file is being read.
      val=val==count?1:++val;                         ##Creating variable val whose value is increment each time and when it is equal to count it is set to 1 then.
      print substr($0,1,32) a[val]"\t\t"substr($0,56) ##Printing sub-string from 1 to 32 chars, value of a[val] TABs then sub-string from 56 char to till last of line.
    }' transformer.names  Input_file                  ##Mentioning Input_file(s) name here.
    

    【讨论】:

    • 谢谢,我一定会的!你能描述代码的关键部分是如何工作的吗?对于刚进入这个领域的人来说,这并不直观。
    • 选项卡仅适用于某些输出设备,并且当字段结束列是 8 的倍数并且替换值的长度变化不超过 7 时。
    【解决方案3】:

    您要修改的文本之前的数据似乎不是大写字母。
    所以你可以试试这个 awk。

    awk '
    FNR==NR {
      a[NR]=$0
      b=length()
      len = len < b ? b : len
      next
    }
    {
      c = sprintf( "%-*2$s" , a[FNR], (len+1))
      sub(/[A-Z][A-Z ]+/,c)
    }
    1' transformer_name customer_name
    

    首先,我们将所有的转换器名称放入数组 a 中,并将较大的长度放入 len 在我们用新名称替换所有旧名称后,调整 c 中的格式。
    您可以根据需要修改 (len+1)。

    【讨论】:

    • 抱歉 - 这是误导。我在问题中修复了它。
    【解决方案4】:
    #!/usr/bin/awk -f
    BEGIN {
    }
    {
      getline line < "transformer.names"
      printf("%s %-32s %s \n", substr($0, 0, 30), line, substr($0, 62, 120))
    }
    

    您的问题几乎已经有了答案!我只是复制了你的并稍作修改:)

    【讨论】:

      猜你喜欢
      • 2023-03-30
      • 2018-06-13
      • 1970-01-01
      • 2012-10-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-29
      相关资源
      最近更新 更多