Làm cách nào để thay thế một phần của tệp văn bản giữa các điểm đánh dấu bằng một tệp văn bản khác?


26

Nói rằng tôi có một tệp văn bản như thế này:

# custom content section
a
b

### BEGIN GENERATED CONTENT
c
d
### END GENERATED CONTENT

Tôi muốn thay thế phần giữa các GENERATED CONTENTthẻ bằng nội dung của tệp khác.

Cách đơn giản nhất để làm điều này là gì?

Câu trả lời:


36
lead='^### BEGIN GENERATED CONTENT$'
tail='^### END GENERATED CONTENT$'
sed -e "/$lead/,/$tail/{ /$lead/{p; r insert_file
        }; /$tail/p; d }"  existing_file

Xuất sắc. sedcó thể làm rất nhiều hơn chỉ là s/.../...!
DevSolar

Hmmm không hoạt động với tôi, tôi có nên đặt lệnh sed trên một dòng không?
lzap

3
Các r insert_filelệnh phải là điều cuối cùng trên đường dây của nó. Lưu ý rằng không có khoảng trắng cũng như bình luận nào được cho phép sau nó. Mã được kiểm tra bằng GNU sedvới --posixtùy chọn được kích hoạt và nó hoạt động như mong đợi, do đó, mã này sẽ hoạt động với bất kỳ tuân thủ posix nào sed.
Peter.O

1
Holy moly, thật tuyệt! Đây là trong từ điển sed của tôi! Cực kỳ hữu ích và đẹp đơn giản. Cảm ơn bạn!
DanielSmedegaardBuus

2
Lưu ý chỉnh sửa tại chỗ yêu cầu bạn nắm bắt đầu ra của sed (ví dụ output=$(sed -e "..." existing_file)) và sau đó thực hiện thay thế trong một lượt thứ hai (ví dụ echo "$output" > existing_file) vì cố gắng chuyển hướng vào một tệp bạn đang đọc sẽ khiến nó bị cắt trước khi đọc nội dung.
Chris Tonkinson

5
newContent=`cat new_file`
perl -0777 -i -pe "s/(### BEGIN GENERATED CONTENT\\n).*(\\n### END GENERATED CONTENT)/\$1$newContent\$2/s" existing_file

Công việc tốt. Đơn giản hơn tôi nhiều. :)
Bác sĩ Kitty

4

Cảnh báo: Đây chắc chắn không phải là cách đơn giản nhất để làm điều đó. (EDIT: bash hoạt động; POSIX grep cũng tốt)

Nếu văn bản chính nằm trong tệp "chính" và nội dung được tạo trong tệp "gen", bạn có thể thực hiện các thao tác sau:

#!/bin/bash
BEGIN_GEN=$(cat main | grep -n '### BEGIN GENERATED CONTENT' | sed 's/\(.*\):.*/\1/g')
END_GEN=$(cat main | grep -n '### END GENERATED CONTENT' | sed 's/\(.*\):.*/\1/g')
cat <(head -n $(expr $BEGIN_GEN - 1) main) gen <(tail -n +$(expr $END_GEN + 1) main) >temp
mv temp main

Nó có hoạt động không? Tôi nghĩ rằng dòng cuối cùng của bạn sẽ mở mainđể viết, xóa nó, trước khi nó được đọc bởi con mèo.
chepner

@chepner Crap, bạn nói đúng. Phần còn lại hoạt động, mặc dù. Tôi sẽ sửa chữa nó.
Bác sĩ Kitty

3
ed -s FILE1 <<EOF
/### BEGIN GENERATED/+,/### END GENERATED/-d
/### BEGIN GENERATED/ r FILE2
w
q
EOF

Sử dụng một heredoc và biên tập dòng ed. Dòng đầu tiên bên trong heredoc là xóa 'd' dòng sau '+' '### BEGIN GENERATED ...' và dòng trước '-' '### END GENERATED ...' dòng thứ hai là chèn FILE2 sau dòng ### END GENERATED ... '
Jetchisel

xin lỗi, ý tôi là đã chèn FILE2 sau dòng '### BEGIN GENERATED ..'
Jetchisel

Làm cho nó dễ dàng với tôi, đó là sau lần đầu tiên của tôi :-). Ngoài ra tôi có thể đã sử dụng từ tương tự nhưng giải pháp khác không sử dụng heredocs mà là printf và pipe. Bất cứ cách nào xin lỗi nếu tôi đã phạm sai lầm :-)
Jetchisel

Cảm ơn, rất dễ đọc! Btw - thay vì r FILE2bạn có thể nói r !commandđể đọc từ một tập lệnh khác.
Kos
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.