Câu hỏi Sử dụng sed để thay thế chuỗi ký tự đặc biệt trong tệp XML


Tôi gặp khó khăn khi lấy sed để thay thế một chuỗi văn bản trong một tệp XML, mặc dù thực tế là tôi không gặp khó khăn khi sử dụng grep để tìm cùng chuỗi đó. Kể từ khi chuỗi mới và chuỗi cũ được thay thế chứa rất nhiều ký tự đặc biệt, tôi nghĩ tốt nhất là lưu trữ chúng trong các biến thay vì sử dụng một loạt các dấu gạch chéo ngược:

OLD_STRING='<property name="webServiceHost">${jboss.bind.address}</property>'
NEW_STRING='<!--<property name="webServiceHost">${jboss.bind.address}</property>-->'

Các chuỗi xuất hiện để được lưu trữ như mong đợi:

$ echo $OLD_STRING; echo $NEW_STRING
<property name="webServiceHost">${jboss.bind.address}</property>
<!--<property name="webServiceHost">${jboss.bind.address}</property>-->

Grep'ing xác nhận chuỗi cũ có trong tệp XML:

$ grep "$OLD_STRING" jboss-beans.xml
<property name="webServiceHost">${jboss.bind.address}</property>

Nhưng lệnh sed sau đây không tạo ra kết quả nào:

sed -i 's/"$OLD_STRING"/"$NEW_STRING"/g' jboss-beans.xml

Bất kỳ ý tưởng những gì tôi đang thiếu ở đây?


4
2018-04-29 20:26


gốc




Các câu trả lời:


Đặt các biến shell trong dấu nháy đơn sẽ vô hiệu hóa cách diễn dịch của chúng. Đó là lý do tại sao lệnh của bạn không có hiệu lực.

$ echo  's/"$OLD_STRING"/"$NEW_STRING"/g'
s/"$OLD_STRING"/"$NEW_STRING"/g

Nó nên được viết như thế:

sed -i "s/'$OLD_STRING'/'$NEW_STRING'/g" jboss-beans.xml

Nhưng sau đó các biến được diễn giải trước gọi điện thoại sed và một lần nữa chứa các ký tự đặc biệt:

$ echo  "s/'$OLD_STRING'/'$NEW_STRING'/g"
s/'<property name="webServiceHost">${jboss.bind.address}</property>'/'<!--<property name="webServiceHost">${jboss.bind.address}</property>-->'/g

Vì lý do đó sed có tính năng đặc biệt này cho phép xác định s/// dấu phân tách lệnh bằng cách đơn giản sử dụng chúng, ví dụ:

sed -i "s#'$OLD_STRING'#'$NEW_STRING'#g" jboss-beans.xml

Biểu thức tìm kiếm của bạn chứa các ký tự regexp đặc biệt và sử dụng sed như thế này chỉ là phí phạm các khả năng của nó. Tôi sẽ viết các biểu thức như thế này:

sed -i 's/\(<.*webServiceHost.*jboss.bind.address.*>\)/<!--\1-->/' jboss-beans.xml

Tất nhiên bạn có thể làm cho chuỗi trận đấu nhiều hơn hoặc ít hơn cụ thể theo nhu cầu của bạn. Ngoài ra còn có tính năng tốt đẹp khác có thể giúp đỡ. sed cho phép thu hẹp hoạt động chỉnh sửa đối với các dòng khớp với mẫu cụ thể. Lệnh của bạn có thể trông như thế này:

sed -i '/webServiceHost/ s/^\(.*\)$/<!--\1-->/' jboss-beans.xml

2
2018-04-29 21:42



À vâng, tôi đã hoàn toàn quên mất việc sử dụng \ 1 để giữ một phần của mẫu trong các biểu thức thông thường và / hoặc sed. Cảm ơn! Thật không may, dường như vẫn còn một chút diễn giải sai đang diễn ra: $ sed -i 's|(<.*webServiceHost.*jboss.bind.address.*>)|<!--\1-->|' jboss-beans.xml: -e expression #1, char 55: invalid reference \1 on s' command's RHS   Tôi cũng đã thử thêm dấu gạch chéo ngược trước cả hai dấu ngoặc đơn, nhưng một lần nữa tôi nhận được không có đầu ra. - rolinrok
@rolinrok Vâng, sai lầm của tôi. Tôi đã quên về các dấu gạch chéo ngược trước dấu ngoặc đơn. Đối với 'không có vấn đề đầu ra' nó sẽ giúp nếu bạn đặt một phần của tệp XML bạn muốn nhận xét với một số dòng trước và sau nó. Ví dụ của tôi giả định rằng các thuộc tính của bạn là một mình trong một dòng để toàn bộ dòng được nhận xét, nhưng đó có thể là giả định sai. - Rajish
Hiểu rồi! Đã được mong đợi để xem sự thay đổi về sản lượng tiêu chuẩn trong quá trình thử nghiệm, nhưng quên tôi đã sử dụng tùy chọn -i. Sau khi kiểm tra tệp, tôi nhận thấy nhiều ký tự nhận xét xung quanh chuỗi mong muốn. Cảm ơn một lần nữa! - rolinrok
@rolinrok Vui vì tôi có thể giúp bạn. Sẽ tốt nếu bạn chấp nhận câu trả lời;) - Rajish
Làm xong! Xin lỗi vì sự chậm trễ - Vẫn là một siêu người dùng noob và chỉ vừa mới nhận ra tôi quên chấp nhận câu trả lời của bạn :) - rolinrok


Điều này có thể hữu ích cho bạn:
Thao tác XML dòng lệnh
http://xmlstar.sourceforge.net/

AFAICR
apt-get install xmlstarlet


0
2017-08-09 15:24