在awk中打印所有剩余的变量

3

我正在尝试编写一个快速的awk脚本,将这种格式的行转换为:

AAAA BBBB CCCC DDDD...

为了

CCCC AAAA BBBB DDDD...

这是我的脚本:
{ printf "%s %s %s %s", $3, $1, $2, $4 };

这个方法在原始输入行中有超过4个标记时会出现问题,此时第5个及其后面的标记不会被打印出来。
我查看了一些答案,例如 Using awk to print all columns from the nth to the last,但它们依赖于将变量设置为"",如果稍后重新使用这些变量,可能会导致问题。
是否有一种简单的方法可以将$4替换为类似于"从$4到行末的子字符串"的内容?

1
可能是重复的问题:使用awk从第n列打印到最后一列 - Lynn
@Mauris 这是那个问题的副本,但那个问题中的所有答案都至少有些麻烦,大多数会不必要地添加和/或删除空格,并且它们在一般情况下都是错误的,因为您只想将记录的结尾按原样打印。 - Ed Morton
4个回答

6

在这个简单的情况下,你所需要的只有:

$ awk '{t=$3; $3=$2; $2=$1; $1=t}1' file
CCCC AAAA BBBB DDDD

在GNU awk中,通常使用gensub()函数来处理\s\S

$ awk '{print $3, $1, $2, gensub(/^\s*(\S+\s+){3}/,"","")}' file
CCCC AAAA BBBB DDDD
gensub()函数只会跳过前三个字段,而从那一点开始保留所有字段及其间的空格。
$ cat file
AAAA BBBB CCCC DDDD    EEEE    FFFF  GGGG

$ awk '{print $3, $1, $2, gensub(/^\s*(\S+\s+){3}/,"","")}' file
CCCC AAAA BBBB DDDD    EEEE    FFFF  GGGG

你可以使用 match()+substr() 与其他 awk 命令实现相同的功能:

$ awk '{match($0,/^[[:space:]]*([^[:space:]]+[[:space:]]+){3}/); print $3, $1, $2, substr($0,RLENGTH+1)}' file
CCCC AAAA BBBB DDDD    EEEE    FFFF  GGGG

您可以使用sub()函数和一个变量:

$ awk '{x=$0; sub(/^[[:space:]]*([^[:space:]]+[[:space:]]+){3}/,"",x); print $3, $1, $2, x}' file
CCCC AAAA BBBB DDDD    EEEE    FFFF  GGGG

4

虽然不算“容易”,但也并不太难:

{  printf "%s %s %s ", $3, $1, $2;
   for (i=4; i<= NF; ++i) {
       printf "%s ", $i;
   }
   printf "\n";
}

另一种稍微更聪明的方法:

{ N3 = $3; N2 = $2; N1 = $1;  // capture the fields
  $1 = N3; $2 = N1; $3 = N2;  // reorder the fields
  print;  // print the whole record
}

4

使用 for 循环:

{ printf("%s %s %s", $3, $1, $2); 
  for (i = 4; i <= NF; i++) printf("%s ", $i); 
  printf("\n"); 
}

0

Perl:

perl -lane '($F[0], $F[2]) = ($F[2], $F[0]); print "@F"' file

虽然这个答案可能是正确和有用的,但最好您同时解释它如何帮助解决问题。如果未来出现任何更改(可能无关),导致它停止工作并且用户需要了解它曾经如何工作,那么这就变得尤为重要了。 - Kevin Brown-Silva

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接