如何使用 AWK 右键单击带有空格的字段



我有一个文件,我正在尝试从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)

任何提示都太棒了!

您需要将%Ns应用于要填充的特定字段而不是整行,并且您需要使减号(用于左垫/右对齐(成为说明符的一部分,并且printf不会像print那样自动添加行/记录分隔符,因此您需要添加:

printf "%s%-32s%sn", 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所示。

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

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

awk '
FNR==NR{
a[FNR]=$0;
count=FNR;
next}
{
val=val==count?1:++val;
print substr($0,1,32) a[val]"tt"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]"tt"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.
#!/usr/bin/awk -f
BEGIN {
}
{
getline line < "transformer.names"
printf("%s %-32s %s n", substr($0, 0, 30), line, substr($0, 62, 120))
}

你的问题几乎有答案!我只是复制了你的并对其进行了一点修改:)

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

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(。

或者只使用FS并跳过substr()调用:

mawk 'NF *=(__=FNR)==NR ? (___[__]=$_)*_ : (OFS=sprintf("%-24s",___[__]))^_'
FS='CUSTOMER NAME TO REMOVE' 
<( echo 'SENTINEL PRIME
OPTIMUS PRIME
BUMBLEBEE
IRONHIDE') -
<小时 />
1234-123   123456 12345678901234SENTINEL 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 12345678901234BUMBLEBEE               12345-1234 TRN   123-123   12345678901-1234  TRN 12345678        
1234-123   123456 12345678901234IRONHIDE                12345-1234 TRN   123-123   12345678901-1234  TRN 12345678

这是一个使用column为您执行所有右填充数学运算的解决方案 - 如果您的输入数据突然改变长度,但不能满足输出线长度与原始线长度匹配的OP要求,则非常方便:

cat my-file.txt | 
awk '{getline line < "transformer.names"; 
print substr($0, 0, 30) line "|" substr($0, 62, 120)}' | 
column -s'|' -t

可以使用gsubcolumn的组合,而无需抓取子字符串(或知道它们的长度(。

cat my-file.txt | 
awk -v pipe='|' 
'{getline line < "transformer.names"; 
gsub("CUSTOMER NAME TO REMOVE",line pipe,$0); 
print $0}' | 
column -s'|' -t

这里 ^ 我们在awk中创建一个名为pipe的变量,将其放置在替换gsub( ... line pipe ....)内,然后将其用作稍后column的分量仪。管道的使用是任意的。我们可以用星号(星号(做完全相同的事情:

cat my-file.txt | 
awk -v star='*' 
'{getline line < "transformer.names"; 
gsub("CUSTOMER NAME TO REMOVE",line star,$0); 
print $0}' | 
column -s'*' -t

最新更新