我如何确定哪些脚本,程序或shell执行了我的Perl脚本?
示例:如果从shell(针对每种类型的shell自定义)执行,我可能希望具有人类可读输出,如果从另一个perl脚本调用脚本,则可能需要不同类型的输出,如果从a执行,则可能需要机器可读格式程序,如持续集成服务器。
动机:我有一个工具可以根据shell执行它来改变输出。我通常将此行为作为脚本的选项实现,但此工具的设计不允许选项。其他shell具有指示正在运行的shell的环境变量。我正在开发一个支持Powershell的补丁,它没有这样的特殊变量。
编辑:其中许多答案恰好是特定于Linux的。不幸的是,Powershell适用于Windows。在这种情况下,getppid
,$ENV{SHELL}
变量以及对ps
的炮轰将无济于事。该脚本需要跨平台运行。
答案 0 :(得分:5)
您使用getppid()。在child.pl
:
my $ppid = getppid();
system("ps --no-headers $ppid");
如果从命令行运行它,system
将显示bash
或类似(以及其他内容)。在另一个脚本中使用system("perl child.pl");
执行它,例如parent.pl
,您会看到perl parent.pl
执行了它。
仅使用参数捕获进程的名称(感谢ikegami提供正确的ps
语法):
my $ppid = getppid();
my $ps = `ps --no-headers -o cmd $ppid`;
chomp $ps;
编辑:此方法的替代方法可能是创建指向您脚本的软链接,使不同的上下文使用不同的链接来访问您的脚本并检查$0
以构建逻辑这一点。
答案 1 :(得分:3)
我建议采用不同的方法来实现目标。而不是猜测上下文,使其更明确。每个用例都是完全独立的,因此有三个不同的接口。
可以在Perl程序中调用的函数。这可能会返回Perl数据结构。这比解析脚本输出更容易,更快速,更可靠。它也可以作为脚本的基础。
为当前shell输出的脚本。它可以查看$ENV{SHELL}
以发现正在运行的shell。对于奖励积分,请提供明确覆盖的开关。
可以在非Perl程序中调用的脚本,例如持续集成服务器,并发出机器可读输出。 XML和/或JSON或其他。
2和3只是用于格式化来自1的数据的薄包装。
每个都是根据其特定需求量身定制的。每个都可以没有启发式工作。每个都比试图猜测上下文和用户想要的东西简单得多。
如果您不能将2和3分开,请让持续集成服务器设置一个环境变量并查找它。
答案 2 :(得分:1)
根据您的环境,您可以从环境变量中获取它。请考虑以下代码:
/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有一个变量$_
,它还显示正在执行的shell或脚本的绝对文件名,这也可能提供一个有价值的提示。同样地,对于其他环境,很可能会在perl %ENV
哈希中留下线索,这些线索应该为您提供有价值的提示。
答案 3 :(得分:1)
这是在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
答案 4 :(得分:1)
如果您正在运行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中不起作用,因为它不支持模块。