In mọi thứ ngoại trừ trường đầu tiên với awk


108

Tôi có một tệp trông giống như sau:

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

Và tôi muốn đảo ngược thứ tự, in mọi thứ đầu tiên ngoại trừ $ 1 và sau đó $ 1:

United Arab Emirates AE

Làm cách nào để thực hiện thủ thuật "mọi thứ ngoại trừ trường 1"?


2
Xin chào @cfisher, nó có thể được thực hiện mà không cần vòng lặp mà không có thêm không gian.
Juan Diego Godoy Robles

Câu trả lời:


91

Chỉ định $1công việc nhưng nó sẽ để lại khoảng trống ở đầu:awk '{first = $1; $1 = ""; print $0, first; }'

Bạn cũng có thể tìm số cột trong đó NFvà sử dụng số đó trong một vòng lặp.


2
Đối với những người hoàn toàn lười biếng; đây là mã klashxx .
Serge Stroobandt

1
Tuyệt quá. Got thoát khỏi không gian hàng đầu với sed: awk {'first = $1; $1=""; print $0'}|sed 's/^ //g'
Thyag

Khoảng trống được loại bỏ dễ dàng với VIM nhấn 'Ctrl + V Gd' ở chế độ bình thường
Santi

107

$1=""để lại một khoảng trống như Ben Jackson đã đề cập, vì vậy hãy sử dụng một forvòng lặp:

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

Vì vậy, nếu chuỗi của bạn là "một hai ba", đầu ra sẽ là:

hai
ba

Nếu bạn muốn kết quả trong một hàng, bạn có thể làm như sau:

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

Điều này sẽ cung cấp cho bạn: "hai ba"


4
và thêm một khoảng trống sau
NeronLeVelu

2
tốt hơn để sử dụng: awk '{for(i=2;i<=NF;i++){ printf("%s",( (i>2) ? OFS : "" ) $i) } ; print ;}' which: in trường 2 thành NF, thêm Dấu phân cách trường đầu ra nếu cần (tức là, ngoại trừ trước $ 2). Bản in cuối cùng thêm một dòng mới cuối cùng để kết thúc việc in dòng hiện tại. Đó là một sẽ làm việc nếu bạn thay đổi FS / OFS (ví dụ, nó sẽ không phải luôn luôn "không gian")
Olivier Dulac

Cái thứ hai làm việc rất tốt cho tôi. Người đầu tiên, không quá nhiều. Không thực sự chắc chắn tại sao. Nó cắt nhỏ toàn bộ văn bản.
lồng tiếng vào

72

Sử dụng cutlệnh với --complementtùy chọn:

$ 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

2
Trong khi không trả lời câu hỏi cụ thể cho awk, tôi thấy điều này hữu ích nhất vì awk đã loại bỏ các khoảng trắng trùng lặp và không cắt.
Fmstrat

19
echo a b c | cut -d' ' -f 2- là một sự thay thế
Luis

2
Nice - @Luis giải pháp công trình trên Mac, mà không hỗ trợ --complement
metadaddy

21

Có thể cách ngắn gọn nhất:

$ 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

Giải trình:

$(NF+1)=$1: Trình tạo của trường cuối cùng "mới".

$1="": Đặt trường đầu tiên ban đầu thành null

sub(FS,""): Sau hai hành động đầu tiên, {$(NF+1)=$1;$1=""}hãy loại bỏ dấu phân tách trường đầu tiên bằng cách sử dụng phụ. Bản in cuối cùng là ẩn.


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

Loại bỏ trường đầu tiên và dấu phân cách, và in kết quả ( 7là giá trị khác 0 nên in $ 0).


Câu trả lời tốt nhất! Đã ủng hộ. Nó khác gì với việc chỉ sử dụng 1? Tôi tự hỏi cách sử dụng của mẫu này và muốn hiểu điều đó. cảm ơn!
Abhijeet Rastogi

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

Đặt trường đầu tiên để ""lại một bản sao của OFSở đầu $0. Giả sử đó OFSchỉ là một ký tự (theo mặc định, đó là một khoảng trắng), chúng ta có thể xóa nó bằng substr($0, 2). Sau đó, chúng tôi nối bản sao đã lưu của $1.


6

Nếu bạn đang sử dụng giải pháp Perl ...

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

là một giải pháp đơn giản với dấu phân tách đầu vào / đầu ra của một khoảng trắng, tạo ra:

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

Cái tiếp theo này phức tạp hơn một chút

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

và giả định rằng dấu phân tách đầu vào / đầu ra là hai khoảng trắng:

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

Các tùy chọn dòng lệnh này được sử dụng:

  • -n lặp xung quanh mọi dòng của tệp đầu vào, không tự động in mọi dòng

  • -l xóa các dòng mới trước khi xử lý và thêm lại sau đó

  • -achế độ autosplit - chia dòng đầu vào thành mảng @F. Mặc định phân tách trên khoảng trắng

  • -F công cụ sửa đổi autosplit, trong ví dụ này phân tách trên '' (hai dấu cách)

  • -e thực thi mã perl sau

@Flà mảng các từ trong mỗi dòng, được đánh chỉ mục bắt đầu bằng 0
$#Flà số từ trong @F
@F[1..$#F]là một lát mảng của phần tử 1 đến phần tử cuối cùng
@F[1..$#F,0]là một lát mảng của phần tử 1 đến phần tử cuối cùng cộng với phần tử 0


1
Tôi chạy nó và có thêm một số ở cuối nên tôi đã sử dụng phiên bản này: perl -lane 'shift @F; print join "", @F '
Hans Poo,

2

Dấu phân tách trường trong gawk (ít nhất) có thể là một chuỗi cũng như một ký tự (nó cũng có thể là một regex). Nếu dữ liệu của bạn nhất quán, thì điều này sẽ hoạt động:

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

Đó là hai dấu cách giữa dấu ngoặc kép.


Câu trả lời tốt nhất cho tình huống hiện tại, nhưng, về mặt kỹ thuật, điều này không trả lời câu hỏi làm thế nào để in mọi thứ trừ trường đầu tiên.
Dan Molding

@DanMoulding: Miễn là tệp nhất quán trong việc sử dụng hai dấu cách để phân tách mã quốc gia và không có sự xuất hiện nào khác của hai dấu cách với nhau, câu trả lời của tôi sẽ giải quyết được câu hỏi.
Tạm dừng cho đến khi có thông báo mới.

2
Những người đặt câu hỏi này đến đây vì họ muốn biết cách in mọi thứ ngoại trừ trường đầu tiên (xem tiêu đề câu hỏi). Đó là cách tôi hạ cánh ở đây. Câu trả lời của bạn cho biết cách in trường đầu tiên, sau đó là trường thứ hai. Mặc dù đây có lẽ là giải pháp tốt nhất cho tình huống cụ thể của OP, nhưng nó không giải quyết được vấn đề chung về cách in mọi thứ ngoại trừ trường đầu tiên.
Dan Molding

2

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


2

Hãy chuyển tất cả các bản ghi sang bản tiếp theo và đặt bản cuối cùng làm bản ghi đầu tiên:

$ 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

Giải trình

  • a=$1 lưu giá trị đầu tiên vào một biến tạm thời.
  • for (i=2; i<=NF; i++) $(i-1)=$i lưu giá trị trường thứ N vào trường thứ (N-1).
  • $NF=a lưu giá trị đầu tiên ($1 ) vào trường cuối cùng.
  • {}1điều kiện đúng để làm cho awkthực hiện các hành động mặc định: {print $0}.

Bằng cách này, nếu bạn tình cờ có một dấu tách trường khác, kết quả cũng tốt:

$ 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

1

Một cú đâm đầu tiên vào nó có vẻ hiệu quả với trường hợp cụ thể của bạn.

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

1

lựa chọn 1

Có một giải pháp hoạt động với một số phiên bản của awk:

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

Giải trình:

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

Kết quả:

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

Tuy nhiên, điều đó có thể không thành công với các phiên bản cũ hơn của awk.


Lựa chọn 2

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

Đó là:

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

Lưu ý rằng những gì cần được xóa là OFS, không phải FS. Dòng được tính lại khi trường $ 1 được đánh dấu. Điều đó thay đổi tất cả các lần chạy FS thành một OFS.


Nhưng ngay cả tùy chọn đó vẫn không thành công với một số dấu phân cách, như được thể hiện rõ ràng bằng cách thay đổi OFS:

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

Dòng đó sẽ xuất:

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

Điều đó tiết lộ rằng các lần chạy FS đang được thay đổi thành một OFS.
Cách duy nhất để tránh điều đó là tránh tính toán lại trường.
Một chức năng có thể tránh tái calc là phụ.
Trường đầu tiên có thể được chụp, sau đó xóa khỏi $ 0 với phụ, và sau đó cả hai được in lại.

Lựa chọn 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

Ngay cả khi chúng tôi thay đổi FS, OFS và / hoặc thêm nhiều dấu phân cách hơn, nó vẫn hoạt động.
Nếu tệp đầu vào được thay đổi thành:

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

Và lệnh thay đổi thành:

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

Đầu ra sẽ là (vẫn bảo toàn dấu phân cách):

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

Lệnh có thể được mở rộng đến một số trường, nhưng chỉ với các awk hiện đại và với tùy chọn --re-period đang hoạt động. Lệnh này trên tệp gốc:

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

Sẽ xuất cái này:

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

1

Nếu bạn đang mở một giải pháp Perl khác:

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

0

Có một tùy chọn quyến rũ nữa ...

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

Giải thích...

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

Giải thích cặn kẽ hơn ...

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

Tuy nhiên, một cách khác ...

... điều này nối lại các trường từ 2 đến NF với FS và xuất ra một dòng trên mỗi dòng đầu vào

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

Tôi sử dụng điều này với git để xem những tệp nào đã được sửa đổi trong dir đang làm việc của tôi:

git diff| \
    grep '\-\-git'| \
    awk '{print$NF}'| \
    awk -F"/" '{for (i=2;i<=NF;i++){printf $i; if (i < NF) {printf FS};}printf RS}'

-3

Một cách khác và dễ dàng sử dụng lệnh mèo

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

Tôi đã phản đối vì đây không phải là một cách tiếp cận năng động. Với điều này, bạn cần biết số lượng đối số và giả sử dữ liệu của bạn là nhất quán. Dữ liệu hầu như không bao giờ nhất quán và cách tiếp cận của bạn phải tính đến điều này hầu hết thời gian.
xh3b4sd
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.