如何找出是什么脚本、程序或shell执行了我的Perl脚本?
我如何确定哪个脚本、程序或shell执行了我的Perl脚本 示例:如果从shell执行,我可能希望有人类可读的输出(针对每种类型的shell进行定制),如果从另一个perl脚本调用脚本,则希望有不同类型的输出,如果从诸如持续集成服务器之类的程序执行,则希望有机器可读的格式 动机:我有一个工具,可以根据shell执行它来更改它的输出。我通常会将此行为作为脚本的一个选项来实现,但此工具的设计不允许使用选项。其他shell具有指示shell正在运行的环境变量。我正在开发一个补丁来支持Powershell,它没有这样的特殊变量如何找出是什么脚本、程序或shell执行了我的Perl脚本?,perl,shell,powershell,Perl,Shell,Powershell,我如何确定哪个脚本、程序或shell执行了我的Perl脚本 示例:如果从shell执行,我可能希望有人类可读的输出(针对每种类型的shell进行定制),如果从另一个perl脚本调用脚本,则希望有不同类型的输出,如果从诸如持续集成服务器之类的程序执行,则希望有机器可读的格式 动机:我有一个工具,可以根据shell执行它来更改它的输出。我通常会将此行为作为脚本的一个选项来实现,但此工具的设计不允许使用选项。其他shell具有指示shell正在运行的环境变量。我正在开发一个补丁来支持Powershel
编辑:这些答案中有许多恰好是linux特有的。不幸的是,Powershell是针对Windows的
getppid
,$ENV{SHELL}
变量,并向外剥离到ps
在这种情况下没有帮助。此脚本需要跨平台运行。根据您的环境,您可以从环境变量中选择它。考虑下面的代码:
/usr/bin/perl -MData::Dumper -e 'print Dumper(\%ENV);' | grep sh
在我的Ubuntu系统上,它让我:
'SHELL' => '/bin/bash',
所以我想这说明我正在从bash shell运行perl。如果您使用其他内容,SHELL变量可能会给您一个提示
但是假设您知道自己在bash中,但是perl是从子shell运行的。然后尝试:
/bin/sh -c "/usr/bin/perl -MData::Dumper -e 'print Dumper(\%ENV);'" | grep sh
你会发现:
'_' => '/bin/sh',
'SHELL' => '/bin/bash',
因此,shell仍然是bash,但是bash有一个变量$\uu
,它还显示正在执行的shell或脚本的绝对文件名,这也可能给出一个有价值的提示。类似地,对于其他环境,perl%ENV
散列中很可能会留下一些线索,这些线索会给您提供有价值的提示。您使用的。在child.pl
中获取此片段:
my $ppid = getppid();
system("ps --no-headers $ppid");
如果从命令行运行它,system
将显示bash
或类似内容(除其他外)。使用系统(“perl child.pl”)执行它在另一个脚本中,例如parent.pl
,您将看到perl parent.pl
执行了它
要仅捕获带有参数的进程名称(感谢ikegami提供了正确的ps
语法):
编辑:这种方法的另一种选择,可能是创建脚本的软链接,让不同的上下文使用不同的链接来访问脚本,并检查$0
,以构建逻辑。我建议使用不同的方法来实现您的目标。与其猜测上下文,不如让它更明确。每个用例是完全独立的,因此有三个不同的接口
可以在Perl程序中调用的函数。这可能会返回一个Perl数据结构。这比解析脚本输出更容易、更快、更可靠。它还将作为脚本的基础
为当前shell输出的脚本。它可以查看$ENV{SHELL}
来发现SHELL正在运行什么。对于奖励积分,提供一个开关以显式覆盖
可以在非Perl程序(如持续集成服务器)内调用的脚本,并发出机器可读的输出。XML和/或JSON或其他
2和3只是对1中的数据进行格式化的薄型包装
每一个都是根据其具体需要量身定制的。每种方法都可以在没有启发式的情况下工作。每种方法都比猜测上下文和用户想要什么要简单得多
如果无法将2和3分开,请让continuous integration server设置一个环境变量并查找它。这是在Windows XP和PowerShell v2.0上实现的,因此请谨慎对待
在cmd.exe
shell中,我得到:
PSModulePath=C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules\
而在PowerShell控制台窗口中,我得到:
PSModulePath=E:\Home\user\WindowsPowerShell\Modules;C:\WINDOWS\system32\WindowsP
owerShell\v1.0\Modules\
其中E:\Home\user
是我的“我的文档”文件夹所在的位置。因此,一种启发式方法可能是检查PSModulePath
是否包含依赖于用户的路径
此外,在控制台窗口中,我得到:
!::=::\代码>
在环境中。从PowerShell ISE,我得到:
!::=::\
!C:=C:\Documents and Settings\user
!::=::\
!C:=C:\Documents and Settings\user如果运行的是PowerShell 2.0或更高版本(最有可能),则可以通过检查环境变量%psmodulepath%
来推断shell是父进程。默认情况下,它指向%windir%\system32\windowspowershell\v1.0\modules
下的系统模块;如果您从cmd.exe
检查变量,就会看到这一点
但是,当PowerShell启动时,它会将用户的默认模块搜索路径前置到此环境变量,该环境变量如下:%userprofile%\documents\windowspowershell\modules
。这是由子进程继承的。因此,您的逻辑是测试%psmodulepath%是否以%userprofile%开头,以检测powershell 2.0或更高版本。这在PowerShell 1.0中不起作用,因为它不支持模块。我不确定我是否理解-在这种情况下,您不应该查看父进程吗?您可以测试STDOUT是否是终端(-t
),如果是,则假设您是从交互式shell而不是(比如)连续集成守护程序中调用的。然而,这种常见的技术并没有针对每个不同的可能父级定制输出(但我认为这有点不合时宜);有了Powershell,就没有这样的环境变量了。@x0n:是的,在一个只有*nix的世界里,getppid
会很神奇。此脚本需要在Windows上工作,请指定
!::=::\
!C:=C:\Documents and Settings\user