2011-12-16 10 views
7

¿Cómo puedo determinar qué secuencia de comandos, programa o shell ejecutó mi script de Perl?¿Cómo puedo averiguar qué script, programa o shell ejecutó mi script de Perl?

Ejemplo: Me gustaría tener salida legible para humanos si se ejecuta desde shell (personalizado para cada tipo de shell), un tipo diferente de salida si se llama como script de otro script perl y un formato legible por máquina si se ejecuta desde un programa como un servidor de integración continua.

Motivación: Tengo una herramienta que cambia su salida en función de qué shell lo ejecuta. Normalmente implementaría este comportamiento como una opción para el script, pero el diseño de esta herramienta no permite las opciones. Otros shells tienen variables de entorno que indican qué shell se está ejecutando. Estoy trabajando en un parche para admitir Powershell, que no tiene esa variable especial.

Editar: Muchas de estas respuestas son específicas de Linux. Desafortunadamente, Powershell es para Windows. getppid, la variable $ENV{SHELL}, y desgranar a ps no ayudará en este caso. Esta secuencia de comandos debe ejecutarse multiplataforma.

+0

No estoy seguro de entender, ¿no debería estar mirando el proceso principal en ese caso? – x0n

+0

Puede probar para ver si STDOUT es un terminal ('-t') y, de ser así, suponga que ha sido invocado desde un shell interactivo en lugar de, por ejemplo, un daemon de integración continua. Sin embargo, esta técnica común no se refiere a la personalización de la salida per-distinct-possible-parent (pero, de todos modos, ese es un deseo un poco fuera de lugar). – pilcrow

+0

Se olvidó mencionar, normalmente busca una variable de entorno que el shell o el usuario establece para indicar qué shell se está ejecutando; con Powershell, no hay tal variable de entorno. –

Respuesta

1

Dependiendo de su entorno, puede ser capaz de recogerlo desde las variables de entorno. Considere el siguiente código:

/usr/bin/perl -MData::Dumper -e 'print Dumper(\%ENV);' | grep sh 

En mi sistema Ubuntu, me obtiene:

'SHELL' => '/bin/bash', 

así que supongo que dice que estoy corriendo Perl desde un shell bash. Si usa algo más, la variable SHELL puede darle una pista.

Pero digamos que sabes que estás en bash, pero Perl se ejecuta desde una subshell. A continuación, intente:

/bin/sh -c "/usr/bin/perl -MData::Dumper -e 'print Dumper(\%ENV);'" | grep sh 

se encuentran:

 '_' => '/bin/sh', 
     'SHELL' => '/bin/bash', 

Así que la cáscara sigue siendo fiesta, pero fiesta tiene una variable $_ que también muestra el nombre de archivo absoluto del script de consola o en ejecución, lo que puede también da una pista valiosa. De manera similar, para otros entornos probablemente haya pistas en el hash perl %ENV que debería darle pistas valiosas.

+0

Ah, finalmente entendí por qué me degradaron. No he visto la etiqueta de powershell hasta ahora. Mi error. –

+0

No fui yo quien te votó negativamente, pero me encantaría una variable de entorno para decirme que PowerShell se está ejecutando. Desafortunadamente, Powershell no tiene esa variable. El script utiliza el entorno para determinar qué mostrar para otros tipos de shell. –

+0

Mirando aquí http://vlaurie.com/computers2/Articles/environment-variables-windows-vista-7.htm parece que COMSPEC apunta a cmd.exe por defecto; tal vez apunta al ejecutable PowerShell cuando se ejecuta bajo PowerShell? Si es así, debería poder averiguar el ambiente de tiempo de ejecución del entorno, incluyendo Cygwin y similares ... –

5

Utiliza getppid(). Tome este fragmento en child.pl:

my $ppid = getppid(); 
system("ps --no-headers $ppid"); 

Si se ejecuta desde la línea de comandos, system mostrará bash o similar (entre otras cosas). Ejecútelo con system("perl child.pl"); en otro script, p. Ej. parent.pl, y verá que perl parent.pl lo ejecutó.

Para capturar sólo el nombre del proceso con argumentos (gracias a Ikegami para la sintaxis correcta ps):

my $ppid = getppid(); 
my $ps = `ps --no-headers -o cmd $ppid`; 
chomp $ps; 

EDIT: Una alternativa a este enfoque, podría ser la creación de enlaces de software a su secuencia de comandos, haga que los diferentes contextos utilicen diferentes enlaces para acceder a su secuencia de comandos e inspeccione $0 para crear lógica alrededor de eso.

+2

Un poco más confiable: 'chomp (mi $ parent_name = \' ps --no-headers -o cmd $ ppid \ ');' – ikegami

+0

@ikegami: Gracias. :) No sabía cómo especificar ese formato. – flesk

+0

Desafortunadamente, Perl en Windows no admite 'getppid()' ni está descartando a 'ps' una posibilidad. :( –

3

Sugeriría un enfoque diferente para lograr su objetivo.En lugar de adivinar el contexto, hágalo más explícito. Cada caso de uso está completamente separado, por lo que tiene tres interfaces diferentes.

  1. Función que se puede llamar dentro de un programa Perl. Esto probablemente devolvería una estructura de datos de Perl. Esto es mucho más fácil, más rápido y más confiable que analizar el resultado del script. También serviría como base para los scripts.

  2. Secuencia de comandos que genera el shell actual. Puede mirar $ENV{SHELL} para descubrir qué shell se está ejecutando. Para los puntos de bonificación, proporcione un interruptor para invalidar explícitamente.

  3. Una secuencia de comandos que se puede llamar dentro de un programa que no es de Perl, como su servidor de integración continua y emitir salida legible por máquina. XML y/o JSON o lo que sea.

2 y 3 sería sólo envolturas delgadas para dar formato a los datos que salen de 1.

Cada uno está diseñado para adaptarse a su necesidad específica. Cada uno funcionará sin heurística. Cada uno será mucho más simple que tratar de adivinar el contexto y lo que el usuario quiere.

Si no puede separar 2 y 3, haga que el servidor de integración continua establezca una variable de entorno y búsquela.

+0

De acuerdo, en el caso general. Como mencioné, los anteriores fueron solo ejemplos de posibles aplicaciones de esta técnica. En este caso, el script emite un script de shell y otras herramientas esperan que emita el tipo correcto de script de shell para el shell que está invocando el script. Para casi todos los demás shells, existen variables de entorno que indican qué shell usar. Powershell no da esa variable. –

1

Esto es en Windows XP con PowerShell v2.0, así que tómelo con un grano de sal.

En una cáscara de cmd.exe, me sale:

PSModulePath=C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules\

mientras que en la ventana de la consola de PowerShell, me sale:

PSModulePath=E:\Home\user\WindowsPowerShell\Modules;C:\WINDOWS\system32\WindowsP owerShell\v1.0\Modules\

donde E:\Home\user es donde mi carpeta "Mis documentos" es. Entonces, una heurística puede ser verificar si PSModulePath contiene una ruta dependiente del usuario.

Además, en una ventana de la consola, me sale:

!::=::\

en el medio ambiente. Del PowerShell ISE, me sale:

!::=::\ 
!C:=C:\Documents and Settings\user
+0

+1 - Ah, mierda. Ni siquiera noté tu respuesta. Acabo de descubrir lo mismo. Por cierto, eso no es powershell 1.0 - v1 no es compatible con los módulos. La ruta en% windir% es v1.0 para v1, v2 y v3 de powershell. – x0n

1

Si se está utilizando PowerShell 2.0 o superior (más probable), se puede inferir la shell como un proceso principal mediante el examen de la variable de entorno %psmodulepath%. Por defecto, apunta a los módulos del sistema bajo %windir%\system32\windowspowershell\v1.0\modules; esto es lo que vería si examina la variable desde cmd.exe.

Sin embargo, cuando se inicia PowerShell, deja por delante la ruta de búsqueda del módulo predeterminada del usuario a esta variable de entorno que se ve así: %userprofile%\documents\windowspowershell\modules. Esto es heredado por procesos secundarios. Entonces, su lógica sería probar si% psmodulepath% comienza con% userprofile% para detectar powershell 2.0 o superior. Esto no funcionará en PowerShell 1.0 porque no admite módulos.

Cuestiones relacionadas