Làm thế nào tôi có thể xóa mọi thứ cho đến khi một mẫu và mọi thứ sau một mẫu khác từ một dòng?


16

Trong tệp sau:

Lorem ipsum dolor ngồi amet, consectetuer adipiscing elit. Ut eu metus id speechus vestibulum ultrices. Maecenas rhoncus.

Tôi muốn xóa mọi thứ trước consectetuervà mọi thứ sau elit.

Đầu ra mong muốn của tôi:

consectetuer adipiscing elit.

Tôi có thể làm cái này như thế nào?


2
Lệnh có thể sed. Nó cũng có thể perl, hoặc thậm chí là bash tinh khiết.
muru

@manuel Nếu một trong những câu trả lời này giải quyết được vấn đề của bạn, vui lòng dành chút thời gian và chấp nhận nó bằng cách nhấp vào dấu kiểm bên trái. Điều đó sẽ đánh dấu câu hỏi đã được trả lời và là cách cảm ơn được thể hiện trên các trang web Stack Exchange.
terdon

Câu trả lời:


27

Tôi sẽ sử dụng sed

sed 's/^.*\(consectetuer.*elit\).*$/\1/' file

Giải mã cú pháp sed s / find / thay thế / cú pháp:

  • s/^.*- thay thế bắt đầu từ đầu dòng ( ^) theo sau là bất cứ thứ gì ( .*) cho đến ...
  • \( - bắt đầu một khối được đặt tên
  • consectetuer.*elit\.- khớp từ đầu tiên, mọi thứ ( .*) cho đến từ cuối cùng (trong trường hợp này, bao gồm cả dấu chấm (thoát)) mà bạn muốn khớp
  • \) - kết thúc khối được đặt tên
  • nối mọi thứ khác ( .*) với cuối dòng ( $)
  • / - kết thúc phần tìm kiếm thay thế
  • \1- thay thế bằng khối tên giữa \(\)trên
  • / - kết thúc thay thế

1
Câu trả lời hay, nhưng bạn không cần ^hoặc $vì sed sẽ thử và tìm trận đấu dài nhất. Ngoài ra, bạn có thể đã bỏ lỡ dấu chấm sau elit, bạn có thể chèn \.nếu cần thiết.
asoundmove

2
@asoundmove Bắt tốt trên dấu chấm trên "elit." - bạn có một đôi mắt khá sắc nét!. Tôi đã cập nhật câu trả lời của mình để bao gồm dấu chấm thoát trong mẫu. Bạn cũng chính xác rằng ^$không cần thiết - tôi đã để họ ở đó vì người hỏi đã lưu ý (ban đầu) rằng anh ta là một người mới bắt đầu và điều này có thể hữu ích trong các bối cảnh khác.
MikeV

Tôi đã luôn sao chép các giải pháp sed đã dán và hack chúng để phù hợp với nhu cầu của tôi nhưng nhờ câu trả lời này mà tôi cảm thấy như bây giờ tôi thực sự hiểu nó. Câu trả lời tuyệt vời
Tyler

6

Nếu mỗi dòng chứa cả mẫu bắt đầu và kết thúc thì cách dễ nhất để làm điều này là với grep. Thay vì xóa phần đầu và phần cuối của mỗi dòng, bạn chỉ cần xuất nội dung giữa cả hai mẫu. Các -otùy chọn trong GNU grepkết quả đầu ra chỉ các trận đấu:

grep -o 'consectetuer.*elit' file

Lưu ý: như đã đề cập, điều này chỉ hoạt động nếu mọi dòng trong tệp có thể được phân tích cú pháp theo cách này. Sau đó, một lần nữa, đó là 80% của tất cả các trường hợp sử dụng điển hình.


1

Hai vòng lặp trong AWK:

$ awk '{for(i=1;i<=NF;i++) {if ($i == "consectetuer") beginning=i; if($i== "elit.") ending=i }; for (j=beginning;j<=ending;j++) printf $j" ";printf "\n"   }' file.txt 
consectetuer adipiscing elit.

Gsub của AWK:

$ awk '{gsub(/^.*consectetuer/,"consectetuer"); gsub(/elit.*$/,"elit.");print}' file.txt
consectetuer adipiscing elit.

1

Một cách Perl. Điều này về cơ bản giống như câu trả lời của MikeVsed :

perl -pe 's/.*(consectetuer.*elit).*./$1/' file

-pnghĩa là "in mọi dòng sau khi áp dụng tập lệnh được cung cấp với -e". Các s/foo/bar/là các nhà điều hành thay thế; nó sẽ thay thế foobằng bar. Các dấu ngoặc đơn nắm bắt một mẫu và cho chúng tôi sử dụng nó trong thay thế. Mẫu đầu tiên được chụp là $1, mẫu thứ hai $2và cứ thế.

Vì vậy, lệnh sẽ khớp mọi thứ lên đến consectetuer( .*consectetuer), sau đó là mọi thứ cho đến khi elit( .*elit) và sau đó là mọi thứ khác cho đến hết dòng ( .*) và sẽ thay thế nó bằng mẫu đã chụp.


1

Tôi không chắc tại sao tiêu đề câu hỏi này đã được chỉnh sửa " từ tệp " thành " từ một dòng " trong khi OP không loại trừ khả năng trên nhiều dòng mặc dù ví dụ này dường như chỉ là một dòng. Dù thế nào, nó có thể hữu ích để cung cấp giải pháp nhiều dòng ở đây.

Điều này hoạt động cho dòng chéo:

from1=consectetuer; to2=elit; a="$(cat file)"; a="$(echo "${a#*"$from1"}")"; echo "$from1${a%%"$to2"*}$to2"

Ví dụ:

[xiaobai@xiaobai tmp]$ cat file
1
abc consectetuer lsl

home

def elit dd
2 consectetuer ABC elit
[xiaobai@xiaobai tmp]$ from1=consectetuer; to2=elit; a="$(cat file)"; a="$(echo "${a#*"$from1"}")"; echo "$from1${a%%"$to2"*}$to2"
consectetuer lsl

home

def elit
[xiaobai@xiaobai tmp]$ 

tham khảo: Mở rộng tham số Shell


1
Thật hoàn hảo!
Clément
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.