|Portada|Blog|Space|
[Índice] > Quine - Script de sed que se replica a sí mismo
Es un interesante ejercicio pensar en como lograr que un script de sed,
muestre su propio código al ejecutarlo.
la idea es que si tengo el código en una variable, al ejecutar:
echo cualquier cosa | sed "$CODIGO"
debería mostrar lo mismo que:
echo "$CODIGO"
Para esto, tenemos que pensar de la siguiente manera. Necesitamos antes
que nada, que el script esté dividido en tres partes:
+------{ TODO ESTO EMPACADO }------+
+-------+ | +-------+ +----------+ | +----------+
| s/.*/ | + | | s/.*/ | + MARCA + | El resto | | + | El resto |
+-------+ | +-------+ +----------+ | +----------+
+----------------------------------+
¿Qué significa empacar?
Como podrán ver, el lugar en donde queda este código empacado, es dentro
del segúndo parámetro de la orden s, por tanto tenemos que asegurarnos
que si usamos barras, contra barras o ampersands, estén "escaped". Como
intenté unas cuantas veces lograr código que haga esto, y me superó, fue
que decidí utilizar la otra, segunda, opción: no utilizar barras, contra
barras ni ampersands.
¿Pero entonces cómo logramos almacenar estos caracteres?
Representando las contra barras con w1,
las barras con w2,
y las w con w3.
De esta forma para empacar utilizamos: s/w/w3/g;s/\\/w1/g;s/\//w2/g'
y para desempacar: s/w1/\\/g;s/w2/\//g;s/w3/w/g
Por tanto, ¿qué metemos en "El resto" del código?
Primero, cerrar con una / la orden anterior, que justamente lo que hace
es meter todo el código empacado, en el pattern space.
Segundo, guardar una copia del código empacado, en el hold space: con h
Tercero, desempacar el código del pattern space: con el trozo de código
que mostré antes.
Cuarto, substituir la marca del código desempacado, por el código
empacado (el cual habíamos guardado en el hold space), G; y el resto.
Para armar el código empacado:
echo 's/.*/%/;h;s/w1/\\/g;s/w2/\//g;s/w3/w/g;G;s/%\(.*\)\n\(.*\)/\2\1/' | sed -e 's/w/w3/g;s/\\/w1/g;s/\//w2/g'
Substituímos nuestra hermosa marca por el código empacado, para quedar
con:
echo | sed 's/.*/sw2.*w2%w2;h;sw2w31w2w1w1w2g;sw2w32w2w1w2w2g;sw2w33w2w3w2g;G;sw2%w1(.*w1)w1nw1(.*w1)w2w12w11w2/;h;s/w1/\\/g;s/w2/\//g;s/w3/w/g;G;s/%\(.*\)\n\(.*\)/\2\1/'
Y así es como logramos tener un programa que hace los cuatro pasos que
antes mencionamos, mostrando en definitiva, el código del programa.
---------
Los documentos en este sitio se encuentran licenciados bajo la GFDL.
Ver comentarios: [Hay i comentarios]
Para agregar un comentario: agregue a la URL: ?do=show_comment_form (explicación)