¿Cómo funciona este comando de sustitución 'sed' con muchos signos @?


8

¿Alguien puede explicar cómo funciona este sedcomando?

sed 's@+@ @g;s@%@\\x@g' | xargs -0 printf "%b"

3
La forma normal de hacer esto es usar barras, pero eso puede volverse engorroso si busca y reemplaza algo con barras. Ese no es el caso aquí, por lo que, aunque está perfectamente bien, confunde a los futuros mantenedores como usted.
Thorbjørn Ravn Andersen

2
... y los lleva a aprender algo nuevo sobre sedesta manera! :)
postre

Respuestas:


15

En sed, los comandos sustitutos generalmente se escriben como s/pattern/replacement/options. Sin embargo, no es necesario usarlo /; puede usar otros caracteres si es conveniente, por lo que podría ser s@pattern@replacement@optionso s:foo:bar:g. s@+@ @ges como s/+/ /g: reemplazar todo +con espacios. De manera similar, s@%@\\x@greemplaza todo %con \x(una barra invertida simple es un carácter de escape en sed, por lo que necesita dos para obtener una barra invertida real).

Una cadena como foo+%2Fbarse convertirá entonces foo \x2Fbar. printf "%b"expandirá las secuencias con barra invertida como \x2F(el carácter ASCII cuyo valor hexadecimal es 2F, que es /) para finalmente darte foo /bar.


2
En resumen, un decodificador URL-> nombre de archivo.
Thorbjørn Ravn Andersen

10

El comando sobre el que está preguntando para decodificar +es y %secuencias de URL no es solo un sedcomando, es una tubería que procesa la entrada sedy luego la canaliza xargspara su posterior procesamiento. Primero veamos el sedcomando:

sed 's@+@ @g;s@%@\\x@g'

Es posible que esté más acostumbrado a verlo en /lugar de @como el separador, lo que fácilmente podría haberse hecho aquí sin complicaciones, ya que no /aparece en ninguno de los patrones de búsqueda ni en ninguno de los textos de reemplazo. Este comando es equivalente:

sed 's/+/ /g;s/%/\\x/g'

Como /, @es un personaje de puntuación perfectamente bueno para sed.

En cada línea de entrada:

  1. s@+@ @g( s/+/ /g) sustituye ( s) ocurrencias de +con un espacio. Esto afecta a todos los +es en una línea ( g), no solo a la primera.

  2. ; finaliza la acción ("comando") y le permite especificar otro en el mismo "script".

  3. s@%@\\x@g( s/%/\\x/g) sustituye ( s) ocurrencias de %con \x. Como antes, actúa sobre todos en lugar de solo el primero de cada línea ( g).

    En \\xel \\representa solo uno \porque \tiene un significado especial para sed. Su significado especial es en realidad como el personaje que usas para quitar el significado especial de otro personaje que viene después que de otro modo tendría un significado especial. Por lo tanto, se debe escapar como \\.


Ahora veamos un xargscomando cuyo propósito es ejecutar printf.

xargsconstruye líneas de comando. Si ejecuta , donde es una o más palabras, se ejecuta con argumentos de línea de comandos adicionales leídos desde su entrada. En este caso, la entrada a es la salida de , debido a la tubería ( ). Normalmente interpreta cualquier espacio en blanco en su entrada para significar que el texto anterior y posterior constituye argumentos separados, pero la opción hace que se dividan los argumentos en las apariciones del carácter nulo .xargs command...command...xargscommand...xargssed|xargs-0

En el uso previsto de su comando, no aparecerá un carácter nulo y xargsse ejecutará printf %bcon solo un argumento adicional en la línea de comandos, el resultado del sedcomando. Por lo tanto, aunque no es equivalente en general, en este caso, toda la tubería podría haberse escrito así usando la sustitución de comandos en lugar de xargs:

printf '%b\n' "$(sed 's/+/ /g;s/%/\\x/g')"

En cuanto a lo que printfse pretende hacer aquí, como muru dice que el %bespecificador de formato consume e imprime un argumento (como %s) pero provoca escapes de barra invertida, del tipo que sedse escribió para generar el comando en el lado izquierdo de la tubería, para traducir en los personajes que representan .

Supongamos que ejecuto ese comando y paso http://foldoc.org/debugging%20by%20printfcomo entrada. Obtengo http://foldoc.org/debugging by printfcomo salida, porque las %20secuencias se traducen en espacios.


3

Esa es la belleza de sed, aplica sus paradigmas a sí mismo ... Después de la orden (por ejemplo, so tro nada), el siguiente carácter es considerado el separador.

Debe elegir sabiamente para evitar interferencias con el shell y el comando en sí mismo, y mantener la cosa legible, pero es perfectamente válido escribir algo tan horrible como:

echo 'arrival' | sed srarbrg

... y brrivblcomo resultado, que es lo que esperas. Puede divertirse haciéndolo realmente críptico, como en:

echo 'arrival' | sed s\fa\fb\fg   # \f is form feed, chr(12)

El uso común es usar la barra como delimitador, pero cuando su expresión contiene el delimitador, hace que sea más fácil agarrar cuál es la intención. Su delimitador puede ser cualquier cosa en el rango ASCII8 (delimitadores multibyte como £provocar un error).

Solo recuerda que el objetivo es hacer las cosas más fáciles, no más crípticas.


Funcionando con la idea críptica, este es un comando sed válido, aunque no hace nada útil:sed "snack is an apple or something" <<< "I sed your snack is an apple or something"
wjandrea

¡Agradable! Sí, también puedes usar sedcomandos como acertijos, ¿qué tan geek es eso?
Marabiloso
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.