Câu trả lời:
Sử dụng dấu phân cách regex thay thế vì sed
cho phép bạn sử dụng bất kỳ dấu phân cách nào ( bao gồm cả các ký tự điều khiển ):
sed "s~$var~replace~g" $file
$var
Một câu trả lời cơ bản thuần túy: sử dụng mở rộng tham số để thoát khỏi dấu gạch chéo ngược bất kỳ dấu gạch chéo nào trong biến:
var="/Users/Documents/name/file"
sed "s/${var//\//\\/}/replace/g" $file
${parameter/pattern/string}
. Vì vậy, trong trường hợp này, tham số là var
, mẫu là /\/
và chuỗi là \\/
. Tất cả các bản sao của mẫu được thay thế vì mẫu bắt đầu bằng a /
.
Sử dụng /
sed làm dấu phân tách sẽ xung đột với các dấu gạch chéo trong biến khi được thay thế và kết quả là bạn sẽ gặp lỗi. Một cách để tránh điều này là sử dụng một dấu phân tách khác là duy nhất từ bất kỳ ký tự nào có trong biến đó.
var="/Users/Documents/name/file"
bạn có thể sử dụng ký tự octothorpe phù hợp với dịp (hoặc bất kỳ ký tự nào khác không phải là ký tự /
để dễ sử dụng)
sed "s#$var#replace#g"
hoặc là
sed 's#$'$var'#replace#g'
điều này phù hợp khi biến không chứa khoảng trắng
hoặc là
sed 's#$"'$var'"#replace#g'
Sẽ khôn ngoan hơn khi sử dụng cách trên vì chúng ta chỉ quan tâm đến việc thay thế bất cứ thứ gì có trong biến đó so với việc trích dẫn kép toàn bộ lệnh có thể khiến shell của bạn xen vào bất kỳ ký tự nào có thể được coi là ký tự shell đặc biệt vào shell.
$var
chứa của bạn ~
, rõ ràng bạn sẽ cần phải chọn một dấu phân cách khác. Lỗi "chưa chấm dứt" có vẻ như của bạn $var
chứa một dòng mới; bạn có thể sửa nó bằng cách thoát dấu gạch chéo ngược mỗi dòng mới trong giá trị, nhưng tôi không nghĩ rằng điều này là hoàn toàn di động. Điều này nói chung không liên quan đến vấn đề giảm giá trị.
sed -i "s~blah~$var~g" file
chỉ với trích dẫn xung quanh sed
kịch bản thực tế .
Đây là một câu hỏi cũ, nhưng không có câu trả lời nào ở đây thảo luận về các hoạt động ngoài s/from/to/
chi tiết.
Hình thức chung của một sed
tuyên bố là
*address* *action*
trong đó địa chỉ có thể là phạm vi regex hoặc phạm vi số dòng (hoặc trống, trong trường hợp đó, hành động được áp dụng cho mọi dòng đầu vào). Ví dụ
sed '1,4d' file
sẽ xóa các dòng từ 1 đến 4 ( địa chỉ là dải số dòng 1,4
và hành động là d
lệnh xóa); và
sed '/ick/,$s/foo/bar/' file
sẽ thay thế lần xuất hiện đầu tiên của foo
bằng bar
trên bất kỳ dòng nào giữa khớp đầu tiên trên regex ick
và phần cuối của tệp ( địa chỉ là phạm vi /ick/,$
và hành động là s
lệnh thay thế s/foo/bar/
).
Trong bối cảnh này, nếu ick
đến từ một biến, bạn có thể làm
sed "/$variable/,\$s/foo/bar/"
(lưu ý việc sử dụng dấu ngoặc kép thay vì dấu đơn, để trình bao có thể nội suy biến và sự cần thiết phải trích dẫn ký hiệu đô la bên trong dấu ngoặc kép) nhưng nếu biến chứa dấu gạch chéo, bạn sẽ gặp lỗi cú pháp. (Trình bao mở rộng biến, sau đó chuyển chuỗi kết quả đến sed
; vì vậy sed
chỉ nhìn thấy văn bản theo nghĩa đen - nó không có khái niệm về các biến của trình bao.)
Cách chữa là sử dụng một dấu phân cách khác (trong đó rõ ràng là bạn cần có thể sử dụng một ký tự không thể xuất hiện trong giá trị của biến), nhưng không giống như trong s%foo%bar%
trường hợp này, bạn cũng cần một dấu gạch chéo ngược trước dấu phân cách nếu bạn muốn sử dụng một ký tự khác dấu phân cách so với mặc định /
:
sed "\\%$variable%,\$s/foo/bar/" file
(bên trong dấu nháy đơn, một dấu gạch chéo ngược rõ ràng là đủ); hoặc bạn có thể thoát riêng từng dấu gạch chéo trong giá trị. Cú pháp cụ thể này chỉ là Bash:
sed "/${variable//\//\\/}/,\$s/foo/bar/" file
hoặc nếu bạn sử dụng một vỏ khác, hãy thử
escaped=$(echo "$variable" | sed 's%/%\\/%g')
sed "s/$escaped/,\$s/foo/bar/" file
Để rõ ràng, nếu $variable
chứa chuỗi 1/2
thì các lệnh trên sẽ tương đương với
sed '\%1/2%,$s/foo/bar/' file
trong trường hợp đầu tiên, và
sed '/1\/2/,$s/foo/bar/' file
trong lần thứ hai.
Sử dụng Perl, trong đó các biến là công dân hạng nhất, không chỉ mở rộng macro:
var=/Users/Documents/name/file perl -pe 's/\Q$ENV{var}/replace/g' $file
-p
đọc từng dòng đầu vào và in dòng sau khi xử lý\Q
trích dẫn tất cả các siêu ký tự trong chuỗi sau (không cần thiết cho giá trị được trình bày ở đây, nhưng cần thiết nếu giá trị chứa [
hoặc một số giá trị khác đặc biệt đối với các phép tính thông thường)