Làm cách nào tôi có thể sử dụng sed hoặc ex để thay thế một khối (mã nhiều dòng) bằng khối văn bản (mã) mới?


9

Tôi phải thay thế một khối lớn văn bản (mã script shell) trong một tệp bằng một khối văn bản khác.

Tôi ấn tượng với Làm thế nào tôi có thể sử dụng sed để thay thế một chuỗi nhiều dòng? trả lời bởi antakthay thế nhiều dòng được trả lời bởi Bruce Ediger

Nhưng tôi có một số rắc rối trong việc sử dụng chúng.

  1. antak đã đề cập trong câu trả lời của mình rằng việc truyền toàn bộ tệp ( 1h;2,$H;$!d;g;) vào bộ đệm là không nên đối với các tệp lớn, vì nó quá tải bộ nhớ.

  2. Tôi biết sedcó thể được sử dụng với tính năng khối để giữ văn bản bên ngoài khối không thay đổi. Tôi muốn sử dụng tính năng này. Nhưng nếu tôi sử dụng,

    sed -i '/marker1/,/marker2/s/.*/new text (code)/' filename
    

nó sẽ chèn văn bản mới (mã) nhiều lần cho mỗi luồng. Do đó, tôi phải tạo khối trực quan thành một luồng, sử dụng thứ gì đó tương tự như được đề xuất bởi antak trước đó, nhưng cho khối (không phải cho toàn bộ tệp).

  1. Như đã đề cập bởi Bruce Ediger tính năng phụ thêm của exmà bắt đầu với acấp với .(dot) có thể được cố gắng, nhưng văn bản mới của tôi (code) chứa dòng bắt đầu với dấu chấm, có thể được coi là dấu chấm cú pháp append. Làm thế nào tôi có thể sử dụng nó trong tình huống này?

  2. ex' ddSố dòng' có thể xóa nhiều dòng, nhưng nếu tôi có một khối nằm giữa / Marker1 / và / Marker2 / với số dòng không cố định (thay đổi) sẽ được thay thế bằng văn bản mới (mã), cách thực hiện nó không


Tôi thấy việc bạn sử dụng thuật ngữ "khối thị giác" khác thường và khó hiểu. Bạn có nghĩa đơn giản là một khối (nhóm) các dòng liên tiếp, đầy đủ?
Scott

Vâng, tôi đang chỉnh sửa câu hỏi để tránh nhầm lẫn.
tặng cho

Nguồn cho văn bản thay thế là gì? Có phải trong một tập tin hay là "chỉ trong tâm trí lập trình viên"?
don_crissti

Điều này là để vá tình huống của một kịch bản shell. Do đó, nguồn cho văn bản thay thế là tâm trí của lập trình viên (Hoặc một tập lệnh chính trên đó sedhoặc exlệnh hoạt động).
tặng cho

Don Crissti Tôi đã sử dụng rlệnh đọc tệp, để sao chép văn bản từ một tệp khác, nếu nguồn cho văn bản thay thế nằm trong một tệp.
tặng cho

Câu trả lời:


10

Tôi đề nghị sử dụng các c lệnh Hange (mà thực chất là một d elete kết hợp với một một ppend, mặc dù append chỉ áp dụng cho dòng cuối cùng trong phạm vi đó là chính xác những gì bạn muốn ở đây):

sed -i '/marker1/,/marker2/c\
New text 1\
New text 2' filename

Ở đây sử dụng sedcú pháp của GNU để chỉnh sửa tại chỗ ( -i). cLệnh đó là tiêu chuẩn và di động. GNU sedhỗ trợ:

sed '/marker1/,/marker2/cNew text 1\
New text 2' filename

như một phần mở rộng không chuẩn.

Các ký tự dòng mới và dấu gạch chéo ngược phải được thoát (có dấu gạch chéo ngược) trong văn bản thay thế.


Lệnh thay đổi hoạt động tốt cho cả hai sedexnhư nhau. Cảm ơn rât nhiều.
tặng cho

Có cách nào để tránh "\" và sử dụng tài liệu ở đây sednhư trong trường hợp excú pháp được đề xuất bởi Bruce Ediger trong Thay thế nhiều dòng .
tặng cho

Bạn sẽ không cần dấu gạch chéo ngược nếu bạn sử dụng rlệnh được thảo luận trong các câu trả lời khác cho câu hỏi đó. Tôi không chắc bạn sẽ sử dụng tài liệu ở đây như thế nào sed.
G-Man nói 'Phục hồi Monica'

8

Sử dụng GNU sed

Để thay thế các dòng bắt đầu khớp dòng 3và tiếp tục khớp dòng 5với New Code:

$ seq 8 | sed '/3/,/5/{/5/ s/.*/New Code/; t; d}'
1
2
New Code
6
7
8

Đối với các dòng trong phạm vi /3/,/5/, chúng tôi kiểm tra xem liệu dòng đó có khớp không 5(có nghĩa đây là dòng cuối cùng trong nhóm) và, nếu vậy, chúng tôi thực hiện thay thế để chèn New Code. Nếu thay thế được thực hiện, thì tlệnh sẽ cho sed nhảy đến cuối các lệnh (trong trường hợp New Codenày được in). Nếu không, dlệnh sẽ cho sed xóa dòng.

Tất cả các dòng khác được in bình thường.

Để thay đổi tập tin tại chỗ, -itùy chọn có thể được sử dụng:

sed -i.bak '/3/,/5/{/5/ s/.*/New Code/; t; d}' file

Sử dụng awk

Để làm tương tự bằng cách sử dụng awk:

$ seq 8 | awk '/3/,/5/{if (!f)print "New Code"; f=1; next}; 1'
1
2
New Code
6
7
8

Lệnh awk xử lý các dòng trong phạm vi /3/,/5/đặc biệt. Đối với các dòng trong phạm vi đó, chúng tôi kiểm tra xem fcó bằng không (nghĩa là nếu !fđúng) và, nếu vậy, chúng tôi in New Codevà đặt fthành 1 và sau đó chúng tôi bỏ qua các lệnh còn lại và nhảy đến nextdòng.

Đối với các dòng ngoài phạm vi /3/,/5/, không có bước nhảy nào được thực hiện và 1nguyên nhân khiến dòng được in. Chi tiết hơn, 1là một điều kiện. Bởi vì 1không phải là không, điều kiện đánh giá là đúng. Vì không có hành động nào được liên kết với điều kiện, nên hành động mặc định được thực hiện để in dòng. Do đó, tốc 1ký cho dòng in.

Để thay đổi một tệp tại chỗ, -i inplacetùy chọn có thể được sử dụng với GNU awk4.1 trở lên:

awk -i inplace '/3/,/5/{if (!f)print "New Code"; f=1; next} 1' file

mát mẻ. Tôi không giỏi lắm awk, bạn có thể vui lòng giải thích chút về awkbiểu hiện của bạn không
Rahul

1
@Rahul Chắc chắn rồi. Tôi đã thêm một lời giải thích về mã awk.
John1024

1
Cảm ơn John Đây chính xác là những gì tôi đang tìm kiếm.
tặng cho

Rất đơn giản để xóa khối sau đó thêm khối mới vào dòng cuối cùng:sed '/3/,/4/d;/5/cNew Code' awk '/5/{print "New Code"}/3/,/5/{next}1'
Costas

1

Dựa trên các cuộc thảo luận ở trên, tôi đưa ra một giải pháp bằng cách sử dụng ex

seq 15 > test1.txt
ex test1.txt << EOEX
/^7/,/^9/c
abcd
123
.xyz
hfr4
.
w!
q
EOEX
cat test1.txt

Ở trên cho

1
2
3
4
5
6
abcd
123
.xyz
hfr4
10
11
12
13
14
15

Cảm ơn g-man để làm cho tôi biết về lệnh thay đổi và làm rõ về dấu chấm. Cả hai sedexchia sẻ cú pháp gần như tương tự cho lệnh thay đổi (cũng cho lệnh xóa, lệnh chắp thêm, v.v.).

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.