He escrito una biblioteca de registro de bash que se implementará con algunos scripts complejos que mi compañía está utilizando actualmente. No me gusta proporcionar el nombre de archivo del script ($ {BASH_SOURCE}) y el número de línea ($ {LINENO}) del script de llamada al hacer las llamadas de registro. Sin embargo, no quería tener que depender del usuario o implementar el script para pasar estas dos variables como parámetros. Si esto fuera C/C++, simplemente crearía una macro que precede "__FILE__" y "__LINE__" a la lista de parámetros.Citas de parámetros de Bash y eval
Finalmente pude hacer que esta pieza funcionara. Aquí están algunos extractos mucho-simplificados como una prueba de concepto:
Aquí está la biblioteca de registro:
# log.sh
LOG="eval _log \${BASH_SOURCE} \${LINENO}"
_log() {
_BASH_SOURCE=`basename "${1}"` && shift
_LINENO=${1} && shift
echo "(${_BASH_SOURCE}:${_LINENO}) [email protected]"
}
Y un script de prueba de aplicación:
# MyTest.sh
. ./log.sh
${LOG} "This is a log message"
# (test.sh:5) This is a log message
Esto funciona bastante bien (y, me estaba encantado de hacerlo funcionar al principio). Sin embargo, esto tiene un problema evidente: la interacción entre presupuestos y eval. Si realizo la llamada:
${LOG} "I'm thrilled that I got this working"
# ./test.sh: eval: line 5: unexected EOF while looking for matching `''
# ./test.sh: eval: line 6: syntax error: unexpected end of file
Ahora, creo que entiendo por qué sucede esto. Los parámetros citados se mantienen intactos a medida que se pasan a eval, pero en ese punto, el contenido se coloca tal cual en la cadena de comando resultante. Sé que puedo arreglar esto escapando un poco; sin embargo, I REALMENTE no quiero obligar a los scripts de implementación a tener que hacer esto. Antes de implementar esta capacidad de "evaluación macro", hacía que los usuarios realizaran llamadas directamente a "_log" y les permitía pasar opcionalmente "$ {LINENO}". Con esta implementación, la llamada de falla anterior (con solo una oración entrecomillada) funcionó bien.
En el nivel más básico, todo lo que realmente quiero es una secuencia de comandos para poder llamar [función log/macro] "Cadena para conectarse con characers especiales" y tienen el mensaje de registro resultante contendrá el nombre del archivo y la línea número de la secuencia de comandos de llamada, seguido del mensaje de registro. Si es posible, asumiría que estoy muy cerca, pero si hay algo que estoy pasando por alto que requeriría un enfoque diferente, estoy abierto a eso también. No puedo obligar a los usuarios a escapar de todos sus mensajes, ya que es probable que no utilicen esta biblioteca. Este es un problema tal que si no puedo encontrar una solución a esto, es probable que regrese a la capacidad anterior (que requería que $ {LINENO} pasara como parámetro de función; esto era mucho menos intrusivo).
TLDR: ¿Hay alguna forma de que eval respete los caracteres especiales dentro de un parámetro entre comillas, sin tener que escapar de ellos?
Si utiliza construcciones específicas de bash, su secuencia de comandos de inicio de sesión no se debe llamar "log.sh". Debería ser "log.bash". –
@WilliamPursell - Realicé algunas búsquedas y no pude encontrar ningún tipo de estándar con respecto a las convenciones de nomenclatura de los scripts de shell. De hecho, la mayoría de la gente parece dejar un sufijo por completo. Para ser honesto, nunca he visto nada más que '\ *. Sh' (o un script sin extensión/sufijo). Y con toda la practicidad, no debería tener ningún impacto, ¿verdad? El intérprete se extrae de la primera línea del script o se usa su shell actual. Parece que básicamente se reduce a las preferencias personales. Pero, tal vez "\ *. Sh" puede implicar para un usuario que el script usa "sh". – LousyG
El único impacto práctico sería si un desarrollador está utilizando sus funciones con un shell diferente. Con un nombre '* .sh', un desarrollador supondría razonablemente que su biblioteca puede obtenerse en un script zsh. –