使用awk打印除第一个字段以外的所有内容

150

我有一个长这样的文件:

AE  United Arab Emirates
AG  Antigua & Barbuda
AN  Netherlands Antilles
AS  American Samoa
BA  Bosnia and Herzegovina
BF  Burkina Faso
BN  Brunei Darussalam

我想反转顺序,先打印除 $1 以外的所有内容,然后是 $1:

United Arab Emirates AE

如何实现“除了第一个字段之外的所有内容”?


2
嗨@cfisher,可以不用循环和额外的空间来完成。 - Juan Diego Godoy Robles
1
问题的表述有点误导性。我的建议是:“如何在awk中将第一个字段移动到最后一个位置”。 - Juan Diego Godoy Robles
17个回答

142

$1="" 留下了一个空格,如Ben Jackson所提到的,因此使用一个 for 循环:

$1="" 留有一个空格,根据Ben Jackson的建议,可以使用一个 for 循环:

awk '{for (i=2; i<=NF; i++) print $i}' filename

如果你的字符串是"one two three",输出结果将为:

two
three

如果你想要结果在一行中显示,可以按照以下方式操作:

awk '{for (i=2; i<NF; i++) printf $i " "; print $NF}' filename
这将给你: "two three"。

4
和一个额外的尾随空格 - NeronLeVelu
3
最好使用以下命令:awk '{for(i=2;i<=NF;i++){ printf("%s",( (i>2) ? OFS : "" ) $i) } ; print ;}'。它会打印第2个到最后一个字段,并根据需要添加输出字段分隔符(即,在$2之前除外)。最后一个print语句会在当前行打印结束时添加换行符。如果更改FS/OFS,该命令也可以正常工作(即,它不总是“空格”)。 - Olivier Dulac
1
第二个对我来说非常好用。第一个不太行。不太确定为什么。它把整个文本都切成了碎片。 - voices
应该将 printf $i " " 更改为 printf "%s ", $i。否则,如果您的列中的数据意外包含 printf 格式字符串(如 %s、%i 等),它将会出现错误!是的,这确实发生在我身上 ;) - void256

121

可以使用awk '{first = $1; $1 = ""; print $0, first; }'来赋值$1,但会留下一个前导空格。

你还可以通过NF找到列数并在循环中使用。


Thyag:为了消除前导空格,在命令的末尾添加sed

awk {'first = $1; $1=""; print $0'}|sed 's/^ //g'

2
对于那些非常懒的人,这里是 klashxx 的代码 - Serge Stroobandt
3
好的。使用sed去掉了行首的空格:awk {'first = $1; $1=""; print $0'}|sed 's/^ //g' - Thyag
在正常模式下,使用VIM按下“Ctrl+V Gd”可以轻松删除空格。 - Santi
2
要删除前导空格,您也可以使用 gsub:awk '/>/ {first = $1; $1=""; gsub(/^ /,""); print $0, first}' somefile - Salix

88

使用-f 2-(POSIX)或--complement(非POSIX)命令来执行cut命令:

$ echo a b c | cut -f 2- -d ' '
b c
$ echo a b c | cut -f 1 -d ' '
a
$ echo a b c | cut -f 1,2 -d ' '
a b
$ echo a b c | cut -f 1 -d ' ' --complement
b c

3
虽然没有回答关于awk的具体问题,但我发现这个最有用,因为awk可以去除重复的空格而cut不能。 - Fmstrat
23
echo a b c | cut -d' ' -f 2- 是一种替代方法。 - Luis
3
好的 - @Luis的解决方案适用于不支持--complement的Mac系统。 - metadaddy

29

也许最简洁的方式:

$ awk '{$(NF+1)=$1;$1=""}sub(FS,"")' infile
United Arab Emirates AE
Antigua & Barbuda AG
Netherlands Antilles AN
American Samoa AS
Bosnia and Herzegovina BA
Burkina Faso BF
Brunei Darussalam BN

说明:

$(NF+1)=$1:生成“新”的最后一字段。

$1="":将原始第一个字段设置为空

sub(FS,""):在前两个动作{$(NF+1)=$1;$1=""}之后,使用sub去除第一个字段分隔符。最后的打印是隐含的。


也许我漏掉了什么,但这在我的gawk 5.1上不起作用——它只是将第一个字段移动到打印的末尾,而不是忽略它。 - Soren Bjornstad
1
这是因为问题的表述具有误导性,@SorenBjornstad。应该是:“如何将第一个字段移动到最后一个位置”。 - Juan Diego Godoy Robles
1
这是一个非常好的解决方案,可以解决在执行$1=""(或$NF=""或其他任何操作时出现前导或尾随空格的问题。我给你点赞。 - bballdave025

18
awk '{sub($1 FS,"")}7' YourFile
删除第一个字段和分隔符,并打印结果(7是非零值,因此打印$0)。

最佳答案!已点赞。这与仅使用 1 有何不同?我想知道这种模式的用法并希望理解它。谢谢! - shadyabhi

10
awk '{ saved = $1; $1 = ""; print substr($0, 2), saved }'

将第一个字段设置为""会在$0的开头留下一个OFS的副本。假设OFS只是一个字符(默认情况下,它是一个单独的空格),我们可以使用substr($0, 2)来删除它。然后,我们附加保存的$1的副本。


7
如果您愿意使用Perl解决方案...
perl -lane 'print join " ",@F[1..$#F,0]' file

这是一个简单的解决方案,其输入/输出分隔符为一个空格,它会产生如下结果:

United Arab Emirates AE
Antigua & Barbuda AG
Netherlands Antilles AN
American Samoa AS
Bosnia and Herzegovina BA
Burkina Faso BF
Brunei Darussalam BN

这个稍微复杂一些。
perl -F`  ` -lane 'print join "  ",@F[1..$#F,0]' file

并且假定输入/输出分隔符是两个空格:

United Arab Emirates  AE
Antigua & Barbuda  AG
Netherlands Antilles  AN
American Samoa  AS
Bosnia and Herzegovina  BA
Burkina Faso  BF
Brunei Darussalam  BN

这些命令行选项被使用:
- -n 循环遍历输入文件的每一行,不会自动打印每一行 - -l 在处理前删除换行符,在处理后添加回来 - -a 自动分割模式 - 将输入行分割成 @F 数组。默认按空格分割 - -F 自动分割修饰符,在此示例中按 ' '(两个空格)分割 - -e 执行以下 Perl 代码 @F 是每行单词的数组,从 0 开始索引 $#F@F 中单词数量 @F[1..$#F] 是元素 1 到最后一个元素的数组切片 @F[1..$#F,0] 是元素 1 到最后一个元素加上元素 0 的数组切片

1
我运行它,最后多了一个数字,所以我使用了这个版本:perl -lane 'shift @F; print join " ", @F'。 - Hans Poo

3
将所有记录移至下一个,并将最后一条记录设为第一条:
$ awk '{a=$1; for (i=2; i<=NF; i++) $(i-1)=$i; $NF=a}1' file
United Arab Emirates AE
Antigua & Barbuda AG
Netherlands Antilles AN
American Samoa AS
Bosnia and Herzegovina BA
Burkina Faso BF
Brunei Darussalam BN

解释

  • a=$1:将第一个值保存到临时变量a中。
  • for (i=2; i<=NF; i++) $(i-1)=$i:将第N个字段的值保存到第(N-1)个字段中。
  • $NF=a:将第一个值($1)保存到最后一个字段中。
  • {}1:为了使awk执行默认操作:{print $0}而设置的真条件。

这种方法可以应对另一种字段分隔符的情况,结果也是很好的:

$ cat c
AE-United-Arab-Emirates
AG-Antigua-&-Barbuda
AN-Netherlands-Antilles
AS-American-Samoa
BA-Bosnia-and-Herzegovina
BF-Burkina-Faso
BN-Brunei-Darussalam

$ awk 'BEGIN{OFS=FS="-"}{a=$1; for (i=2; i<=NF; i++) $(i-1)=$i; $NF=a}1' c
United-Arab-Emirates-AE
Antigua-&-Barbuda-AG
Netherlands-Antilles-AN
American-Samoa-AS
Bosnia-and-Herzegovina-BA
Burkina-Faso-BF
Brunei-Darussalam-BN

2
如果您愿意接受另一个Perl解决方案:
perl -ple 's/^(\S+)\s+(.*)/$2 $1/' file

2

awk '{ tmp = $1; sub(/^[^ ]+ +/, ""); print $0, tmp }'

可以将一行文本中的第一个单词移到最后,并在它们之间添加空格。


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