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

使用awk打印除第一个字段以外的所有内容,awk,sed,Awk,Sed,我有一个文件如下所示: 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 我如何才能完成“除字段1以外的所有内容”

我有一个文件如下所示:

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

我如何才能完成“除字段1以外的所有内容”的技巧?

分配
$1
有效,但会留下一个前导空格:
awk'{first=$1;$1=”“;print$0,first;}'


您还可以在
NF
中找到列数,并在循环中使用它。

第一次尝试它似乎适用于您的特定情况

awk '{ f = $1; i = $NF; while (i <= 0); gsub(/^[A-Z][A-Z][ ][ ]/,""); print $i, f; }'

awk'{f=$1;i=$NF;while(igawk中的字段分隔符(至少)可以是字符串,也可以是字符(也可以是正则表达式)。如果数据一致,那么这将起作用:

awk -F "  " '{print $2,$1}' inputfile
双引号之间有两个空格。

awk'{tmp=$1;sub(/^[^]+/,“”);print$0,tmp}'
$1=“”
如本•杰克逊所述留下一个空格,因此使用
循环:

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

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

的保存副本附加到
cut
命令和
-f2-
(POSIX)或
--complete
(非POSIX):


让我们将所有记录移动到下一个记录,并将最后一个记录设置为第一个:

$ 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

也许最简洁的方式是:

$ 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                          # add a new field equal to field 1.
                  $1=""                    # erase the contents of field 1.
                        $0=$0;} NF=NF      # force a re-calc of fields.
                                           # and use NF to promote a print.
$(NF+1)=$1
:最后一个“新”字段的生成器

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

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

awk '{sub($1 FS,"")}7' YourFile

删除第一个字段和分隔符,然后打印结果(
7
是非零值,所以打印$0)。

如果您对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 有一种解决方案可用于某些版本的awk:

awk '{ $(NF+1)=$1;$1="";$0=$0;} NF=NF ' infile.txt
说明:

       $(NF+1)=$1                          # add a new field equal to field 1.
                  $1=""                    # erase the contents of field 1.
                        $0=$0;} NF=NF      # force a re-calc of fields.
                                           # and use NF to promote a print.
结果:

United Arab Emirates AE
Antigua & Barbuda AG
Netherlands Antilles AN
American Samoa AS
Bosnia and Herzegovina BA
Burkina Faso BF
Brunei Darussalam BN
但是,旧版本的awk可能会失败。


选择2 即:

awk '{                                      # call awk.
       $(NF+1)=$1;                          # Add one trailing field.
                  $1="";                    # Erase first field.
                        sub(OFS,"");        # remove leading OFS.
                                    }1'     # print the line.
请注意,需要擦除的是OFS,而不是FS。当字段$1被赋值时,将重新计算该行。这会将所有FS运行更改为一个OFS


但即使是该选项也会因几个分隔符而失败,这一点可以通过更改OFS清楚地看出:

awk -v OFS=';' '{ $(NF+1)=$1;$1="";sub(OFS,"");}1' infile.txt
该行将输出:

United;Arab;Emirates;AE
Antigua;&;Barbuda;AG
Netherlands;Antilles;AN
American;Samoa;AS
Bosnia;and;Herzegovina;BA
Burkina;Faso;BF
Brunei;Darussalam;BN
这表明FS的运行正在更改为OFS之一。
避免这种情况的唯一方法是避免字段重新计算。
一个可以避免重新计算的功能是sub.
可以捕获第一个字段,然后使用sub从$0中删除,然后重新打印这两个字段

选择3 即使我们更改FS、OFS和/或添加更多分隔符,它也可以工作。
如果输入文件更改为:

AE..United....Arab....Emirates
AG..Antigua....&...Barbuda
AN..Netherlands...Antilles
AS..American...Samoa
BA..Bosnia...and...Herzegovina
BF..Burkina...Faso
BN..Brunei...Darussalam
命令将更改为:

awk -vFS='.' -vOFS=';' '{a=$1;sub("[^"FS"]+["FS"]+",""); print $0,a;}' infile.txt
输出将是(仍保留分隔符):

该命令可以扩展到多个字段,但只能在现代AWK和--re interval选项处于活动状态时使用。此命令用于原始文件:

awk -vn=2 '{a=$1;b=$2;sub("([^"FS"]+["FS"]+){"n"}","");print $0,a,b;}' infile.txt
将输出以下内容:

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

还有一个sed选项

 sed 's/\([^ ]*\)  \(.*\)/\2 \1/' inputfile.txt
解释说

Swap
\([^ ]*\) = Match anything until we reach a space, store in $1
\(.*\)    = Match everything else, store in $2
With
\2        = Retrieve $2
\1        = Retrieve $1
s    = Swap
/    = Beginning of source pattern
\(   = start storing this value
[^ ] = text not matching the space character
*    = 0 or more of the previous pattern
\)   = stop storing this value
\(   = start storing this value
.    = any character
*    = 0 or more of the previous pattern
\)   = stop storing this value
/    = End of source pattern, beginning of replacement
\2   = Retrieve the 2nd stored value
\1   = Retrieve the 1st stored value
/    = end of replacement
更彻底的解释

Swap
\([^ ]*\) = Match anything until we reach a space, store in $1
\(.*\)    = Match everything else, store in $2
With
\2        = Retrieve $2
\1        = Retrieve $1
s    = Swap
/    = Beginning of source pattern
\(   = start storing this value
[^ ] = text not matching the space character
*    = 0 or more of the previous pattern
\)   = stop storing this value
\(   = start storing this value
.    = any character
*    = 0 or more of the previous pattern
\)   = stop storing this value
/    = End of source pattern, beginning of replacement
\2   = Retrieve the 2nd stored value
\1   = Retrieve the 1st stored value
/    = end of replacement
还有另一种方式

…这将字段2至NF与FS重新连接,并每行输入输出一行

awk '{for (i=2;i<=NF;i++){printf $i; if (i < NF) {printf FS};}printf RS}'

awk'{for(i=2;i如果您对另一个Perl解决方案持开放态度:

perl -ple 's/^(\S+)\s+(.*)/$2 $1/' file

使用cat命令的另一种简单方法

cat filename | awk '{print $2,$3,$4,$5,$6,$1}' > newfilename

对于目前的情况,这是最好的答案,但从技术上讲,这并不能解决如何打印除第一个字段以外的所有内容的问题。@DanMoulding:只要文件在使用两个空格分隔国家/地区代码时保持一致,并且没有其他两个空格同时出现,我的答案就解决了这个问题关于这个问题,请点击此处,因为他们想知道如何打印除第一个字段以外的所有内容(请参见问题标题).这就是我在这里登陆的原因。您的答案显示了如何打印第一个字段,然后再打印第二个字段。虽然这可能是解决OP特殊情况的最佳解决方案,但它并不能解决如何打印除第一个字段以外的所有内容的一般问题。您好@cfisher,这可以在没有循环和额外空间的情况下完成。公式我的两分钱:“如何将awk中的第一个字段移动到最后一个位置”虽然没有回答特定于awk的问题,但我发现这是最有用的,因为awk删除了重复的空格,而cut没有。
echo a b c | cut-d'-f 2-
是另一个不错的解决方案-@Luis解决方案在Mac上工作,它不支持对完全懒惰的人的补充;这里是。太好了。用sed:
去掉了前导空格>awk{'first=$1;$1=“”;print$0'}| sed's/^//g'
使用VIM pres可以轻松删除空间
s    = Swap
/    = Beginning of source pattern
\(   = start storing this value
[^ ] = text not matching the space character
*    = 0 or more of the previous pattern
\)   = stop storing this value
\(   = start storing this value
.    = any character
*    = 0 or more of the previous pattern
\)   = stop storing this value
/    = End of source pattern, beginning of replacement
\2   = Retrieve the 2nd stored value
\1   = Retrieve the 1st stored value
/    = end of replacement
awk '{for (i=2;i<=NF;i++){printf $i; if (i < NF) {printf FS};}printf RS}'
git diff| \
    grep '\-\-git'| \
    awk '{print$NF}'| \
    awk -F"/" '{for (i=2;i<=NF;i++){printf $i; if (i < NF) {printf FS};}printf RS}'
perl -ple 's/^(\S+)\s+(.*)/$2 $1/' file
cat filename | awk '{print $2,$3,$4,$5,$6,$1}' > newfilename