2011-02-02 13 views
13

Tener alguna dificultad en la sustitución de un texto simple/doble cita con sed y se preguntaba ¿cuál es el método correcto para estos 2 ejemplossed reemplazar texto simple/doble citado?

para cambiar el contenido del archivo de Memached.ini

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

a

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

y para cambiar el contenido del archivo memcache.php para estas líneas de

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 

a

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 

me trataron por ejemplo

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

mientras se ejecuta el comando, archivo memcache.php no cambia en absoluto?

Respuesta

24

Puede reemplazar el comillas simples en el comando sed con comillas simples de comillas dobles. El intérprete de comandos ve una sola cita como terminando una cadena. Entonces, déjalo.Tenías

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

Pero, si sustituye la 'en el comando sed con ' '''', entonces la cáscara verá la primera 'como el final de la primera cadena entre comillas simples, a continuación, "'" como un doble cita única citada, y luego la última 'como el comienzo de una nueva cadena entre comillas simples. Eso sería

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

También debe ser capaz de hacer '\' 'en lugar del' dentro del comando, por la misma razón.

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

Pero realmente, sería mejor usar un mecanismo alternativo. Sugeriría definir las cadenas fuente y de destino como variables, y luego ponerlas en la cadena sed.

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

Esa es la manera más fácil de leer, y hace que sea más fácil para usted para manejar el desorden citar de una manera sana con trozos pequeños. Los contenidos variables de shell "Yay" no están sujetos a la expansión de la palabra a menos que usted lo fuerce. :)

Sin embargo, asegúrese de no poner una/en las variables $ SRC o $ DST. ;)

8

Tendrás que usar escapes hex, por ejemplo, para hacer esos reemplazos.

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

También es posible usar los escapes octales: \o047 (que es una letra minúscula "Oh") o escapes decimales: \d39.

+0

La mejor respuesta en mi opinión. – wind39

1

O bien debe citar las comillas o escapar de las comillas. ¿Intentó comprobar qué ve sed cuando le da el último comando?

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

Prueba esto:

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

Se da esto:

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

Ups! Tus comillas simples no fueron interpretadas como pensabas. Una solución fácil para este caso es citar proteger su comando sed del shell con comillas dobles en su lugar.

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

+0

Gracias citando todo el comando sed trabajado para la primera parte, pero la segunda parte tocó el error [* sed -i "s/$ MEMCACHE_SERVERS [] = 'mymemcache-server1: 11211';/$ MEMCACHE_SERVERS [] = 'localhost: 11211';/g "/var/www/html/memcache.php *] – p4guru

+0

@ p4guru, en este caso es debido al signo de dólar, que le dice al shell que desreferencia una variable (en este caso llamada MEMCACHE_SERVERS). Podrías escapar del signo de dólar con una barra invertida: '" s/\ $ MEMCACHE_SERVERS ... "'. Otras soluciones serían cambiar las comillas dobles a comillas simples, y luego escapar las comillas simples de su comando sed con una barra diagonal inversa. Finalmente, para un divertido truco sucio, podría hacer MEMCACHE_SERVERS una variable real, y darle el valor MEMCACHE_SERVERS: 'MEMCACHE_SERVERS = MEMCACHE_SERVERS sed -i ...'. – rlibby

6

Para entender cómo hacerlo, debe comprender cómo el shell está jugando con sus cotizaciones y barras diagonales inversas, así como si sed está jugando con ellas.

En general, es más fácil utilizar comillas simples en el intérprete de órdenes, excepto cuando la expresión regular debe coincidir con comillas simples. No hay caracteres especiales dentro de comillas simples; la próxima cita simple lo finaliza. Las comillas dobles son mucho más difíciles; las barras invertidas, los dólares y las comillas son especiales.

El primer requisito es mejor manejado por un solo citado sed expresión:

Cambio:

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

a

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

Para esto, podríamos utilizar:

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

El shell simplemente envía todo dentro de las comillas simples al sed, intacto. El único carácter especial para sed es el corchete cuadrado abierto. Eso comenzaría una clase de caracteres a excepción de la barra invertida anterior. El corchete de cierre solo es especial cuando estás en una clase de personaje, por lo que no es necesario escapar. Las acciones para reconocer esa línea son imprimir el original, luego hacer el 11212 para la sustitución del 11211; la impresión predeterminada imprimirá la línea modificada.

La otra parte es un poco más complicada. Debido a que los patrones contienen comillas simples, lo mejor será usar comillas dobles alrededor de la expresión regular.

Cambio:

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 

a:

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 

Las dos primeras líneas podrían ser mapeable utilizando una sola expresión regular:

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

Esto captura dos partes - el define('ADMIN_USERNAME',' como \1 y username' como \2, y la sustitución coloca my entre las dos partes. Esto no fue tan malo; el intérprete de comandos no hace nada especial con ninguno de los personajes, por lo que simplemente escriba lo que desea sed para ver dentro de las comillas dobles.

Las dos últimas líneas son más difíciles:

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

Sin embargo, no es mucho más complicado; solo tiene que detener el shell para expandir el $MEMCACHE_SERVERS como una variable de shell, por lo que hay una barra invertida delante del $. El corchete necesita protección de sed como antes. La expresión regular coincide con todo lo que no es dos puntos y lo reemplaza con localhost.

Por lo tanto, este script debería funcionar:

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]" 

Sin embargo, sólo he explicado por qué se debe trabajar; ¡No he demostrado que funcione!

Cuestiones relacionadas