Expansión retrasada

Expansión retrasada

Quiero crear un script quine .sh y esto es lo que he hecho hasta ahora
quine.sh:

#!/bin/sh
q="#!/bin/sh\nq=$q;echo \$q";echo $q

Centrarse en esta línea:

q="#!/bin/sh\nq=$q;echo \$q";echo $q

En la primera aparición de $q(en \nq=$q), primero quiero configurar el resto de la variable y luego esta parte (algo de línea setlocal enabledelayedexpansionen archivos por lotes).Tenga en cuenta que quiero una solución para sh, no basho algo más, ya que quiero portabilidad.. Además, no me den consejos sobre cómo acortar mi código, etc. Solo quiero una solución para el problema anterior.

Respuesta1

Si envolvemos la cadena inicial en 's en lugar de "s, entonces $qno se expandirá inmediatamente. Luego podemos expandirlo más tarde usando eval:

#!/bin/sh
q='#!/bin/sh\nq=$q;eval "echo \"\$q\""';eval "echo \"$q\""

Desafortunadamente, la \nno se expande, la 's y "la s se pierden y la \"s se convierte "en s.

Producción:

#!/bin/sh\nq=#!/bin/sh\nq=$q;eval "echo \"\$q\"";eval echo "$q"

Estamos bastante cerca, pero intentar arreglar el escape sedtermina volviéndose bastante engorroso.


El enlace de jw013 recomienda un enfoque bastante comprensible:

  • Parte 1: definir algunos datos (por ejemplo, una variable) que contiene la segunda parte del programa
  • Parte 2: use los datos para generar la primera parte del programa y luego use los datos para generar la segunda parte del programa. (Aquí se necesita envolver y escapar para la parte 1).

Aquí hay un burdo intento inicial de lograrlo:

#!/bin/sh
data="echo -e \"#!/bin/sh\ndata=\"\$data\"\"\\n\$data"
echo -e "#!/bin/sh\ndata=\"$data\"\n$data"

Producción:

#!/bin/sh
data="echo -e "#!/bin/sh
data="$data""
$data"
echo -e "#!/bin/sh
data="$data""
$data

Este intento adolece de \nser siempre interpretado y de \perderse. Necesitamos alguna forma de escapar de la cadena de datos cuando la imprimamos nuevamente.


Aquí hay una mejora que utiliza múltiples llamadas echopara evitar problemas con \ns.

#!/bin/sh
data='echo "#!/bin/sh"\necho "data=$data"\necho -e "$data"'
echo "#!/bin/sh"
echo "data='$data'"
echo -e "$data"

Tiene un pequeño defecto que es difícil de superar: faltan 'mensajes en la salida (en el medio echo):

#!/bin/sh
data='echo "#!/bin/sh"\necho "data=$data"\necho -e "$data"'
echo "#!/bin/sh"
echo "data=$data"
echo -e "$data"

Eso es todo lo que tengo para ti. Algunos puntos de partida para escapar de los problemas. ¡Buena suerte!

información relacionada