Drukowanie wszystkiego oprócz pierwszego pola za pomocą awk

Mam plik, który wygląda tak:

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

A ja lubię odwracać kolejność, drukując najpierw wszystko oprócz $1 a potem $1:

United Arab Emirates AE

Jak mogę zrobić sztuczkę "wszystko poza polem 1"?

 113
Author: Kjetil S., 2010-11-16

16 answers

Przypisanie $1 działa, ale pozostawia spację wiodącą: awk '{first = $1; $1 = ""; print $0, first; }'

Możesz również znaleźć liczbę kolumn w NF i użyć jej w pętli.

 97
Author: Ben Jackson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-16 19:32:13

$1="" pozostawia spację, jak wspomniał Ben Jackson, więc użyj pętli for:

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

Więc jeśli twój łańcuch był "raz dwa trzy", wyjście będzie:

Dwa
trzy

Jeśli chcesz uzyskać wynik w jednym wierszu, możesz wykonać następujące czynności:

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

To da ci: "dwa trzy"

 114
Author: 7winkie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-13 21:30:06

Użyj polecenia cut z opcją --complement:

$ 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
 74
Author: zeleniy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-13 21:30:45

Może najbardziej zwięzły sposób:

$ 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

Wyjaśnienie:

$(NF+1)=$1: Generator" nowego " ostatniego pola.

$1="": Ustaw oryginalne pierwsze pole na null

sub(FS,""): po pierwszych dwóch akcjach {$(NF+1)=$1;$1=""} pozbądź się pierwszego separatora pól za pomocą sub. Ostateczny druk jest niejawny.

 21
Author: Juan Diego Godoy Robles,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-13 21:31:44
awk '{sub($1 FS,"")}7' YourFile

Usuń pierwsze pole i separator i wydrukuj wynik (7 jest wartością niezerową, więc Drukuj $0).

 15
Author: NeronLeVelu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-07 10:50:32
awk '{ saved = $1; $1 = ""; print substr($0, 2), saved }'

Ustawienie pierwszego pola na "" pozostawia pojedynczą kopię OFS na początku $0. Zakładając, że OFS jest tylko pojedynczym znakiem (domyślnie jest to pojedyncza spacja), możemy ją usunąć za pomocą substr($0, 2). Następnie dołączamy zapisaną kopię $1.

 10
Author: dubiousjim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-19 04:05:41

Jeśli jesteś otwarty na rozwiązanie Perla...

perl -lane 'print join " ",@F[1..$#F,0]' file

Jest prostym rozwiązaniem z separatorem wejścia/wyjścia jednej przestrzeni, który daje:

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

Ten następny jest nieco bardziej złożony

perl -F`  ` -lane 'print join "  ",@F[1..$#F,0]' file

I zakłada, że separator wejścia/wyjścia ma dwie spacje:

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

Używane są następujące opcje wiersza poleceń:

  • -n pętla wokół każdej linii pliku wejściowego, nie Drukuj automatycznie każdej linii

  • -l usuwa nowe linie przed przetworzeniem, a następnie dodaje je z powrotem w

  • -a Tryb autosplit-podział linii wejściowych na tablicę @F. Domyślnie dzielenie na białe znaki

  • -F modyfikator autosplit, w tym przykładzie dzieli się na "" (dwie spacje)

  • -e wykonaj następujący kod Perla

@F jest tablicą słów w każdej linii, indeksowaną zaczynając od 0
$#F jest liczbą słów w @F
@F[1..$#F] jest tablicą kawałek elementu 1 przez ostatni element
@F[1..$#F,0] jest wycinkiem tablicy elementu 1 przez ostatni element plus element 0

 6
Author: Chris Koknat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-17 15:57:25

Separator pól w gawk (przynajmniej) może być zarówno ciągiem znaków, jak i znakiem (może to być również regex). Jeśli Twoje dane są spójne, to zadziała:

awk -F "  " '{print $2,$1}' inputfile

To dwie spacje między podwójnymi cudzysłowami.

 2
Author: Dennis Williamson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-16 20:34:53

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

 2
Author: Arkku,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-16 22:02:05

Przenieśmy wszystkie rekordy do następnego i ustawmy ostatni jako pierwszy:

$ 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

Wyjaśnienie

  • a=$1 Zapisz pierwszą wartość do zmiennej tymczasowej.
  • for (i=2; i<=NF; i++) $(i-1)=$i Zapisz N-tą wartość pola do (N-1)tego pola.
  • $NF=a Zapisz pierwszą wartość ($1) do ostatniego pola.
  • {}1 true condition to make awk performing the default action: {print $0}.

W ten sposób, jeśli zdarzy ci się mieć inny separator pola, wynik jest również dobry:

$ 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
Author: fedorqui 'SO stop harming',
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-14 09:46:23

Jeśli jesteś otwarty na inne rozwiązanie Perla:

perl -ple 's/^(\S+)\s+(.*)/$2 $1/' file
 2
Author: Kjetil S.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-19 21:01:06

Pierwsze dźgnięcie wydaje się działać w twojej konkretnej sprawie.

awk '{ f = $1; i = $NF; while (i <= 0); gsub(/^[A-Z][A-Z][ ][ ]/,""); print $i, f; }'
 1
Author: Wesley Rice,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-16 20:42:09

Opcja 1

Istnieje rozwiązanie, które działa z niektórymi wersjami awk:

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

Wyjaśnienie:

       $(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.

Wynik:

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

Może to jednak zawieść w starszych wersjach awk.


Opcja 2

awk '{ $(NF+1)=$1;$1="";sub(OFS,"");}1' infile.txt

Czyli:

awk '{                                      # call awk.
       $(NF+1)=$1;                          # Add one trailing field.
                  $1="";                    # Erase first field.
                        sub(OFS,"");        # remove leading OFS.
                                    }1'     # print the line.

Zauważ, że to, co należy usunąć, to OFS, a nie FS. Linia jest ponownie obliczana, gdy pole $1 jest asigned. To zmienia wszystkie biegi FS do jednego z nich.


Ale nawet ta opcja nadal nie działa z kilkoma ogranicznikami, co jest wyraźnie pokazane przez zmianę OFS:

awk -v OFS=';' '{ $(NF+1)=$1;$1="";sub(OFS,"");}1' infile.txt

Ta linia wyświetli:

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

To pokazuje, że biegi FS są zmieniane na jeden z nich.
Jedynym sposobem, aby tego uniknąć, jest uniknięcie ponownego obliczenia pola.
Jedną z funkcji, która może uniknąć re-calc jest sub.
Pierwsze pole może zostać przechwycone, a następnie usunięte z $0 za pomocą sub, a następnie oba ponownie wydrukowane.

Opcja 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

Nawet jeśli zmienimy FS, OFS i / lub dodamy więcej ograniczniki, to działa.
Jeśli plik wejściowy zostanie zmieniony na:

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

I polecenie zmienia się na:

awk -vFS='.' -vOFS=';' '{a=$1;sub("[^"FS"]+["FS"]+",""); print $0,a;}' infile.txt

Wyjście będzie (nadal zachowując ograniczniki):

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

Polecenie może być rozszerzone do kilku pól, ale tylko z nowoczesnymi awk i z aktywną opcją --re-interval. To polecenie w oryginalnym pliku:

awk -vn=2 '{a=$1;b=$2;sub("([^"FS"]+["FS"]+){"n"}","");print $0,a,b;}' infile.txt

Wyświetli to:

Arab Emirates AE United
& Barbuda AG Antigua
Antilles AN Netherlands
Samoa AS American
and Herzegovina BA Bosnia
Faso BF Burkina
Darussalam BN Brunei
 1
Author: Community,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-20 09:12:55

Jest też opcja sed...

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

Wyjaśnione...

Swap
\([^ ]*\) = Match anything until we reach a space, store in $1
\(.*\)    = Match everything else, store in $2
With
\2        = Retrieve $2
\1        = Retrieve $1

Dokładniej wyjaśnione...

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
 0
Author: ZeBadger,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-05 10:14:42

Yet another way...

...to dołącza do pól 2 przez NF z FS i wyprowadza jedną linię na linię wejścia

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

Używam tego z Gitem, aby zobaczyć, jakie pliki zostały zmodyfikowane w moim roboczym katalogu:

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
Author: Rondo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-12 00:52:52

Inny i łatwy sposób użycia polecenia cat

cat filename | awk '{print $2,$3,$4,$5,$6,$1}' > newfilename
 -3
Author: Scorpio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-10-10 04:11:19