当前位置:  开发笔记 > 编程语言 > 正文

找出Cocoa中可执行文件的位置

如何解决《找出Cocoa中可执行文件的位置》经验,为你挑选了3个好方法。

简单的问题是:如何在Cocoa应用程序中找出可执行文件的位置.

请记住,在许多类Unix操作系统中,人们使用PATH环境为其可执行文件分配首选位置,尤其是当他们的系统中有多个版本的相同应用程序时.作为一个好习惯,我们的Cocoa应用程序应该找到它需要的可执行文件的PREFERRED位置.

例如,/ usr/bin中的Leopard默认配置中有一个SVN 1.4,你通过/ opt/local/bin上的MacPorts安装了一个更新的版本,比如SVN 1.5.3.你可以使用/etc/path.d或.bash_profile或.zshrc设置你的PATH:

export PATH =/opt/local/bin:$ PATH

因此,您可以使用新版本的svn而不是系统中的旧版本.它适用于任何终端环境.但不是在Cocoa应用程序中.据我所知,Cocoa应用程序只有一个默认的PATH环境,如下所示:

export PATH ="/ usr/bin:/ bin:/ usr/sbin:/ sbin"

默认情况下,它不会使用/etc/path.d,.bash_profile,.profile,.zshrc等中的配置.

那我们究竟怎么办?

ps我们在这里有一个半解决方案,但它不能完全满足这个问题的目标.



1> Brian Webste..:

尝试执行此操作的棘手部分是,用户可以将其shell设置为任何内容:sh,bash,csh,tcsh等,并且每个shell以不同方式设置其终端环境.我不确定自己是否会为此自行解决问题,但如果你真的想这样做,这就是我要采取的路线.

第一步是找出用户的shell.在OS X上,此信息存储在目录服务中,可以通过DirectoryService.framework中的API或使用dscl命令行工具加入.DirectoryService API是一个王室的痛苦,所以我可能会去CLI路线.在Cocoa中,您可以使用NSTask来执行带有参数的工具来获取用户的shell(我会在其他地方留下详细信息).该命令看起来像:

dscl -plist localhost -read /Local/Default/Users/username UserShell

这将返回您可以解释为plist并转换为NSDictionary的XML文本,或者您可以省略该-plist选项并自行解析文本输出.

一旦知道了用户shell的路径,下一步就是执行该shell并告诉它运行env命令打印出用户的环境.看起来大多数shell都接受一个-c命令行选项,它允许你传入一个字符串来执行 - 我想你只需要假设它是用户选择的任何shell的通用接口.

一旦你拥有了用户的环境,你就可以从中获取它们的路径列表,然后搜索你正在寻找的任何可执行文件.就像我说的那样,我真的不知道这是否值得这么麻烦,但如果我实施这个,那就是我要去的方向.



2> Abizern..:

与Brian Webster的回答有关:

获取User的shell的一种更简单的方法是使用NSProcessInfo类.例如

NSDictionary *environmentDict = [[NSProcessInfo processInfo] environment];
NSString *shellString = [environmentDict objectForKey:@"SHELL"];

这比使用dscl和解析XML输入更容易.



3> Andrey Taran..:

这是我基于上述答案的实现,可以从applicationDidFinishLaunching调用:

// from http://cocoawithlove.com/2009/05/invoking-other-processes-in-cocoa.html
#import "NSTask+OneLineTasksWithOutput.h"

void FixUnixPath() {
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^(void){
        NSString *userShell = [[[NSProcessInfo processInfo] environment] objectForKey:@"SHELL"];
        NSLog(@"User's shell is %@", userShell);

        // avoid executing stuff like /sbin/nologin as a shell
        BOOL isValidShell = NO;
        for (NSString *validShell in [[NSString stringWithContentsOfFile:@"/etc/shells" encoding:NSUTF8StringEncoding error:nil] componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]]) {
            if ([[validShell stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] isEqualToString:userShell]) {
                isValidShell = YES;
                break;
            }
        }

        if (!isValidShell) {
            NSLog(@"Shell %@ is not in /etc/shells, won't continue.", userShell);
            return;
        }
        NSString *userPath = [[NSTask stringByLaunchingPath:userShell withArguments:[NSArray arrayWithObjects:@"-c", @"echo $PATH", nil] error:nil] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
        if (userPath.length > 0 && [userPath rangeOfString:@":"].length > 0 && [userPath rangeOfString:@"/usr/bin"].length > 0) {
            // BINGO!
            NSLog(@"User's PATH as reported by %@ is %@", userShell, userPath);
            setenv("PATH", [userPath fileSystemRepresentation], 1);
        }
    });
}

PS这个工作的原因是因为它捕获了shell所做的环境变化.例如,RVM PATH=$PATH:$HOME/.rvm/bin在安装时添加到.bashrc.Cocoa应用程序是从launchd启动的,因此它们的PATH中没有这些更改.

我对这段代码并不是百分之百满意,因为它并没有抓住所有东西.我最初的意图是专门处理RVM,所以我不得不在这里使用非登录shell,但实际上,人们随机地将PATH修改放入.bashrc和.bash_profile中,因此最好同时运行它们.

我的一个用户甚至在他的shell配置文件中有一个交互式菜单(!!!),这自然导致这个代码挂起,我只为他导出一个shell env标志.:-)添加超时可能是一个好主意.

这也假设shell是bourne兼容的,因此不适用于鱼2.0,它在黑客社区中越来越受欢迎.(Fish认为$ PATH是一个数组,而不是冒号分隔的字符串.因此它默认使用空格作为分隔符打印它.可以做一个简单的修复,比如运行for i in $PATH; echo "PATH=$i"; end然后只采用开头的行PATH=.过滤是在任何情况下都是个好主意,因为配置文件脚本经常会自行打印.)

最后需要注意的是,这段代码已经成为一年多来发货应用程序的重要组成部分(一年中大部分时间都在Mac App Store上排名前10位的付费开发者工具).但是,我现在正在实施沙盒并将其取出; 当然,你不能从沙盒应用程序中做到这一点.我正在替换它,明确支持RVM和朋友,并手动重现他们各自的env更改.

对于那些希望从沙盒应用程序中使用类似系统Git的人,请注意,虽然您无权访问读取文件和枚举目录,但您可以访问stat - [[NSFileManager defaultManager] fileExistsAtPath:path].您可以使用它来探测寻找二进制文件的典型文件夹的硬编码列表,当您找到位置(例如/ usr/local或/ opt/local或其他)时,请让用户通过NSOpenPanel授予您访问权限.这不会抓住每个案例,但会处理90%的用例,这是您可以为开箱即用的用户做的最好的事情.

推荐阅读
臭小子
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有