2010-10-13 13 views
8

Estoy buscando una manera de procesar un script de shell para determinar:¿Determina la función y la dependencia de archivo de un script de shell?

  1. qué comandos, scripts o funciones son llamados en el guión.
  2. a qué archivos accede el script (r o w).

No es necesario recurse a través de las dependencias, simplemente enumere lo que se ejecuta directamente. Probablemente podría escribir algo que lo haga yo mismo, pero debe haberse hecho antes ... Simplemente no lo estoy encontrando.

+0

Pregunta interesante, no trivial de responder. Considere seguir la salida desde 'sh -x' (pero eso solo muestra los comandos que se ejecutan, no aquellos que no lo son. –

Respuesta

1

Será una característica del proyecto Loker que desarrollo actualmente. Por ahora, el analizador está casi completo y puede implementar una aproximación razonable de lo que quiere encima de él. Sin embargo, en general esta tarea es muy compleja, porque el nombre del comando puede ser el resultado de la expansión de variables, división de campos, etc.

Si describe para qué necesita esto y qué tipo de scripts va a analizar I podrá decir cuánto de sus necesidades puede satisfacer Loker por ahora.

Como opción alternativa, algunas versiones de bash tienen la opción --rpm-requires, que también hace algo similar.

+0

Muy interesante. Voy a echar un vistazo mejor a Loker cuando tenga tiempo. Programar correctamente el código para archivos y ejecutables es bastante complejo de hecho ... Estaba fantaseando con que podría ser una forma de hacer esto ejecutando el código usando UNIX para rastrear el acceso a los archivos. Realmente no sé nada sobre esto ... de ahí la fantasía. – mathtick

+0

@mathtick "I Estaba fantaseando con que podría ser una forma de hacerlo ejecutando el código usando UNIX para rastrear el acceso al archivo."Esto definitivamente es posible, use' strace' para esto. El problema es que realmente necesita ejecutar código (análisis dinámico frente a análisis estático) y no verá todos los comandos/archivos posibles, solo aquellos que fueron ejecutados/accedidos durante esta ejecución en particular. –

+0

Gracias, parece un buen punto de partida. También una combinación de pree y pfiles puede ser un punto de partida útil para el análisis dinámico. El problema de probar todos los casos (en lugar de solo los que se ejecutan en un determinado ejemplo) es importante para el código que estoy mirando en este momento. – mathtick

5

Puede usar 'strace' para ejecutar un script y ver todo lo que el script y sus subprocesos hacen, incluso buscar y abrir archivos. Por ejemplo:

$ cat foo.sh 
#!/usr/bin/env bash 

touch /tmp/foon 
$ chmod +x foo.sh 
$ strace -f -e execve,access,open,stat -o foo.trace ./foo.sh 
$ cat foo.trace 
32176 execve("./foo.sh", ["./foo.sh"], [/* 42 vars */]) = 0 
32176 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) 
32176 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) 
32176 open("/usr/local/lib/tls/x86_64/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory) 
... 
32176 execve("/bin/bash", ["bash", "./foo.sh"], [/* 42 vars */]) = 0 
... 
32177 execve("/usr/bin/touch", ["touch", "/tmp/foon"], [/* 41 vars */]) = 0 
32177 open("/tmp/foon", O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK, 0666) = 3 
... 
32176 --- SIGCHLD (Child exited) @ 0 (0) --- 
$ 

he recortado un montón de la otra actividad pasando allí (bibliotecas del sistema de apertura; la búsqueda de datos local, y mucho más). Verifique 'man strace' para detalles sobre qué significan las opciones; -f, -o y -e son los que uso más a menudo.

+0

Esto es bueno para mostrar la ruta de ejecución de un script, pero idealmente una solución a la pregunta del OP también mostraría rutas no ejecutadas (de forma análoga a cómo 'bash -n' comprueba la sintaxis a lo largo de un script). –

+0

Sí, esto es un problema para mí ... hay tantas excepciones con diferentes casos enviando los scripts para acceder a diferentes archivos que se ponen un poco min. d alucinante. Mi estrategia principal es usar strace y reducir la salida a algo que pueda ejecutar un diff para ver cuando las cosas cambian drásticamente. – mathtick

0

Simplemente no puede hacer eso en un lenguaje tan dinámico, su herramienta de análisis estático no será confiable y perderá una serie de dependencias. Considere el siguiente código:

#!/bin/sh 

func_foo() { echo 'foo running' ; } 
func_bar() { echo 'bar running' ; } 
# etc... 

printf 'foo, bar,...? ' # for testing 
read RPC 
# rpc_is_in_rpclist "$RPC" || die "invalid call" 
printf 'Calling func_%s\n' "$RPC" 
func_"$RPC" 

Esto no es un ejemplo intrincado; Recientemente agregué a un entorno de producción una versión más elaborada de esto con parámetros.

Si realmente necesita análisis estático, entonces no debería estar utilizando un lenguaje dinámico, en primer lugar, que son simplemente incompatibles entre sí. Lo mismo vale para cualquier otro lenguaje funcional donde las funciones se pasan como argumentos: el análisis estático no puede predecir prácticamente los valores de los argumentos.

Incluso en un lenguaje muy estático y simple como Java, aún puedes eludir el análisis estático si lo intentas con fuerza y ​​usas el reflejo. Sin embargo, la reflexión es engorrosa por diseño y no tiene un uso amplio, por lo que el análisis de Java es muy útil en la práctica: vea Eclipse, etc.

+0

Es cierto que desearía que una herramienta de análisis manejara códigos como los que muestra, pero ese no es un buen diseño. Para la mantenibilidad, etc., se debe usar una declaración 'case'. –

+0

@Dennis: una razón por la que las personas usan los lenguajes dinámicos es porque pueden codificar * más rápido *. Para eso, están listos para correr el riesgo de menos análisis/verificación estáticos en tiempo de compilación. Para ser realmente implementado más rápido, muchos scripts no se molestarían con una declaración de caso de peso pesado. De lo contrario, sus desarrolladores habrían estado usando un lenguaje más estático. – MarcH

Cuestiones relacionadas