2011-02-24 11 views
5

Me han entregado un proyecto que consta de varias docenas (probablemente más de 100, no he contado) scripts bash. La mayoría de los scripts hacen al menos una llamada a otro de los scripts. Me gustaría obtener el equivalente de un gráfico de llamadas donde los nodos son los guiones en lugar de las funciones.Generar el árbol de llamadas de script de shell

¿Hay algún software existente para hacer esto?

Si no, ¿alguien tiene ideas ingeniosas sobre cómo hacerlo?

El mejor plan que pude encontrar fue enumerar los scripts y verificar si los basenames son únicos (abarcan múltiples directorios). Si hay basenames duplicados, entonces llora, porque las rutas de los scripts generalmente se mantienen en nombres de variables, por lo que es posible que no puedas eliminar ambigüedades. Si son únicos, agregue los nombres en los guiones y use esos resultados para crear un gráfico. Use alguna herramienta (¿sugerencias?) Para visualizar el gráfico.

Sugerencias?

+0

Graphviz es una buena herramienta de visualización, pero es necesario comprobar la validez de su proceso de producción basename'd alguna manera antes de pasarla a Graphviz. Puede intentar usar bashdb para depurar sus scripts. – vissi

+0

Lo que hago rutinariamente estos días es agregar un Depends: comment justo al comienzo de cada script que creo. Probablemente no sea factible hacerlo como una idea de último momento en una escala mayor, pero es una convención muy simple que me ha sido útil. – tripleee

Respuesta

1

Así es como terminé haciéndolo (disclaimer: un montón de esto es hack-ish, por lo que es posible que desee limpiar si se va a utilizar a largo plazo) ...

Supuestos : - El directorio actual contiene todos los scripts/binarios en cuestión. - Los archivos para construir el gráfico entran en subdir call_graph.

Creó la secuencia de comandos call_graph/make_tgf.SH:

#!/bin/bash 
# Run from dir with scripts and subdir call_graph 
# Parameters: 
# $1 = sources (default is call_graph/sources.txt) 
# $2 = targets (default is call_graph/targets.txt) 

SOURCES=$1 
if [ "$SOURCES" == "" ]; then SOURCES=call_graph/sources.txt; fi 
TARGETS=$2 
if [ "$TARGETS" == "" ]; then TARGETS=call_graph/targets.txt; fi 

if [ ! -d call_graph ]; then echo "Run from parent dir of call_graph" >&2; exit 1; fi 
(
# cat call_graph/targets.txt 
    for file in `cat $SOURCES ` 
    do 
    for target in `grep -v -E '^ *#' $file | grep -o -F -w -f $TARGETS | grep -v -w $file | sort | uniq` 
    do echo $file $target 
    done 
    done 
) 

Entonces, me encontré con lo siguiente (terminé haciendo las secuencias de comandos única versión):

cat /dev/null | tee call_graph/sources.txt > call_graph/targets.txt 
for file in * 
do 
    if [ -d "$file" ]; then continue; fi 
    echo $file >> call_graph/targets.txt 
    if file $file | grep text >/dev/null; then echo $file >> call_graph/sources.txt; fi 
done 

# For scripts only: 
bash call_graph/make_tgf.sh call_graph/sources.txt call_graph/sources.txt > call_graph/scripts.tgf 

# For scripts + binaries (binaries will be leaf nodes): 
bash call_graph/make_tgf.sh > call_graph/scripts_and_bin.tgf 

entonces abrí el archivo de TGF resultando en yEd, y había yEd hacer el diseño (Diseño -> Jerárquico). Guardé como graphml para separar el archivo editable manualmente del generado automáticamente.

Encontré que había ciertos nodos que no eran útiles tener en el gráfico, como los scripts/binarios de utilidad que se llamaban por todos lados. Entonces, los eliminé de los archivos de orígenes/objetivos y los regeneré según fue necesario hasta que me gustó el conjunto de nodos.

Espero que esto ayude a alguien ...

+0

No puedo configurar yEd. ¿Hay una alternativa para ver los archivos TGF? – user13107

3

Envuelva el shell por su implementación, inicie sesión quién lo llamó envolvió y ejecutó el shell original.

Sí, debe iniciar los scripts para identificar qué script realmente se usa. De lo contrario, necesita una herramienta con el mismo conocimiento que el propio motor de shell para soportar toda la expansión de variables, PATH, etc. - Nunca escuché acerca de una herramienta de este tipo.

Para visualizar el gráfico de llamadas use GraphViz's dot format.

+0

Voto a favor de la astucia. Tal vez soy poco creativo, pero nunca se me ocurrió envolver el caparazón. Lamentablemente, no es práctico para mí ejecutar todos estos; Ni siquiera sé qué hacen la mayoría de ellos o cuáles son importantes. Estoy de acuerdo en que la expansión variable y los problemas de ruta son difíciles, pero tengo que hacerlo en función del código, o simplemente vivir sin él. –

+0

Ok, si está pensando en una nueva implementación, considere tomar la fuente de shell original (¿de código abierto?) Y añada allí su lógica. Obtendrás el analizador por menos. Intente deshabilitar todas las llamadas de exec() excepto las secuencias de comandos de shell y registre lo que está buscando. Debido a que nunca escuché acerca de un proyecto de este tipo, me interesaría conocer su progreso. Buena suerte. –

0

Inserta una línea al principio de cada script de shell, después del #! línea, que registra una marca de tiempo, la ruta completa del script y la lista de argumentos.

Con el tiempo, puede extraer este registro para identificar posibles candidatos, es decir, dos líneas registradas muy juntas tienen una alta probabilidad de que el primer script llame al segundo.

Esto también le permite enfocarse en las secuencias de comandos que todavía están en uso.

Se podría utilizar un guión ed

1a 
log blah blah blah 
. 
wq 

y ejecutarlo así:

find/-perm +x -exec ed {} <edscript

asegúrese de probar el comando find con -print en lugar de la cláusula Exec. Y/probablemente no sea la ruta que desea usar. Si tiene que incluir directorios bin entonces necesitará cambiar a grep para identificar las rutas a incluir, luego cuando tenga un archivo lleno de los nombres correctos, use xargs en lugar de find para ejecutar el script.

+0

Ah, y también necesita escribir un script de registro o preferiblemente un alias/función de shell. –

Cuestiones relacionadas