chúng ta có thể in từ cuối cùng của mỗi dòng trong linux bằng lệnh sed không?


9

giả sử, nếu có một tập tin bao gồm các dòng sau, nếu chúng là

12345 567 7878 66

   er3 t45t y6y46y 


 4y6 y656y y5y

   46y6 65y7 y66uyuy

 yy46y6y

Đầu ra phải giống như:

66

y6y46y

y5y

y66uyuyy

y46y6y

Tôi đã thử sed 's/.* //g'tên tệp và một số sedlệnh khác , nhưng nó không hoạt động.

Tôi có thể biết sedlệnh chính xác là gì?


Có phải sử dụng sedkhông?
coffeMug

Câu trả lời:


8
awk '{print $NF}'
sed 's/[[:blank:]]*$//;s/.*[[:blank:]]//'

Điều đó vẫn sẽ in một dòng trống cho mỗi dòng trống. Để tránh nó:

awk 'NF{print $NF}'
sed 's/[[:blank:]]*$//;s/.*[[:blank:]]//;/./!d'

Biểu thức thay thế duy nhất : sed -n 's/.*[[:blank:]]\+\([^[:blank:]]\+\)[[:blank:]]*$/\1/p'.
jimmij

@jimmij - cái đó không hoạt động nếu chuỗi không trống cuối cùng cũng là chuỗi đầu tiên và không có khoảng trống nào trước nó. Ngoài ra, bạn cũng có thể chỉ cần làm .*ở phần đuôi, có lẽ - bạn loại trừ bất cứ điều gì ngoại trừ dấu vết trống dù thế nào w / .*[^[:blank:]].
mikeerv


4

Bạn co thể thử :

  • sed 's/.* //'
  • awk '{print $NF}'

4

Bạn đã gần tới. Chỉ cần xác định từ cuối cùng:

sed 's/^.* \([^ ][^ ]*\)/\1/g'

Những gì nó làm:

  1. '^. *' xóa mọi thứ trong đầu dòng và mọi khoảng trắng.
  2. '\ (...) \' khớp với mẫu và trả về là \ 1.
  3. '[^]' Phù hợp với mọi thứ mà không có khoảng trắng trong đó.

(Đã chỉnh sửa để thêm giải pháp tốt hơn. Cảm ơn Hildred!)


1
Đây là một biểu thức ngắn hơn: sed -r 's/.* ([^ ]+)/\1/g'nếu các biểu thức chính quy mở rộng được cho phép, thường là trường hợp.
mkalkov

Phiên bản ngắn hơn, sử dụng thay thế những gì bạn không muốn giữ thay vì những gì bạn muốn giữ:sed 's/.* //'
Uriel

2

Bạn có thể sử dụng một số mô hình đầy đủ grepthay vì sed, ví dụ:

grep -o "[a-Z0-9]*$"

Trong ví dụ này, [...]phạm vi chứa các ký tự được coi là phù hợp cho một "từ" (chữ số trong trường hợp này, các ký hiệu khác có thể được thêm vào, một số ký tự phải được thoát).


2
Điều đó giả định rằng không có khoảng trống ở cuối dòng. a-Zvì một phạm vi không có nhiều ý nghĩa, ngay cả trong các địa phương dựa trên ASCII. Lưu ý rằng đó -olà một phần mở rộng GNU.
Stéphane Chazelas 27/1/2015

0

Nếu bạn đủ điều kiện từ có nghĩa là bất kỳ chuỗi của 1 hoặc nhiều phi trống ký tự thì câu trả lời chắc chắn là có, và nó rất đơn giản được thực hiện là tốt. Điều này là do [[:blank:]]*[^[:blank:]]*là bổ sung boolean và - miễn là tất cả các ký tự trong một chuỗi hoàn tất - [[:blank:]]*U [^[:blank:]]*có thể mô tả bất kỳ chuỗi nào có thể theo cách tương tự .*.

Nếu một ký tự không đầy đủ hoặc chuỗi byte không hợp lệ tồn tại trong một chuỗi thì không thể mô tả thành công nó từ đầu đến cuối - như đôi khi có thể xảy ra khi diễn giải một chuỗi trong mã hóa sai. Để đảm bảo một ký tự hoàn chỉnh trên mỗi byte trong bất kỳ chuỗi nào, ngôn ngữ C có thể được buộc như sau:

LC_ALL=C sed ...

... sẽ tránh mọi vấn đề mô tả chuỗi từ đầu đến đuôi với một mẫu bao gồm tất cả, chẳng hạn như .*hoặc([ ]*[^ ]*)*

Một mô hình bổ sung đầy đủ có thể lặp lại nhiều lần khi cần thiết từ trái sang phải độ dài của bất kỳ chuỗi nào để hạ cánh ở lần xuất hiện cuối cùng mà không có bất kỳ sự phá vỡ nào trong mẫu. Đây là, chắc chắn, ngôn ngữ thường xuyên.

BRE:

sed 's/\(\([^[:blank:]]*\)[[:blank:]]*\)*/\2/'

ERE:

sed -E 's/(([^[:blank:]]*)[[:blank:]]*)*/\2/'

Cả hai phiên bản này vẫn sẽ in các dòng trống và điều này là do *ngôi sao Kleene khớp với 0 hoặc nhiều lần xuất hiện của một mẫu. Đầu tiên, nó khớp với 0 hoặc nhiều hơn các ký tự trống, sau đó là 0 hoặc nhiều ký tự trống, sau đó là 0 hoặc nhiều lần xuất hiện của các kết quả khớp nhóm cho đến khi nó khớp toàn bộ chuỗi.

Đã khớp với tất cả những điều này, phép màu xảy ra trong sự thay thế - các tham chiếu được trả về bởi các nhóm \1\2là lần xuất hiện cuối cùng của mỗi nhóm. Vì vậy, khi thay thế được thực hiện, tất cả các chuỗi được thay thế chỉ với lần xuất hiện cuối cùng trên một dòng bằng 0 hoặc nhiều hơn các ký tự trống - hoặc nhóm con \2.

Tất nhiên, điều này hoạt động cho bất kỳ chuỗi nào có thể - ngay cả một chuỗi trống - có nghĩa là cả hai biểu mẫu sẽ in các ký tự dòng mới cho các dòng chỉ chứa các ký tự trống hoặc không có ký tự nào cả. Để xử lý việc này, có một vài điều bạn có thể làm, nhưng trước tiên hãy làm cho lớp nhân vật dễ nhập hơn một chút:

b='[:blank:]'

Bây giờ, chỉ in nếu một dòng chứa một hoặc nhiều ký tự trống bạn có thể làm:

BRE:

sed -n "s/\(\([^$b]*\)[$b]*\)*/\2/;/./p"

ERE:

sed -En "/[^$b]/s/(([^$b]*)[$b]*)*/\2/p"
  1. Trường hợp BRE - sự thay thế luôn được thực hiện và chỉ các không gian mẫu có ít nhất một ký tự còn lại được in.
  2. Trường hợp ERE - sự thay thế chỉ được thử trên một không gian mẫu có chứa ít nhất một char không trống.

Một trong hai hình thức sẽ hoạt động với một trong hai phương thức - miễn là cú pháp đúng.

Công -ntắc vô hiệu hóa tự động in không gian mẫu và pcờ vào s///ubstlation hoặc các lệnh /địa chỉ chỉ /in kết quả của nó nếu thành công.

Logic tương tự này cũng có thể được áp dụng để có được bất kỳ {num}sự xuất hiện nào, như, như:

BRE:

sed -n "s/\([$b]*\([^$b]\{1,\}\)\)\{num\}.*/\2/p"

ERE:

sed -En "s/([$b]*([^$b]+)){num}.*/\2/p"

... Trong đó numcả hai biểu thức chính có thể được thay thế bằng một số để chỉ in {num}lần xuất hiện được chỉ định của một chuỗi các ký tự không trống. Một hình thức hơi khác nhau được sử dụng ở đây để đảm bảo số lượng không bị sai lệch cho không gian hàng đầu trong một chuỗi.

Lưu ý rằng -EERE chuyển sang sedđược hỗ trợ trong cả BSD và các phiên bản GNU, mặc dù nó không phải là chưa POSIX cú pháp chuẩn.


Giải thích hay, hack hay, nhưng lưu ý rằng nó sẽ không hoạt động với các sed triển khai truyền thống (như Solaris / usr / bin / sed) và sẽ đắt hơn so với cách tiếp cận đơn giản hơn (làm cạn kiệt bộ nhớ với các dòng đầu vào dài hơn 25 ký tự với các sed_su3từ toolchest Heirloom ví dụ). Vì vậy, mặc dù tôi thích câu trả lời, tôi sẽ không đề xuất cách tiếp cận đó.
Stéphane Chazelas 2/2/2015

Dường như không hoạt động trong FreeBSD.
Stéphane Chazelas 2/215

@ StéphaneChazelas - vâng, hiệu suất thực sự khủng khiếp cho một thứ như thế này, nhưng nó có thể rất hiệu quả để chọn ra các lần xuất hiện được đánh số. Và đối với một trường hợp cuối dòng s/.* \([^[:blank:]]\{1,\}\).*/\1/là tốt hơn nhiều, nhưng khó khăn hơn khi nhiều dòng có liên quan. Tuy nhiên, mới hôm nọ, tôi phát hiện ra 's/\(\n\)*/\1/g;s/\n\(\n.*\)*/&&/[num];s///[samenum]có thể lên bờ khá hiệu quả. Dù sao, miễn là không có lỗi rõ ràng trong logic thì tôi rất vui - tôi chỉ nghĩ rằng mình đã bỏ lỡ điều gì đó.
mikeerv

@ StéphaneChazelas - ồ, và về những người lớn tuổi hơn sed- điều đó hơi lạ - nó phải là âm thanh theo tiêu chuẩn. xrat nói ... Các nhà phát triển tiêu chuẩn đã xem xét hành vi lịch sử phổ biến, hỗ trợ "\n*", nhưng không "\n\{min,max\}", "\(...\)*", hoặc "\(...\)\{min,max\}", là kết quả không cố ý của việc triển khai cụ thể và họ hỗ trợ cả hai biểu thức sao chép và khoảng sau các biểu hiện phụ và tham chiếu ngược.
mikeerv 3/2/2015

@ StéphaneChazelas - Và tiêu chuẩn cho biết ... Nếu biểu hiện phụ được tham chiếu bởi tham chiếu ngược khớp với nhiều chuỗi vì dấu hoa thị ( '*' )hoặc biểu thức khoảng (xem mục (5)), tham chiếu ngược sẽ khớp với cuối cùng (ngoài cùng bên phải ) của các chuỗi này. Tôi khá chắc chắn rằng tôi đã thử nghiệm cái này minisedmặc dù - chắc chắn tôi đã thử nghiệm thứ gì đó kỳ lạ minisedvào ngày khác.
mikeerv

-1

Đúng. Lệnh sed sau đây trước tiên loại bỏ tất cả các khoảng trắng theo sau ( s/ *$//) và sau đó mọi thứ lên đến và bao gồm cả khoảng trắng cuối cùng ( s/.* //). Có lẽ đáng để thay thế khoảng trắng theo nghĩa đen bằng [[:blank:]]cách chụp các tab và các ký tự giống như không gian khác.

$ echo "  aaa bbb cc   " | sed -e 's/ *$//' -e 's/.* //'
cc
$ echo "  aaa bbb cc" | sed -e 's/ *$//' -e 's/.* //'
cc
$ echo "aaa bbb cc   " | sed -e 's/ *$//' -e 's/.* //'
cc
$ echo "aaa bbb cc" | sed -e 's/ *$//' -e 's/.* //'
cc
$ echo "  cc  " | sed -e 's/ *$//' -e 's/.* //'
cc
$ echo "cc" | sed -e 's/ *$//' -e 's/.* //'
cc

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.