Cách xóa cột cuối cùng của tệp trong Linux


25

Tôi muốn xóa cột cuối cùng của tệp txt, trong khi tôi không biết số cột là gì. Làm thế nào tôi có thể làm điều này?

Thí dụ:

Đầu vào:

1223 1234 1323 ... 2222 123
1233 1234 1233 ... 3444 125
0000 5553 3455 ... 2334 222

Và tôi muốn đầu ra của mình là:

1223 1234 1323 ... 2222
1233 1234 1233 ... 3444
0000 5553 3455 ... 2334

Có nhiều cách để làm điều này .. xin vui lòng thêm một ví dụ và đầu ra dự kiến ​​của bạn từ nó ..
heemayl

@heemayl ok tôi đã làm
zara

Cảm ơn..có các tab cột được phân tách hoặc phân tách không gian?
heemayl

@heemayl không gian là dấu phân cách
zara

Câu trả lời:


43

Với awk:

awk 'NF{NF-=1};1' <in >out

hoặc là:

awk 'NF{NF--};1' <in >out

hoặc là:

awk 'NF{--NF};1' <in >out

Mặc dù điều này trông giống như voodoo, nó hoạt động. Có ba phần cho mỗi lệnh awk này.

Đầu tiên là NF, điều kiện tiên quyết cho phần thứ hai. NFlà một biến chứa số lượng các trường trong một dòng. Trong AWK, mọi thứ đều đúng nếu chúng không phải là 0 hoặc chuỗi rỗng "". Do đó, phần thứ hai (nơi NFbị giảm) chỉ xảy ra nếu NFkhông bằng 0.

Phần thứ hai ( NF-=1 NF--hoặc --NFlà) chỉ trừ một từ NFbiến. Điều này ngăn trường cuối cùng được in, bởi vì khi bạn thay đổi một trường (loại bỏ trường cuối cùng trong trường hợp này), hãy awkxây dựng lại $0, nối tất cả các trường được phân tách bằng dấu cách theo mặc định. $0không chứa trường cuối cùng nữa.

Phần cuối cùng là 1. Nó không phải là phép thuật, nó chỉ được sử dụng như một biểu thức có nghĩa true. Nếu một awkbiểu thức ước tính là đúng mà không có bất kỳ hành động liên quan nào, thì awkhành động mặc định là print $0.


@JJoao: À, cảm ơn, quên mất --. Một lưu ý, hiện tại, bạn cần ;1tuân thủ POSIX.
cuonglm

Bản năng ban đầu của tôi sẽ là sử dụng một vòng lặp for, nhưng điều này ngắn gọn và thông minh hơn nhiều.
Sergiy Kolodyazhnyy

5
Điều đáng chú ý là nếu bạn đang sử dụng một dấu phân cách không mặc định, bạn sẽ cần thực hiện một số thay đổi. Giả sử ,là người phân định của bạn:awk -F',' 'BEGIN { OFS = FS }; NF { NF -= 1 }; 1' < in > out
Ông Llama

1
Hiệu ứng giảm dần NF là hành vi không xác định bởi POSIX - bạn sẽ nhận được đầu ra khác nhau tùy thuộc vào việc bạn đang chạy. Một số awks sẽ xóa trường cuối cùng như bạn muốn, một số sẽ không làm gì cả, và một số khác có thể báo cáo lỗi cú pháp hoặc bất cứ điều gì khác.
Ed Morton

16

Sử dụng grepvới PCRE:

$ grep -Po '.*(?=\s+[^\s]+$)' file.txt 
1223 1234 1323 ... 2222
1233 1234 1233 ... 3444
0000 5553 3455 ... 2334

Sử dụng GNU sed:

$ sed -r 's/(.*)\s+[^\s]+$/\1/' file.txt 
1223 1234 1323 ... 2222
1233 1234 1233 ... 3444
0000 5553 3455 ... 2334

1
@ramin Chắc chắn..có thể bạn vui lòng hỏi nó như một câu hỏi mới (đây là cách trang web này hoạt động) :)
heemayl

@ramin Nó có cung cấp cho bạn bất kỳ hạn chế thời gian hoặc bất kỳ cảnh báo nào không?
heemayl

Nó nói rằng đây là ra khỏi câu hỏi tiêu chuẩn!
zara

@ramin Ok..cho tôi liên hệ với quản trị viên, họ có thể giúp bạn không..bt bạn đã kiểm tra bất kỳ QA cũ nào về câu hỏi của bạn chưa? có khả năng là câu hỏi đã được hỏi và trả lời ..
heemayl

3
Đừng hỏi những câu hỏi siêu cơ bản như " làm thế nào tôi có thể đổi tên một tên tệp trong Linux ". Sử dụng Google.
Christoffer Hammarström

11

Sử dụng Perl:

perl -lane '$,=" ";pop(@F);print(@F)' in

Sử dụng rev+ cut:

rev in | cut -d ' ' -f 2- | rev

5

Sử dụng GNU sed:

sed -r 's/\s+\S+$//' input.txt

Tổng quát hơn, cái này hoạt động với sed BSD trong OSX, cũng như GNU sed:

sed 's/[[:space:]]\{1,\}[^[:space:]]\{1,\}$//' input.txt

1

Nếu dấu phân cách luôn là một char (vì vậy hai hoặc nhiều dấu phân cách liên tiếp chỉ định các trường trống), bạn headchỉ có thể là dòng đầu tiên từ tệp đầu vào của mình, đếm số dấu phân cách ( ndấu phân cách có nghĩa là số trường là n+1) sau đó sử dụng cutđể in từ trường 1st lên đến trường nthứ (thứ hai đến cuối cùng), ví dụ với đầu vào được phân định bằng tab:

n=$(head -n 1 infile | tr -dc \\t | tr \\t \\n | wc -l)
cut -f1-$n infile > outfile

hoặc ví dụ với tệp csv :

n=$(head -n 1 infile | tr -dc , | tr , \\n | wc -l)
cut -d, -f1-$n infile > outfile

Tôi sẽ chạy một số điểm chuẩn sau nếu tôi có thời gian nhưng với đầu vào lớn tôi nghĩ giải pháp này sẽ nhanh hơn các giải pháp khác sử dụng regex vì giải pháp này xử lý tối thiểu trên dòng đầu tiên để có được không. của các lĩnh vực và sau đó sử dụng cutđược tối ưu hóa cho công việc này.


1

Bạn có thể sử dụng một trong hai cách sau:

sed 's/[[:space:]]*[^[:space:]]*$//' file

awk '{sub(/[[:space:]]*[^[:space:]]*$/,"")}1' file

0

Sử dụng vim:

Mở tệp trong vim

vim <filename> 

Chuyển đến hàng đầu tiên, chỉ trong trường hợp con trỏ được đặt ở bất kỳ nơi nào khác.

gg

Tạo một macro có tên "q" qq, đi đến phía sau của dòng hiện tại $, sau đó quay trở lại không gian cuối cùng F(viết hoa F, theo sau là SPACE bằng chữ) sau đó xóa từ vị trí hiện tại qua cuối dòng Dđi xuống dòng tiếp theo jvà dừng ghi macro với q.

qq$F Djq

Bây giờ chúng ta có thể lặp lại macro của chúng tôi với @qmỗi dòng.
Chúng tôi cũng có thể nhấn @@để lặp lại macro cuối cùng hoặc thậm chí dễ dàng hơn:

99@q

để lặp lại macro 99 lần.
Lưu ý: Số phải không chính xác khớp với các dòng.


0

Đối với những người có vấn đề tương tự nhưng với các dấu tách trường khác nhau, awkphương pháp này sẽ bảo vệ chính xác dấu tách trường:

$ cat file 
foo.bar.baz
baz.bar.foo
$ awk -F'.' 'sub(FS $NF,x)' file
foo.bar
baz.bar
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.