gpt4 book ai didi

objective-c - Xcode Cocoa Objective C 使用 NSTask 执行 "Find"Shell 命令返回语法

转载 作者:行者123 更新时间:2023-12-03 17:38:25 30 4
gpt4 key购买 nike

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

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

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

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

NSString* newShell = @"-c";
NSString* commandFind = @"find";
NSString* optionName = @"-iname";
NSString* searchFor = @"\"";
NSString* searchPath = @"\"";
searchPath = [searchPath stringByAppendingString:_searchPathOutlet.stringValue];
searchPath = [searchPath stringByAppendingString:@"\""];
NSString* searchWildCard = @"*";
NSString* searchWord = _searchWordsOutlet.stringValue;
searchFor = [searchFor stringByAppendingString:searchWildCard];
searchFor = [searchFor stringByAppendingString:searchWord];
searchFor = [searchFor stringByAppendingString:searchWildCard];
searchFor = [searchFor stringByAppendingString:@"\""];
NSLog(@"%@",searchPath); //debug
NSLog(@"%@",searchFor); //debug
NSTask *task = [[NSTask alloc] init];
[task setLaunchPath:@"/bin/sh"];
NSArray *arguments = [NSArray arrayWithObjects: newShell, commandFind, searchPath, optionName, searchFor, nil];
NSString *stringRep = [NSString stringWithFormat:@"%@",arguments]; //debug
NSLog(@"%@",stringRep); //debug
[task setArguments:arguments];
NSPipe* pipe = [NSPipe pipe];
[task setStandardOutput:pipe];
[task launch];
[task waitUntilExit]; // Alternatively, make it asynchronous.
NSData *outputData = [[pipe fileHandleForReading] readDataToEndOfFile];
NSString *outputString = [[NSString alloc] initWithData:outputData encoding:NSUTF8StringEncoding];
_searchResultsOutlet.string = outputString;



The output is as follows:
2015-07-16 12:09:39.141 APSAETVSANSearch[2716:68456] "/Users/test/Downloads"
2015-07-16 12:09:39.141 APSAETVSANSearch[2716:68456] "*adobe*"
2015-07-16 12:09:39.141 APSAETVSANSearch[2716:68456] (
"-c",
find,
"\"/Users/test/Downloads\"",
"-iname",
"\"*adobe*\""
)
usage: find [-H | -L | -P] [-EXdsx] [-f path] path ... [expression]
find [-H | -L | -P] [-EXdsx] -f path [path ...] [expression]

我同意你和特洛伊木马的观点。我是 Objective-C 的新手,我发现与其他语言相比,语法有点奇怪,但下面列出了一些工作代码。我想在异步线程中将函数 doSearch 作为回调运行。我熟悉与使用委托(delegate)到线程回调函数(例如 searchPathURL、searchWords、textView)传递“线程安全”参数相关的 Microsoft 线程,但似乎无法通过 google 找到合适的示例。这是我的功能,你能帮我开始吗?

- (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 <command>时该命令必须是一个参数。也就是说,在 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*" ] 。在不需要时使用 shell 只会增加危险和效率低下。例如,如果您的用户在文本字段中输入“$(rm -rf ~)”,那么当您运行任务时他们会非常不高兴。如果目录路径或搜索项包含双引号 ( " ) 字符,则破坏性较小,但更有可能。

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

<小时/>

针对您更新的问题进行更新:

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

- (IBAction)buttonSearch_Click:(id)sender {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
doSearch(directoryURL, _searchWordOutlet.stringValue, _textViewOutlet);
});
}

但是,您无法从后台线程更新 GUI。所以,你的doSearch()函数需要将对 TextView 的任何操作分流回主线程。它可以使用如下代码来完成此操作:

dispatch_async(dispatch_get_main_queue(), ^{
[textView insertText:url.path];
[textView insertText:@"\n"];
});

顺便说一句,您检查搜索词是否在路径中的检查与 find 的检查不同。你开始使用的命令确实如此。您正在检查整个路径,包括父目录,而 find命令仅检查每个项目的文件名。您可以从 NSURL 获取文件名通过请求其 lastPathComponent而不是它的path .

此外,要执行不区分大小写的检查一个字符串是否包含另一个字符串,您不应将两个字符串都小写,然后调用 -containsString: 。你应该只使用 -localizedCaseInsensitiveContainsString:无需手动小写。 (或者,如果您不希望适合区域设置且不区分大小写,则可以使用 -rangeOfString:options:NSCaseInsensitiveSearch 作为选项。)

关于objective-c - Xcode Cocoa Objective C 使用 NSTask 执行 "Find"Shell 命令返回语法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31459727/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com