Objective c Xcode C使用NSTask执行;查找“;Shell命令返回语法

Objective c Xcode C使用NSTask执行;查找“;Shell命令返回语法,objective-c,xcode,shell,cocoa,nstask,Objective C,Xcode,Shell,Cocoa,Nstask,我正在使用Xcode 6.4尝试执行find命令。应用程序是find命令的包装器。我们有一个SAN,finder不会搜索,但是find命令会搜索SAN,我不想与SAN讨论这些问题 我最初在几分钟内用Swift编写了应用程序。不幸的是,它不会部署到OSX10.8,所以我继续在Objective C中重写 我怀疑我遇到的问题与我构造参数数组的方式有关。在谷歌搜索了3天之后,我遇到的唯一的例子都是硬编码的参数,在现实世界中,我们使用变量 以下是我单击“搜索”按钮时关联的基本代码 我同意你和特洛伊的观点

我正在使用Xcode 6.4尝试执行find命令。应用程序是find命令的包装器。我们有一个SAN,finder不会搜索,但是find命令会搜索SAN,我不想与SAN讨论这些问题

我最初在几分钟内用Swift编写了应用程序。不幸的是,它不会部署到OSX10.8,所以我继续在Objective C中重写

我怀疑我遇到的问题与我构造参数数组的方式有关。在谷歌搜索了3天之后,我遇到的唯一的例子都是硬编码的参数,在现实世界中,我们使用变量

以下是我单击“搜索”按钮时关联的基本代码


我同意你和特洛伊的观点。我是objective-c新手,与其他语言相比,我觉得语法有点奇怪,但我有下面列出的一些工作代码。我想在异步线程中以回调的形式运行doSearch函数。我熟悉微软的线程技术,它使用线程回调函数的委托来传递“线程安全”参数(如searchPathURL、searchWords、textView),但似乎无法通过谷歌找到合适的例子。这是我的功能,你能帮我开始吗

- (IBAction)buttonSearch_Click:(id)sender {
doSearch(directoryURL, _searchWordOutlet.stringValue, _textViewOutlet);
}

void doSearch(NSURL *searchPathURL, NSString *searchWords, NSTextView *textView){
NSArray *keys = [NSArray arrayWithObjects:
NSURLIsDirectoryKey, NSURLIsPackageKey, NSURLLocalizedNameKey, nil];
NSDirectoryEnumerator *enumerator = [[NSFileManager defaultManager]
enumeratorAtURL:directoryURL
includingPropertiesForKeys:keys
options:(NSDirectoryEnumerationSkipsHiddenFiles)
errorHandler:^(NSURL *url, NSError *error) {
 // Handle the error.
 // Return YES if the enumeration should continue after the error.
 return YES;
}
];
for (NSURL *url in enumerator) {
// Error-checking is omitted for clarity.

NSNumber *isDirectory = nil;
[url getResourceValue:&isDirectory forKey:NSURLIsDirectoryKey error:NULL];

if ([isDirectory boolValue]) {
NSString *localizedName = nil;
[url getResourceValue:&localizedName forKey:NSURLLocalizedNameKey error:NULL];

NSNumber *isPackage = nil;
[url getResourceValue:&isPackage forKey:NSURLIsPackageKey error:NULL];

if ([isPackage boolValue]) {
//Its a package
//NSLog(@"Package at %@", localizedName);
}
else {
//Its a directory
//NSLog(@"Directory at %@", localizedName);
}
}
else {
//Its a file
NSString *searchPath = [url.path lowercaseString];
NSString *searchText = [searchWords lowercaseString];
if ([searchPath containsString:searchText]) {
NSLog(@"%@", url.path);
[textView insertText:url.path];
[textView insertText:@"\n"];
}
}
}
}

使用
/bin/sh-c
时,命令必须是一个参数。也就是说,在shell中,您不能执行以下操作:

/bin/sh -c find "/Users/test/Downloads" -iname "*adobe*"
你必须做到:

/bin/sh -c 'find "/Users/test/Downloads" -iname "*adobe*"'
因此,只需制作一个字符串,其内容相当于:

NSString* command = @"find \"/Users/test/Downloads\" -iname \"*adobe*\"";
并使用相当于
@[@“-c”,command]
的参数数组

或者,如果您不需要shell来处理字符串(在您的示例中,您不需要),那么您应该将任务的启动路径设置为
@/usr/bin/find“
,并将参数设置为
@[@”/Users/test/Downloads“,@“-iname”,“@”*adobe*”
。在不需要的时候使用外壳只会增加危险和效率低下。例如,如果您的用户在文本字段中输入“$(rm-rf~”,则在您运行任务时,他们会非常不高兴。破坏性较小但更有可能的情况是,目录路径或搜索项包含双引号(
)字符

综上所述,我同意trojanfoe的观点,即您应该以编程方式执行此操作,而不是启动子进程。如果
NSDirectoryEnumerator
由于某种原因无法工作,您可以使用POSIX/BSD API


更新以回应您更新的问题:

要在后台运行任务,您可以使用Grand Central Dispatch(GCD)。例如,您的
-buttonSearch\u Click:
方法可以这样编写:

- (IBAction)buttonSearch_Click:(id)sender {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        doSearch(directoryURL, _searchWordOutlet.stringValue, _textViewOutlet);
    });
}
但是,您无法从后台线程更新GUI。因此,您的
doSearch()
函数需要将文本视图的任何操作分流回主线程。它可以使用如下代码来完成此操作:

dispatch_async(dispatch_get_main_queue(), ^{
    [textView insertText:url.path];
    [textView insertText:@"\n"];
});
顺便说一下,检查搜索项是否在路径中与开始使用的
find
命令不同。您检查的是整个路径,包括父目录,而
find
命令只检查每个项目的文件名。您可以通过请求
l从
NSURL
获取文件名astPathComponent
而不是它的
路径


另外,要对一个字符串是否包含另一个字符串进行不区分大小写的检查,您不应该将两个字符串都小写,然后调用
-containssString:
。您应该只使用
-localizedCaseInsensitiveContainsString:
,而不手动小写。(或者,如果您不希望区域设置适当的大小写不敏感,您可以使用
-rangeOfString:options:
NSCaseInsensitiveSearch
作为选项。)

为什么不在代码中实现您想要的功能呢?这样会更快、更高效。我有很多用户将使用此工具,但他们都不知道如何使用终端会话(假设这就是您所说的“在代码中”的意思)。我真的需要一个GUI,任何人都可以在没有任何编码知识的情况下使用。你对如何修复代码有什么建议吗?我知道这必须非常简单,因为我是objective-c新手。不,我的意思是编写代码来做
find
所做的事情;这基本上是在目录中查找符合特定条件的文件。分叉shell pr如果程序本身无法完成任务,则处理程序中可以完成的任务通常是一个坏主意。好建议!我想我可以尝试使用NSDirectoryEnumerator,但搜索SAN目录时可能会遇到与Finder假设Finder也使用enumerator相同的问题。在获得initi后al shell工具正确包装员工可以立即使用,然后我将尝试API。制造SAN的公司在2年前停业,我们无法在元数据控制器上更新操作系统。我同意你和特洛伊木马。我是objective-c新手,与其他语言相比,我觉得语法有点奇怪,但我我有下面列出的一些工作代码。我想在异步线程中以回调的形式运行doSearch函数。我熟悉Microsoft的线程,该线程与向线程的回调函数传递“线程安全”参数有关(例如searchPathURL、searchWords、textView)但似乎无法通过谷歌找到一个合适的例子。这是我的功能,你能让我开始吗?关于在后台线程上进行搜索的问题应该是一个单独的问题,但我更新了我的答案来解决它。
dispatch_async(dispatch_get_main_queue(), ^{
    [textView insertText:url.path];
    [textView insertText:@"\n"];
});