如何找出是什么脚本、程序或shell执行了我的Perl脚本?

如何找出是什么脚本、程序或shell执行了我的Perl脚本?,perl,shell,powershell,Perl,Shell,Powershell,我如何确定哪个脚本、程序或shell执行了我的Perl脚本 示例:如果从shell执行,我可能希望有人类可读的输出(针对每种类型的shell进行定制),如果从另一个perl脚本调用脚本,则希望有不同类型的输出,如果从诸如持续集成服务器之类的程序执行,则希望有机器可读的格式 动机:我有一个工具,可以根据shell执行它来更改它的输出。我通常会将此行为作为脚本的一个选项来实现,但此工具的设计不允许使用选项。其他shell具有指示shell正在运行的环境变量。我正在开发一个补丁来支持Powershel

我如何确定哪个脚本、程序或shell执行了我的Perl脚本

示例:如果从shell执行,我可能希望有人类可读的输出(针对每种类型的shell进行定制),如果从另一个perl脚本调用脚本,则希望有不同类型的输出,如果从诸如持续集成服务器之类的程序执行,则希望有机器可读的格式

动机:我有一个工具,可以根据shell执行它来更改它的输出。我通常会将此行为作为脚本的一个选项来实现,但此工具的设计不允许使用选项。其他shell具有指示shell正在运行的环境变量。我正在开发一个补丁来支持Powershell,它没有这样的特殊变量


编辑:这些答案中有许多恰好是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