2010-08-09 99 views
10

這裏是我的代碼:NSTask NSPipe - 目標C命令行幫助

task = [[NSTask alloc] init]; 
[task setCurrentDirectoryPath:@"/applications/jarvis/brain/"]; 
[task setLaunchPath:@"/applications/jarvis/brain/server.sh"]; 

NSPipe * out = [NSPipe pipe]; 
[task setStandardOutput:out]; 

[task launch]; 
[task waitUntilExit]; 
[task release]; 

NSFileHandle * read = [out fileHandleForReading]; 
NSData * dataRead = [read readDataToEndOfFile]; 
NSString * stringRead = [[[NSString alloc] initWithData:dataRead encoding:NSUTF8StringEncoding] autorelease]; 

所以我想複製這樣的:

cd /applications/jarvis/brain/ 
./server.sh 

但在Objective-C使用NSTask。

由於某些原因,當我運行此代碼時,stringRead,不會返回任何內容。它應該返回當我啓動.sh文件時終端正在返回的內容。正確?

任何想法?

利亞

+0

你確定server.sh腳本輸出標準輸出嗎?也許你應該把stderr連接起來,看看它是否包含任何東西。 您可能還想考慮在任務運行時從管道讀取數據,因爲如果在您未讀取時嘗試向管道打印過多且緩衝區填滿,則下次任務將掛起它會嘗試輸出任何東西。 – 2010-08-09 21:07:34

+0

我不確定。你能告訴我一個例子嗎?是的,我刪除了[任務發佈]和[任務waitUntilExit]。同樣的問題。 – objectiveccoder001 2010-08-09 21:23:54

+0

你是否以編程方式(或在gdb中)檢查stringRead的內容,還是試圖使用NSLog或其他東西打印出來?如果您使用的是NSLog並且根本看不到輸出,請檢查您的輸出的「應用程序」>「實用程序」中的控制檯日誌。 Shell腳本作爲NSTask運行,可以使Xcode控制檯輸出停止工作。 除此之外,我第二凱文的意見,以檢查是否有標準錯誤的東西(只需添加第二個管道,並將其設置爲您的任務的標準錯誤),並且不依賴於管道能夠緩衝所有你的任務的輸出。 – puzzle 2010-08-09 21:39:40

回答

19

Xcode的錯誤
有一個在Xcode中,從後使用標準輸出新任務啓動打印任何輸出停止一個bug(它收集所有輸出,但不再打印任何東西)。你將不得不打電話[task setStandardInput:[NSPipe pipe]]讓它再次顯示輸出(或者,也可以將任務打印到stderr而不是stdout)。


建議最終的代碼:

NSTask *server = [NSTask new]; 
[server setLaunchPath:@"/bin/sh"]; 
[server setArguments:[NSArray arrayWithObject:@"/path/to/server.sh"]]; 
[server setCurrentDirectoryPath:@"/path/to/current/directory/"]; 

NSPipe *outputPipe = [NSPipe pipe]; 
[server setStandardInput:[NSPipe pipe]]; 
[server setStandardOutput:outputPipe]; 

[server launch]; 
[server waitUntilExit]; // Alternatively, make it asynchronous. 
[server release]; 

NSData *outputData = [[outputPipe fileHandleForReading] readDataToEndOfFile]; 
NSString *outputString = [[[NSString alloc] initWithData:outputData encoding:NSUTF8StringEncoding] autorelease]; // Autorelease optional, depending on usage. 
+0

看起來這似乎也凍結了我的代碼......呵呵......其他想法呢? – objectiveccoder001 2010-08-13 04:06:50

+0

而且,我試圖在回聲「你好世界」它返回空白....日期回覆空白。 – objectiveccoder001 2010-08-13 04:09:50

+0

即使使用'[server setStandardInput:[NSPipe pipe]]'?這有點奇怪。你是否逐字複製了我的代碼?試試吧,看看它是否可以與只包含'echo「Hello World」的文件一起工作; pwd | ls'。 如果它仍然不起作用,請告訴我們您正在使用的Xcode的版本,並查看是否將字符串寫入文件會生成任何輸出(可能只是Xcode終端不打印更多輸出)。 – 2010-08-13 08:15:21

9

將溶液上方凍結,因爲它是同步的。 致電[server waitUntilExit]會阻止運行循環,直到完成任務。

以下是獲取任務輸出的異步解決方案。

task.standardOutput = [NSPipe pipe]; 
[[task.standardOutput fileHandleForReading] setReadabilityHandler:^(NSFileHandle *file) { 
    NSData *data = [file availableData]; // this will read to EOF, so call only once 
    NSLog(@"Task output! %@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]); 

    // if you're collecting the whole output of a task, you may store it on a property 
    [self.taskOutput appendData:data]; 
}]; 

也許你想重複一遍上面的task.standardError

重要:

當任務結束,你必須設置readabilityHandler塊零;否則,你會遇到高CPU使用率,因爲閱讀永遠不會停止。

[task setTerminationHandler:^(NSTask *task) { 

    // do your stuff on completion 

    [task.standardOutput fileHandleForReading].readabilityHandler = nil; 
    [task.standardError fileHandleForReading].readabilityHandler = nil; 
}]; 

這是所有異步(你應該這樣做async),所以你的方法應該有一個^完成塊。

+0

完美。正在尋找一個塊API的例子。 – uchuugaka 2015-05-23 07:47:07