Печать всего, кроме первого поля, с помощью awk - PullRequest
93 голосов
/ 16 ноября 2010

У меня есть файл, который выглядит следующим образом:

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"?

Ответы [ 15 ]

1 голос
/ 20 января 2018

Если вы открыты для другого решения Perl:

perl -ple 's/^(\S+)\s+(.*)/$2 $1/' file
1 голос
/ 23 сентября 2015

Вариант 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 '{ $(NF+1)=$1;$1="";sub(OFS,"");}1' infile.txt

То есть:

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.
Первое поле может быть захвачено, затем удалено из $ 0 с помощью sub, а затем снова напечатано.

Вариант 3

awk '{ a=$1;sub("[^"FS"]+["FS"]+",""); print $0, a;}' infile.txt
       a=$1                                   # capture first field.
       sub( "                                 # replace: 
             [^"FS"]+                         # A run of non-FS
                     ["FS"]+                  # followed by a run of FS.
                            " , ""            # for nothing.
                                  )           # Default to $0 (the whole line.
       print $0, a                   # Print in reverse order, with OFS.


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 и / или добавим дополнительные разделители, это сработает.
Если входной файл изменен на:

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

Вывод будет (сохраняя разделители):

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

Команда может быть расширена до нескольких полей, но только с современными 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
1 голос
/ 16 ноября 2010

Первый удар по нему, похоже, работает для вашего конкретного случая.

awk '{ f = $1; i = $NF; while (i <= 0); gsub(/^[A-Z][A-Z][ ][ ]/,""); print $i, f; }'
0 голосов
/ 12 мая 2017

Еще один способ ...

... это объединяет поля с 2 по NF с FS и выводит одну строку на строку ввода

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

Я использую это с git, чтобы увидеть, какие файлы были изменены в моем рабочем каталоге:

git diff| \
    grep '\-\-git'| \
    awk '{print$NF}'| \
    awk -F"/" '{for (i=2;i<=NF;i++){printf $i; if (i < NF) {printf FS};}printf RS}'
0 голосов
/ 05 июля 2016

Также есть опция 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...