Làm thế nào để thay thế chuỗi chứa dấu gạch chéo với sed?


147

Tôi có một dự án Visual Studio, được phát triển tại địa phương. Các tập tin mã phải được triển khai đến một máy chủ từ xa. Vấn đề duy nhất là URLsthey chứa mã hóa cứng.

Dự án chứa URLS, chẳng hạn như ? Page = one . Để liên kết có hiệu lực trên máy chủ, nó phải là / page / one .

Tôi đã quyết định thay thế tất cả các URL trong bộ mã của mình bằng sed trước khi triển khai, nhưng tôi bị kẹt trong dấu gạch chéo.

Tôi biết đây không phải là một giải pháp hay, nhưng nó đơn giản sẽ giúp tôi tiết kiệm rất nhiều thời gian. Tổng số chuỗi tôi phải thay thế ít hơn 10. Tổng số tệp phải kiểm tra là ~ 30.

Ví dụ mô tả tình huống của tôi là dưới đây:

Lệnh tôi đang sử dụng:

sed -f replace.txt < a.txt > b.txt

thay thế chứa tất cả các chuỗi:

s/?page=one&/pageone/g
s/?page=two&/pagetwo/g
s/?page=three&/pagethree/g

a.txt:

?page=one&
?page=two&
?page=three&

Nội dung của b.txt sau khi tôi chạy lệnh sed:

pageone
pagetwo
pagethree

Những gì tôi muốn b.txt chứa:

/page/one
/page/two
/page/three


Câu trả lời:


274

Cách dễ nhất là sử dụng một dấu phân cách khác trong các dòng tìm kiếm / thay thế của bạn, ví dụ:

s:?page=one&:pageone:g

Bạn có thể sử dụng bất kỳ ký tự nào làm dấu phân cách không phải là một phần của chuỗi. Hoặc, bạn có thể thoát nó bằng dấu gạch chéo ngược:

s/\//foo/

Mà sẽ thay thế /bằng foo. Bạn muốn sử dụng dấu gạch chéo ngược đã thoát trong trường hợp bạn không biết ký tự nào có thể xảy ra trong chuỗi thay thế (ví dụ: nếu chúng là biến shell).


1
> Hoặc, bạn có thể thoát nó bằng dấu gạch chéo ngược. Một ví dụ về điều đó sẽ hữu ích hơn, vì bạn không phải lúc nào cũng biết các ký tự trong chuỗi để có thể chọn thứ gì đó khác. ví dụ: cái này: echo / | sed s / \ // a / g không hoạt động: sed: -e biểu thức # 1, char 5: tùy chọn không xác định đối với `s '
Max Waterman

1
Bạn có thể thêm một sau đó? Cảm ơn :) Tôi thấy xung quanh trong dấu ngoặc kép dường như hoạt động: echo / | sed "s / \ // a / g"
Max Waterman

@MaxWaterman là quy trình hoạt động tiêu chuẩn khi sử dụng sedlệnh regex được đặt trong dấu ngoặc kép. Tôi đã không sử dụng chúng trong câu trả lời của mình vì tôi không hiển thị toàn bộ seddòng lệnh mà chỉ là sedchuỗi lệnh regex như OP đã làm. Nếu bạn đặt nó trong một tệp, như OP đã làm, bạn không cần dấu ngoặc kép.
lừa đảo

Vâng, đủ công bằng (mặc dù có lẽ nó có thể được đề cập). Ví dụ đó giúp. Tôi đã tìm thấy tôi cần phải đưa vào rất nhiều dấu gạch chéo ngược đôi khi ... và nó thực sự gây nhầm lẫn. ví dụ: -e "s / '/ \\\\\\ & / g" Tôi nghĩ rằng văn bản sai, mặc dù: "Cái nào sẽ thay thế \ bằng foo" - nên là "Cái nào sẽ thay thế / bằng foo", không?
Max Waterman

@MaxWaterman cảm ơn vì đã nắm bắt được điều đó trên \ vs. /. Đã sửa nó. Nếu bạn có một sedlệnh trong tập lệnh shell, thì có thể cần thêm dấu gạch chéo ngược (mỗi dấu gạch chéo ngược cần được gạch chéo lại).
lừa đảo

105

Các slệnh có thể sử dụng bất kỳ ký tự như một dấu phân cách; bất cứ nhân vật nào đến sau khi sđược sử dụng. Tôi đã được đưa lên để sử dụng a #. Thích như vậy:

s#?page=one&#/page/one#g

5
Trang man cho BSD sed trên OS X nói về lệnh s : Thay thế chuỗi thay thế cho phiên bản đầu tiên của biểu thức chính quy trong không gian mẫu. Bất kỳ ký tự nào khác ngoài dấu gạch chéo ngược hoặc dòng mới có thể được sử dụng thay vì dấu gạch chéo để phân định RE và thay thế. Tôi đặt cược tiền mà trang man cho GNU sed nói điều gì đó tương tự.
Tom Anderson

Câu trả lời được chấp nhận hiện tại về cơ bản giống như câu trả lời này, và đã được đăng trước đó một phút!
Tom Anderson

61

Một thực tế rất hữu ích nhưng ít được biết đến về sed là s/foo/bar/lệnh quen thuộc có thể sử dụng bất kỳ dấu câu nào, không chỉ dấu gạch chéo. Một thay thế phổ biến là s@foo@bar@, từ đó nó trở nên rõ ràng làm thế nào để giải quyết vấn đề của bạn.


Lời khuyên thiên tài khi bạn muốn thay thế cho dấu gạch chéo về phía trước. Cảm ơn!
mbb

9

thêm \ trước các ký tự đặc biệt:

s/\?page=one&/page\/one\//g

Vân vân.


4
Tôi có thể đã bỏ lỡ điều gì đó, nhưng tôi đã thử điều này và nó dường như không hoạt động. Nó dường như là điều rõ ràng để thử, nhưng giả sử tôi đúng và nó thực sự không hoạt động, tại sao lại đăng nó?
codenoob

4
@codenoob (và bất kỳ ai khác đến đây) - 's' ở đầu là bắt buộc. s/foo\/bar/foo_bar/sẽ làm việc, nhưng /foo\/bar/foo_bar/sẽ không.
MynockSpit

5

Trong một hệ thống tôi đang phát triển, chuỗi được thay thế bởi sed là văn bản đầu vào từ người dùng được lưu trữ trong một biến và được chuyển đến sed.

Như đã lưu ý trước đó trong bài đăng này, nếu chuỗi chứa trong khối lệnh sed chứa dấu phân cách thực tế được sử dụng bởi sed - thì sed chấm dứt do lỗi cú pháp. Hãy xem xét ví dụ sau:

Những công việc này:

$ VALUE=12345
$ echo "MyVar=%DEF_VALUE%" | sed -e s/%DEF_VALUE%/${VALUE}/g
MyVar=12345

Điều này phá vỡ:

$ VALUE=12345/6
$ echo "MyVar=%DEF_VALUE%" | sed -e s/%DEF_VALUE%/${VALUE}/g
sed: -e expression #1, char 21: unknown option to `s'

Thay thế dấu phân cách mặc định không phải là một giải pháp mạnh mẽ trong trường hợp của tôi vì tôi không muốn giới hạn người dùng nhập các ký tự cụ thể được sử dụng bởi sed làm dấu phân cách (ví dụ "/").

Tuy nhiên, thoát khỏi mọi sự xuất hiện của dấu phân cách trong chuỗi đầu vào sẽ giải quyết được vấn đề. Hãy xem xét giải pháp dưới đây về việc thoát một cách có hệ thống ký tự phân cách trong chuỗi đầu vào trước khi phân tích cú pháp bởi sed. Việc thoát như vậy có thể được thực hiện như một sự thay thế bằng chính sed, sự thay thế này là an toàn ngay cả khi chuỗi đầu vào chứa dấu phân cách - điều này là do chuỗi đầu vào không phải là một phần của khối lệnh sed:

$ VALUE=$(echo ${VALUE} | sed -e "s#/#\\\/#g")
$ echo "MyVar=%DEF_VALUE%" | sed -e s/%DEF_VALUE%/${VALUE}/g
MyVar=12345/6

Tôi đã chuyển đổi hàm này thành một hàm được sử dụng bởi các tập lệnh khác nhau:

escapeForwardSlashes() {

     # Validate parameters
     if [ -z "$1" ]
     then
             echo -e "Error - no parameter specified!"
             return 1
     fi

     # Perform replacement
     echo ${1} | sed -e "s#/#\\\/#g"
     return 0
}

1
Lấy đi từ câu trả lời của bạn đối với tôi, là nếu giá trị mà bạn đang sử dụng để thay thế DEF_VALUE, có dấu gạch chéo trong nó, sau đó bạn phải thoát khỏi chúng bằng 3 backslashes cho sed để làm việc ví dụVALUE="01\\\/01\\\/2018"
alexkb

3

dòng này sẽ hoạt động cho 3 ví dụ của bạn:

sed -r 's#\?(page)=([^&]*)&#/\1/\2#g' a.txt
  • Tôi đã sử dụng -rđể tiết kiệm một số thoát.
  • dòng nên là chung cho một, hai ba trường hợp của bạn. bạn không phải làm phụ 3 lần

kiểm tra với ví dụ của bạn (a.txt):

kent$  echo "?page=one&
?page=two&
?page=three&"|sed -r 's#\?(page)=([^&]*)&#/\1/\2#g'
/page/one
/page/two
/page/three


1

Câu trả lời tuyệt vời từ Anonymous. \ đã giải quyết vấn đề của tôi khi tôi cố thoát dấu ngoặc kép trong chuỗi HTML.

Vì vậy, nếu bạn sử dụng sed để trả về một số mẫu HTML (trên máy chủ), hãy sử dụng dấu gạch chéo kép thay vì đơn:

var htmlTemplate = "<div style=\\"color:green;\\"></div>";

1

seds tream ed itor , trong đó bạn có thể sử dụng |(ống) để gửi con suối chuẩn (STDIN và STDOUT cụ thể) thông qua sedvà thay đổi chúng theo chương trình một cách nhanh chóng, làm cho nó một công cụ hữu ích trong truyền thống triết lý Unix; nhưng cũng có thể chỉnh sửa các tập tin trực tiếp bằng cách sử dụng -itham số được đề cập dưới đây.
Hãy xem xét những điều sau đây :

sed -i -e 's/few/asd/g' hello.txt

s/ đã từng s ubstitute biểu thức tìm thấy fewvới asd:

Số ít, người dũng cảm.


Các asd, dũng cảm.

/glà viết tắt của "toàn cầu", có nghĩa là làm điều này cho toàn bộ dòng. Nếu bạn rời khỏi /g(với s/few/asd/, luôn cần có ba dấu gạch chéo bất kể điều gì) và fewxuất hiện hai lần trên cùng một dòng, chỉ lần đầu tiênfew được thay đổi thành asd:

Một vài người đàn ông, một vài phụ nữ, những người dũng cảm.


Đàn ông asd, ít phụ nữ, dũng cảm.

Điều này hữu ích trong một số trường hợp, như thay đổi các ký tự đặc biệt ở đầu dòng (ví dụ, thay thế các ký hiệu lớn hơn một số người sử dụng để trích dẫn tài liệu trước đó trong các chủ đề email bằng một tab ngang trong khi để lại bất đẳng thức đại số được trích dẫn sau dòng không bị ảnh hưởng), nhưng trong ví dụ của bạn, nơi bạn xác định rằng bất cứ nơi nào few xảy ra nó nên được thay thế, hãy chắc chắn rằng bạn có điều đó /g.

Hai tùy chọn (cờ) sau đây được kết hợp thành một , -ie:

-itùy chọn được sử dụng để chỉnh sửa i n ra vào tập tin hello.txt.

-etùy chọn này cho biết lệnh e xpression / lệnh chạy, trong trường hợp này s/.

Lưu ý: Điều quan trọng là bạn sử dụng -i -eđể tìm kiếm / thay thế. Nếu bạn làm như vậy -ie, bạn tạo một bản sao lưu của mọi tệp có chữ 'e' được thêm vào.


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.