2011-02-02 35 views
13

Có một số khó khăn trong việc thay thế một số/đôi văn bản trích dẫn duy nhất với sed và đã tự hỏi những phương pháp chính xác cho những ví dụ 2sed thay thế văn bản trích dẫn đơn/đôi?

là những điều cần thay đổi nội dung tập tin Memached.ini từ

[server] 
server[] = "localhost:11211" 

để

[server] 
server[] = "localhost:11211" 
server[] = "localhost:11212" 

và thay đổi nội dung tệp memcache.php cho các dòng này từ

define('ADMIN_USERNAME','username'); // Admin Username 
define('ADMIN_PASSWORD','password'); // Admin Password 

$MEMCACHE_SERVERS[] = 'mymemcache-server1:11211'; // add more as an array 
$MEMCACHE_SERVERS[] = 'mymemcache-server2:11211'; // add more as an array 

để

define('ADMIN_USERNAME','myusername'); // Admin Username 
define('ADMIN_PASSWORD','mypassword');  // Admin Password 

$MEMCACHE_SERVERS[] = 'localhost:11211'; // add more as an array 
$MEMCACHE_SERVERS[] = 'localhost:11212'; // add more as an array 

tôi đã cố gắng ví dụ

sed -i 's/'ADMIN_USERNAME','memcache'/'ADMIN_USERNAME','u'/g' /var/www/html/memcache.php 

trong khi lệnh chạy, tập tin memcache.php là không thay đổi ở tất cả?

Trả lời

24

Bạn có thể thay thế dấu nháy đơn trong lệnh sed với dấu trích dẫn đơn kép. Shell thấy một dấu nháy đơn kết thúc một chuỗi. Vì vậy, hãy để nó.Bạn có

sed -i 's/'ADMIN_USERNAME','memcache'/'ADMIN_USERNAME','u'/g' /var/www/html/memcache.php 

Nhưng, nếu bạn thay thế 'trong lệnh sed với ' '''', sau đó vỏ sẽ thấy đầu tiên khi kết thúc chuỗi đơn trích dẫn trước, sau đó "'" như một đôi trích dẫn duy nhất được trích dẫn, và sau đó là dấu ngoặc kép cuối cùng 'làm khởi đầu của một chuỗi trích dẫn đơn mới. Điều đó muốn được

sed -i 's/'"'"'ADMIN_USERNAME'"'"','"'"'memcache'"'"'/'"'"'ADMIN_USERNAME'"'"','"'"'u'"'"'/g' /var/www/html/memcache.php 

Bạn cũng sẽ có thể làm '\' 'thay cho' trong lệnh, với lý do tương tự.

sed -i 's/'\''ADMIN_USERNAME\'',\''memcache\''/\''ADMIN_USERNAME\'',\''u\''/g' /var/www/html/memcache.php 

Nhưng thực sự, nó muốn được tốt hơn để sử dụng một cơ chế thay thế. Tôi muốn đề nghị xác định các chuỗi nguồn và đích như các biến, và sau đó đặt các chuỗi đó vào chuỗi sed.

SRC="'ADMIN_USERNAME','memcache'" 
DST="'ADMIN_USERNAME','u'" 
sed -i "s/$SRC/$DST/g" /var/www/html/memcache.php 

Đó là cách dễ đọc hơn, và nó làm cho nó dễ dàng hơn để bạn có thể xử lý các mớ hỗn độn trích dẫn một cách lành mạnh với khối cắn cỡ. Yay "nội dung biến shell không phải là từ mở rộng trừ khi bạn ép buộc" kiến ​​thức. :)

Đảm bảo bạn không đặt/trong biến $ SRC hoặc $ DST. ;)

8

Bạn sẽ phải sử dụng lệnh thoát hex, ví dụ: để thực hiện các thay thế đó.

$ echo "'foo'" | sed 's/\x27foo\x27/\x27bar\x27/' 
'bar' 

Bạn cũng có thể sử dụng thoát bát phân: \o047 (đó là một trường hợp thấp hơn "Oh") hoặc thoát thập phân: \d39.

+0

Câu trả lời hay nhất theo ý kiến ​​của tôi. – wind39

1

Bạn cần báo giá hoặc thoát khỏi dấu ngoặc kép. Bạn đã thử kiểm tra những gì sed thấy khi bạn cho nó lệnh cuối cùng?

sed -i 's /' ADMIN_USERNAME ' 'memcache'/ 'ADMIN_USERNAME', 'u'/ g' /var/www/html/memcache.php

Hãy thử điều này:

vang sed -i 's /' ADMIN_USERNAME ' 'memcache'/ 'ADMIN_USERNAME', 'u'/ g' /var/www/html/memcache.php

Nó cung cấp này:

sed -i s/ADMIN_USERNAME, memcache/ADMIN_USERNAME, u/g /var/www/html/memcache.php

Oops! Dấu nháy đơn của bạn không được giải thích cách bạn nghĩ. Một cách giải quyết dễ dàng cho trường hợp này là báo giá bảo vệ lệnh sed của bạn từ trình bao với dấu ngoặc kép để thay thế.

sed -i "s/'ADMIN_USERNAME', 'memcache'/'ADMIN_USERNAME', 'u'/g" /var/www/html/memcache.php

+0

Cảm ơn trích dẫn toàn bộ lệnh sed đã làm việc cho phần đầu tiên nhưng phần lỗi thứ hai là [* sed -i "s/$ MEMCACHE_SERVERS [] = 'mymemcache-server1: 11211';/$ MEMCACHE_SERVERS [] = 'localhost: 11211';/g "/var/www/html/memcache.php *] – p4guru

+0

@ p4guru, trong trường hợp này là do ký hiệu đô la, nó báo cho shell biết dereference một biến (trong trường hợp này gọi là MEMCACHE_SERVERS). Bạn có thể thoát khỏi dấu đô la bằng dấu gạch chéo ngược: '" s/\ $ MEMCACHE_SERVERS ... "'. Các giải pháp khác sẽ là thay đổi dấu nháy kép trở lại dấu nháy đơn, và sau đó thoát khỏi dấu nháy đơn của lệnh sed với dấu gạch chéo ngược. Cuối cùng, cho một hack bẩn vui, bạn có thể làm cho MEMCACHE_SERVERS một biến thực tế, và cung cấp cho nó giá trị MEMCACHE_SERVERS: 'MEMCACHE_SERVERS = MEMCACHE_SERVERS sed -i ...'. – rlibby

6

Để hiểu làm thế nào để làm điều này, bạn cần phải hiểu như thế nào vỏ là rối tung với dấu ngoặc kép và dấu xồ nguợc của bạn cũng như liệu sed đang rối tung với họ.

Nói chung, dễ nhất trong trình bao để sử dụng dấu nháy đơn - ngoại trừ khi regex phải khớp với dấu nháy đơn. Không có ký tự đặc biệt nào trong dấu nháy đơn; trích dẫn đơn tiếp theo kết thúc nó. Dấu nháy kép khó hơn nhiều; dấu gạch chéo ngược và đô la và dấu ngoặc kép là tất cả đặc biệt.

Yêu cầu đầu tiên được xử lý tốt nhất bằng một single trích dẫn sed biểu:

Thay đổi:

[server] 
server[] = "localhost:11211" 

để

[server] 
server[] = "localhost:11211" 
server[] = "localhost:11212" 

Đối với điều này, chúng ta có thể sử dụng:

-e '/^server\[] = "localhost:11211"/{p;s/11211/11212/}' 

Vỏ chỉ đơn giản gửi mọi thứ bên trong dấu ngoặc đơn đến sed, không bị ảnh hưởng. Ký tự đặc biệt duy nhất cho sed là dấu ngoặc vuông mở. Điều đó sẽ bắt đầu một lớp nhân vật ngoại trừ dấu gạch chéo ngược trước nó. Dấu ngoặc vuông gần chỉ là đặc biệt khi bạn đang ở trong một lớp nhân vật, vì vậy nó không cần phải thoát. Các hành động để nhận biết dòng đó là in bản gốc, sau đó thực hiện 11212 để thay thế 11211; in mặc định sẽ in dòng đã sửa đổi.

Phần khác phức tạp hơn một chút. Bởi vì các mẫu có chứa dấu nháy đơn, chúng ta sẽ sử dụng tốt nhất các dấu ngoặc kép xung quanh regex.

Thay đổi:

define('ADMIN_USERNAME','username'); // Admin Username 
define('ADMIN_PASSWORD','password'); // Admin Password 

$MEMCACHE_SERVERS[] = 'mymemcache-server1:11211'; // add more as an array 
$MEMCACHE_SERVERS[] = 'mymemcache-server2:11211'; // add more as an array 

tới:

define('ADMIN_USERNAME','myusername'); // Admin Username 
define('ADMIN_PASSWORD','mypassword');  // Admin Password 

$MEMCACHE_SERVERS[] = 'localhost:11211'; // add more as an array 
$MEMCACHE_SERVERS[] = 'localhost:11212'; // add more as an array 

Hai dòng đầu tiên có thể là trí trên bản đồ sử dụng một regex duy nhất:

-e "s/^\(define('ADMIN_[A-Z]\{0,8\}','\)\([^']*'\)/\1my\2/" 

này chụp hai phần - define('ADMIN_USERNAME','\1username'\2 và địa điểm thay thế my giữa hai phần. Điều này không quá tệ; vỏ không làm bất cứ điều gì đặc biệt với bất kỳ ký tự nào, vì vậy bạn chỉ cần gõ những gì bạn muốn sed để xem bên trong dấu ngoặc kép.

Hai dòng cuối cùng thì rắc rối hơn:

-e "s/^\(\$MEMCACHE_SERVERS\[] = '\)[^:]*\(:[0-9]*'\)/\1localhost\2/" 

Tuy nhiên, không phức tạp hơn nhiều; bạn chỉ cần dừng trình bao mở rộng $MEMCACHE_SERVERS làm biến hệ vỏ, đó là lý do tại sao có dấu gạch chéo ngược ở phía trước của $. Khung hình vuông cần bảo vệ từ sed như trước đây. Regex khớp với mọi thứ không phải là dấu hai chấm và thay thế bằng localhost.

Vì vậy, kịch bản này nên làm việc:

sed -e '/^server\[] = "localhost:11211"/{p;s/11211/11212/}' \ 
    -e "s/^\(define('ADMIN_[A-Z]\{0,8\}','\)\([^']*'\)/\1my\2/" \ 
    -e "s/^\(\$MEMCACHE_SERVERS\[] = '\)[^:]*\(:[0-9]*'\)/\1localhost\2/" \ 
    "[email protected]" 

Tuy nhiên, tôi đã chỉ giải thích lý do tại sao nó phải làm việc; Tôi đã không chứng minh rằng nó hoạt động!

Các vấn đề liên quan