Làm thế nào để in cột thứ ba đến cột cuối cùng?


121

Tôi đang cố gắng xóa hai cột đầu tiên (mà tôi không quan tâm đến) khỏi tệp nhật ký DbgView. Tôi dường như không thể tìm thấy một ví dụ nào in từ cột 3 trở đi cho đến cuối dòng. Lưu ý rằng mỗi dòng có số cột thay đổi.


Câu trả lời:


108

... hoặc một giải pháp đơn giản hơn: cut -f 3- INPUTFILE chỉ cần thêm đúng dấu phân cách (-d) và bạn sẽ có được hiệu quả tương tự.


9
Lưu ý rằng điều này chỉ hoạt động nếu dấu phân cách hoàn toàn giống nhau giữa tất cả các cột ... Ví dụ: bạn không thể sử dụng dấu cắt với dấu phân cách như \ d +. (Điều đó tôi biết.)
Zach Wily

72
Khi câu hỏi có tiêu đề awk, không thích hợp để chấp nhận câu trả lời không phải là awk. Điều gì sẽ xảy ra nếu mọi người cần nó cho các kịch bản awk? Câu trả lời này lẽ ra chỉ là một bình luận.
syaz

24
@SyaZ: Thông thường tôi sẽ đồng ý, nhưng với số lượng 'awk vô cớ' đang diễn ra trên bảng này, tôi nghĩ rằng cần phải đưa ra một cách thay thế để thực hiện nhiệm vụ. Bạn sẽ không cảm ơn nếu ai đó đã chỉ cho bạn một cách đơn giản và nhanh chóng hơn để thực hiện cùng một nhiệm vụ? Có thể người đăng bài nghĩ rằng awk là cách duy nhất để làm điều này vì số lượng câu trả lời 'không chính xác, nhưng chắc chắn có thể ứng biến được' cho các câu hỏi khác?
Marcin

12
Đó là những gì nhận xét dành cho. Chấp nhận câu trả lời awk tốt nhất và cung cấp các đề xuất không awk tốt hơn về nhận xét. Nếu mọi người bắt đầu đăng các câu trả lời không trả lời chính xác câu hỏi, sẽ rất khó chịu khi tìm kiếm (trong trường hợp của tôi).
syaz

12
Không chỉ dấu phân cách phải giống nhau giữa tất cả các cột mà còn phải có CHÍNH XÁC MỘT ký tự phân cách giữa các cột. Vì vậy, nếu bạn đang xử lý các chương trình căn chỉnh đầu ra của chúng bằng các dấu phân cách, tốt hơn là sử dụng awk.
sknaumov

112
awk '{for(i=3;i<=NF;++i)print $i}' 

3
awk '{for (i = 3; i <= NF; ++ i) print $ i}' nhỏ gọn hơn. :)
dùng172818

1
Cảm ơn, lh3. Tôi chỉ đang sao chép và dán cho sổ tay hướng dẫn sử dụng. :)
Jonathan Feinberg

23
này không thành công với nhiều dòng, mỗi cột là trated như một dòng mới khi in iwth in
meso_2600

13
Để giải quyết vấn đề đầu ra tách ra, tôi đề xuất giải pháp này: awk '{for(i=3;i<=NF;++i)printf $i""FS ; print ""}'( printfsẽ không in newline char trong khi print ""sẽ thêm xuống dòng sau khi các trường khác đã được in)
lauhub

1
Hoặc: echo $(seq 1 10) | awk '{for (i=3; i<=NF; i++) printf $i FS}', mang đến cho: 3 4 5 6 7 8 9 10.
x-yuri

106
awk '{ print substr($0, index($0,$3)) }'

giải pháp được tìm thấy tại đây:
http://www.linuxquestions.org/questions/linux-newbie-8/awk-print-field-to-end-and-character-count-179078/


23
Tôi là loại trễ này, nhưng điều này sẽ không làm việc cho các hồ sơ, trong đó lĩnh vực đầu tiên hoặc thứ hai là tương đương với thứ ba (ví dụ: 3 2 3 4 5)
aleph_null

cũng có thể in phạm vi nội bộ: `` `# từ $ 3 (bao gồm) đến $ 6 (không bao gồm); echo "1,2,3,4,5,6,7,8,9" | awk 'BEGIN {FS = ","; OFS = ","} {print substr ($ 0, index ($ 0, $ 3), length ($ 0) -index ($ 0, $ 6) -1)}'; # cho 3,4,5 ''
splaisan

34

Câu trả lời của Jonathan Feinberg in mỗi trường trên một dòng riêng biệt. Bạn có thể sử dụng printfđể xây dựng lại bản ghi cho kết quả đầu ra trên cùng một dòng, nhưng bạn cũng có thể chỉ cần di chuyển các trường một bước sang trái.

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

1
Lưu ý rằng điều này chỉ hoạt động với Gnu awk, NFPOSIX không cho phép giảm bớt.
kvantour

1
@kvantour: Nó hoạt động trong gawk, mawk, MacOS awk (nawk?). POSIX dường như im lặng về việc liệu NFcó thể được giảm bớt.
Tạm dừng cho đến khi có thông báo mới.

Đó là một trong những góc tối vui nhộn của awk .
kvantour

19
awk '{$1=$2=$3=""}1' file

NB: phương thức này sẽ để lại "khoảng trống" trong 1,2,3 trường nhưng không phải là vấn đề nếu bạn chỉ muốn xem đầu ra.


Thực hiện lệnh đó với `| sed s / ^ \ * // | cột -t` để tách các khoảng trắng ở đầu và căn chỉnh các cột còn lại
MSpreij 9/09

Cuối cùng 1có nghĩa là gì? tôi nên tìm kiếm với từ khóa awknào?
Itachi


1
@Nathan bạn giải quyết vấn đề này là{$1=$2=$3="";$0=$0;$1=$1}1
kvantour

11

Nếu bạn muốn in các cột sau cột thứ 3, chẳng hạn trong cùng một dòng, bạn có thể sử dụng:

awk '{for(i=3; i<=NF; ++i) printf "%s ", $i; print ""}'

Ví dụ:

Mar 09:39 20180301_123131.jpg
Mar 13:28 20180301_124304.jpg
Mar 13:35 20180301_124358.jpg
Feb 09:45 Cisco_WebEx_Add-On.dmg
Feb 12:49 Docker.dmg
Feb 09:04 Grammarly.dmg
Feb 09:20 Payslip 10459 %2828-02-2018%29.pdf

Nó sẽ in:

20180301_123131.jpg
20180301_124304.jpg
20180301_124358.jpg
Cisco_WebEx_Add-On.dmg
Docker.dmg
Grammarly.dmg
Payslip 10459 %2828-02-2018%29.pdf

Như chúng ta có thể thấy, phiếu lương dù có khoảng trắng vẫn hiển thị ở dòng chính xác.


Nhanh chóng và kiểu dáng đẹp. Cảm ơn;)
9nz9

Điều này là tuyệt vời, ngoại trừ tôi gặp sự cố với $ NF bị loại trừ. Khi tôi đặt điều kiện (<= NF), tôi nhận được trường cuối cùng nhưng ký tự đầu tiên của trường đầu tiên bị cắt. Tôi có đang hiểu sai điều gì đó về mặt chức năng không?
Ken Ingram

Có vẻ như vấn đề của tôi là ^ M bị mắc kẹt ở cuối cột cuối cùng. Không thấy làm thế nào để loại bỏ nó.
Ken Ingram

8

Còn về dòng sau:

awk '{$ 1 = $ 2 = $ 3 = ""; in lại file này

Dựa trên gợi ý @ ghostdog74. Của tôi sẽ hoạt động tốt hơn khi bạn lọc các dòng, tức là:

awk '/ ^ exim4-config / {$ 1 = ""; in lại file này

Ngắn gọn và đơn giản. Cũng có thể viết và thêm sed 's/\s\+//g'vào cuối lệnh để cắt bớt khoảng trắng ở đầu
jump_monkey

8
awk -v m="\x0a" -v N="3" '{$N=m$N ;print substr($0, index($0,m)+1)}'

Thao tác này cắt những gì đứng trước trường đã cho nr., N và in tất cả phần còn lại của dòng, bao gồm trường nr.N và duy trì khoảng cách ban đầu (nó không định dạng lại). Nó không có giá trị nếu chuỗi của trường cũng xuất hiện ở một nơi khác trong dòng, đó là vấn đề với câu trả lời của daisaa.

Xác định một chức năng:

fromField () { 
awk -v m="\x0a" -v N="$1" '{$N=m$N; print substr($0,index($0,m)+1)}'
}

Và sử dụng nó như thế này:

$ echo "  bat   bi       iru   lau bost   " | fromField 3
iru   lau bost   
$ echo "  bat   bi       iru   lau bost   " | fromField 2
bi       iru   lau bost 

Đầu ra duy trì mọi thứ, bao gồm cả dấu cách ở cuối

Hoạt động tốt đối với các tệp trong đó '/ n' là dấu phân tách bản ghi, do đó bạn không có ký tự dòng mới đó bên trong các dòng. Nếu bạn muốn sử dụng nó với các dấu phân tách bản ghi khác, hãy sử dụng:

awk -v m="\x01" -v N="3" '{$N=m$N ;print substr($0, index($0,m)+1)}'

ví dụ. Hoạt động tốt với hầu hết tất cả các tệp miễn là chúng không sử dụng char nr thập lục phân. 1 bên trong các dòng.


4

Lệnh awk sau đây in N trường cuối cùng của mỗi dòng và ở cuối dòng in ra một ký tự dòng mới:

awk '{for( i=6; i<=NF; i++ ){printf( "%s ", $i )}; printf( "\n"); }'

Tìm bên dưới một ví dụ liệt kê nội dung của thư mục / usr / bin, sau đó giữ 3 dòng cuối cùng rồi in 4 cột cuối cùng của mỗi dòng bằng awk:

$ ls -ltr /usr/bin/ | tail -3
-rwxr-xr-x 1 root root       14736 Jan 14  2014 bcomps
-rwxr-xr-x 1 root root       10480 Jan 14  2014 acyclic
-rwxr-xr-x 1 root root    35868448 May 22  2014 skype

$ ls -ltr /usr/bin/ | tail -3 | awk '{for( i=6; i<=NF; i++ ){printf( "%s ", $i )}; printf( "\n"); }'
Jan 14 2014 bcomps 
Jan 14 2014 acyclic 
May 22 2014 skype

4
awk '{a=match($0, $3); print substr($0,a)}'

Đầu tiên, bạn tìm vị trí bắt đầu của cột thứ ba. Với substr, bạn sẽ in toàn bộ dòng ($ 0) bắt đầu từ vị trí (trong trường hợp này là a) đến cuối dòng.


3

Chà, bạn có thể dễ dàng đạt được hiệu ứng tương tự bằng cách sử dụng biểu thức chính quy. Giả sử dấu phân cách là một khoảng trắng, nó sẽ giống như sau:

awk '{ sub(/[^ ]+ +[^ ]+ +/, ""); print }'

1
Tôi muốn tránh regex. Nó có thể chậm hơn và dễ dàng hơn để vô tình lộn xộn.
Cascabel

1
Nó rút ngắn nó như thế này: awk '{ sub(/([^ ]+ +){2}/, ""); print }'làm mất mẫu đi hai lần.
erik


2

Giải pháp Perl:

perl -lane 'splice @F,0,2; print join " ",@F' file

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 chia tách trên khoảng trắng

  • -e thực thi mã perl

splice @F,0,2 xóa sạch cột 0 và 1 khỏi mảng @F

join " ",@F nối các phần tử của mảng @F, sử dụng khoảng trắng ở giữa mỗi phần tử

Nếu tệp đầu vào của bạn được phân tách bằng dấu phẩy, thay vì phân cách bằng dấu cách, hãy sử dụng -F, -lane


Giải pháp Python:

python -c "import sys;[sys.stdout.write(' '.join(line.split()[2:]) + '\n') for line in sys.stdin]" < file


1

Ở đây hơi muộn, nhưng không có cách nào ở trên có vẻ hiệu quả. Hãy thử điều này, sử dụng printf, chèn khoảng trắng giữa mỗi. Tôi đã chọn không có dòng mới ở cuối.

awk '{for(i=3;i<=NF;++i) printf("%s ",  $i) }'

1
awk '{for (i=4; i<=NF; i++)printf("%c", $i); printf("\n");}'

in các bản ghi bắt đầu từ trường thứ 4 đến trường cuối cùng theo cùng thứ tự mà chúng có trong tệp gốc


xin lỗi, đây không phải là câu trả lời đúng. nó là quá cụ thể, nhưng tôi không biết làm thế nào để xóa nó
Massimo

1

Trong Bash, bạn có thể sử dụng cú pháp sau với các tham số vị trí:

while read -a cols; do echo ${cols[@]:2}; done < file.txt

Tìm hiểu thêm: Xử lý các tham số vị trí tại Bash Hackers Wiki


0

Nếu nó chỉ là bỏ qua hai trường đầu tiên và nếu bạn không muốn có khoảng trắng khi che các trường đó (giống như một số câu trả lời ở trên làm):

awk '{gsub($1" "$2" ",""); print;}' file

0
awk '{$1=$2=""}1' FILENAME | sed 's/\s\+//g'

Hai cột đầu tiên bị xóa, sedloại bỏ khoảng trắng ở đầu.


-2

Trong AWK, các cột được gọi là trường, do đó NF là khóa

tất cả các hàng:

awk -F '<column separator>' '{print $(NF-2)}' <filename>

chỉ hàng đầu tiên:

awk -F '<column separator>' 'NR<=1{print $(NF-2)}' <filename>
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.