Printing everything except the first field with awk

前端 未结 16 2610
北恋
北恋 2020-12-04 07:04

I have a file that looks like this:

AE  United Arab Emirates
AG  Antigua & Barbuda
AN  Netherlands Antilles
AS  American Samoa
BA  Bosnia and Herzegovina         


        
相关标签:
16条回答
  • 2020-12-04 07:51

    $1="" leaves a space as Ben Jackson mentioned, so use a for loop:

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

    So if your string was "one two three", the output will be:

    two
    three

    If you want the result in one row, you could do as follows:

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

    This will give you: "two three"

    0 讨论(0)
  • 2020-12-04 07:53

    If you're open to another Perl solution:

    perl -ple 's/^(\S+)\s+(.*)/$2 $1/' file
    
    0 讨论(0)
  • 2020-12-04 07:54

    Use the cut command with the --complement option:

    $ 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
    
    0 讨论(0)
  • 2020-12-04 07:55

    Assigning $1 works but it will leave a leading space: awk '{first = $1; $1 = ""; print $0, first; }'

    You can also find the number of columns in NF and use that in a loop.

    0 讨论(0)
  • 2020-12-04 07:56

    Maybe the most concise way:

    $ 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
    

    Explanation:

    $(NF+1)=$1: Generator of a "new" last field.

    $1="": Set the original first field to null

    sub(FS,""): After the first two actions {$(NF+1)=$1;$1=""} get rid of the first field separator by using sub. The final print is implicit.

    0 讨论(0)
  • 2020-12-04 07:57

    Option 1

    There is a solution that works with some versions of awk:

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

    Explanation:

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

    Result:

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

    However that might fail with older versions of awk.


    Option 2

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

    That is:

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

    Note that what needs to be erased is the OFS, not the FS. The line gets re-calculated when the field $1 is asigned. That changes all runs of FS to one OFS.


    But even that option still fails with several delimiters, as is clearly shown by changing the OFS:

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

    That line will output:

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

    That reveals that runs of FS are being changed to one OFS.
    The only way to avoid that is to avoid the field re-calculation.
    One function that can avoid re-calc is sub.
    The first field could be captured, then removed from $0 with sub, and then both re-printed.

    Option 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
    

    Even if we change the FS, the OFS and/or add more delimiters, it works.
    If the input file is changed to:

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

    And the command changes to:

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

    The output will be (still preserving delimiters):

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

    The command could be expanded to several fields, but only with modern awks and with --re-interval option active. This command on the original file:

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

    Will output this:

    Arab Emirates AE United
    & Barbuda AG Antigua
    Antilles AN Netherlands
    Samoa AS American
    and Herzegovina BA Bosnia
    Faso BF Burkina
    Darussalam BN Brunei
    
    0 讨论(0)
提交回复
热议问题