如何使用AppleScript和Perl确定某个应用程序是否正在运行

BBColors通过阅读和写入BBEdit的偏好来做它的事情默认系统该默认手册页说:

Since applications do access the defaults system while they’re running, you shouldn’t modify the defaults of a running applicationIf you change a default in a domain that belongs to a running application, the application won’t see the change and might even overwrite the default.

所以,作为预防措施,bbcolors如果BBEdit(或TextWrangler,如果那是你的包)当前正在运行,工具将不会加载新的配色方案但是,如何测试应用程序当前是否正在运行?

BBColors是用Perl编写的,但我知道测试应用程序是否正在运行的最简单方法就是AppleScript:

tell application "System Events"
    count (every process whose creator type is "R*ch")
end tell

其中“R * ch”是BBEdit的四字符创建者类型。

If BBEdit isn’t running, it returns 0; if it is running, it returns 1 (or a larger integer, if, for whatever reason, you’re running more than one copy of BBEdit).

使用创建者类型有点令人讨厌 - 另外,一些进程没有创建者类型(大多数此类应用程序是后台“帮助”应用程序,但即使是一些普通应用程序,例如控制台,也没有创建者类型)所以,你也可以问这个名字:

tell application "System Events"
    count (every process whose name is "BBEdit")
end tell

并且您应该得到相同的结果,并且能够识别任何进程的额外好处 - 并非每个进程都有创建者类型,但它们都有名称。

还有显示的名称财产,不同于平原名称

tell application "System Events"
    count (every process whose displayed name is "BBEdit")
end tell

威力工作,但如果您有Finder的首选项,则不会始终显示打开的文件扩展名(就像我一样)在那种情况下,一个应用程序显示的名称包含“.app”扩展名,所以你必须写:

tell application "System Events"
    count (every process whose displayed name is "BBEdit.app")
end tell

名称“和”显示的名字“在其他方面也可能有所不同您可以确定Quicksilver是否正在使用它运行名称

tell application "System Events"
    count (every process whose name is "Quicksilver")
end tell

并且因为字符串比较不区分大小写,所以你可以错误地将它“错误地”化为“QuickSilver”或“quicksilver”或“QUICKSILVER”,它仍然可以工作但是如果你想通过它来识别它显示的名称,你必须使用你在其应用程序菜单上看到的聪明的Unicode负载拼写:

tell application "System Events"
    count (every process whose displayed name is "Quıcĸsıɩⅴεʀᵦ₄₉.app")
end tell

所以坚持:创作者类型名称properties are good bets; the显示的名称属性不是,因为它会根据用户的Finder首选项更改以显示文件扩展名。

从Perl和Shell做到这一点

就像我之前写的那样,BBColors是用Perl编写的,而不是AppleScript我想大多数Unixheads会做的是管道结果ps -aux通过grep的,但是从Perl或任何其他shell脚本语言调用AppleScript很容易:只需使用osascript命令行工具从终端,您可以输入:

osascript -e'告诉应用程序“系统事件”来计算名称为“Finder”的进程

这是一个Perl子例程,它将创建者类型作为参数,并返回AppleScript的结果(即the number of processes running with that creator):

sub is_app_running {
    my $creator = shift;

    my $applescript = qq{ 'tell application "System Events" to count }qq{ (every process whose creator type is "$creator")' };
    my $result = qx( osascript -e $applescript );
    chomp $result;

    return $result;
}

除了这个代码有一些微妙的错误:如果它传递一个包含文字双引号或反斜杠字符的创建者类型字符串,它将无法工作我不知道任何使用这些字符的创建者类型代码,但它们是合法的。

所以这是一个固定版本,反斜杠转义单引号,双引号和文字反斜杠对于Perl,我们需要一个级别的反斜杠,当我们调用时,我们需要shell的另一个级别osascript工具:

sub is_app_running {
    my $creator = shift;
    $creator =~ s{\\}{\\\\}g;
    $creator =~ s{"}{\\"}g;
    $creator =~ s{'}{'\\''}g;

    my $applescript = qq{ 'tell application "System Events" to count }qq{ (every process whose creator type is "$creator")' };
    my $result = qx( osascript -e $applescript );
    print "result: $result\n";
    chomp $result;

    return $result;
}

从Mac OS X 10.4开始,系统的默认Perl安装包括一个名为的Perl模块MacPerl(它开始在经典的Mac OS时代回归生活)。MacPerl包含一个名为的例程DoAppleScript(), which does what you think it does; it takes as input a string containing AppleScript code, runs the script, and returns the result as a string我们可以使用它而不是呼唤osascriptshell工具,像这样:

use MacPerl 'DoAppleScript';

sub is_app_running {
    my $creator = shift;
    $creator =~ s{\\}{\\\\}g;
    $creator =~ s{"}{\\"}g;

    my $applescript = qq{ tell application "System Events" to count } .
            qq{ (every process whose creator type is "$creator") };
    my $running = DoAppleScript($applescript);
    chomp $running;

    return $running;
}

这种技术唯一真正的优点是你不必担心转义单引号 - 只需双引号和字面反斜杠。DoAppleScript也比炮轰要快一点osascript,但这两种技术都非常快。

你也可以使用苹果::进程模块,是其中的一部分苹果::碳软件包,默认情况下也包含在Mac OS X 10.4的默认Perl安装中我们可以改写我们的is_app_running()子程序使用苹果::进程像这样:

use Mac::Processes;

sub is_app_running {
    my $creator = shift;
    my $running = 0;

    PROCESS_LIST:
    while ( my ($psn, $psi) = each(%Process) ) {
        if ($psi->processSignature eq $creator) {
            $running = 1;
            last PROCESS_LIST;
        }
    }

    return $running;
}

我们还可以使用名称识别应用程序苹果::进程,通过使用processName财产而不是processSignature; these names are the same as those returned by the名称AppleScript示例中的属性(即不显示的名称)。

使用的好处苹果::进程是你不必将任何AppleScript混合到你的Perl中不过,缺点是版本的苹果::碳基于Intel的Macs默认提供的模块包含一堆与endian相关的错误一个这样的错误是由...返回的创建者类型processSignatureproperty appear backwards: instead of “R*ch” for BBEdit, you get “hc*R”; instead of “MACS” for the Finder, you get “SCAM”.1

这可能会让你感到非常奇怪简短的解释是创建者类型不是真正的四个字符字符串; they’re four-byte integers, and treating each of the bytes as a MacRoman-encoded character is just a shortcut that makes them more readable and memorable(整个Carbon使用这种四字节“OSType”。)问题是PowerPC和680×0架构是大端和x86(a.k.a“Intel”)架构是小端,这意味着包含整数的字节在Intel上以相反的顺序出现。

克里斯南多尔- 谁维护整个苹果::碳模块套件 -修复了这些Intel兼容性错误back in June, but, alas, the fixed versions don’t yet ship with the OS因此,如果您正在编写自己使用的脚本并已升级到最新版本苹果::碳CPAN,你没有后顾之忧但是,如果您希望将您的脚本分发给可能具有默认(英特尔错误)版本的其他Mac用户苹果::碳安装,就像我和BBColors一样,你很难处理有缺陷的版本最好的方法是按名称识别应用程序 - 使用默认版本苹果::进程在所有运行10.4的Mac上 - 而不是创建者类型。


  1. Insert your own joke here. ↩︎

以前: BBColors 1.0
下一个: 处理流程