2011-11-16 109 views
1

可可新手警告!如何從shell命令捕獲輸出?

我發現下面的外殼命令是一個很好的方法,以確定是否一個進程正在運行(1 =運行,0 =未運行):

if [ $(ps -Ac | egrep -o 'ProcessName') ]; then echo 1; else echo 0; fi; 

我可以與「系統納入可可這「命令:

system("if [ $(ps -Ac | egrep -o 'Finder') ]; then echo 1; else echo 0; fi;"); 

然而,輸出被定向到運行日誌,我無法弄清楚如何捕獲的結果(0或1)在我的可可代碼。

我試圖實現此與NSTask如下:

NSTask *task = [[NSTask alloc] init]; 
[task setLaunchPath:@"/bin/sh"]; 
[task setArguments:[NSArray arrayWithObject:@"if [ $(ps -Ac | egrep -o 'Finder') ]; then echo 1; else echo 0; fi;"]]; 
NSPipe *pipe = [NSPipe pipe]; 
[task setStandardOutput:pipe]; 
[task launch]; 
NSData *data = [[pipe fileHandleForReading] readDataToEndOfFile]; 
[task waitUntilExit]; 
[task release]; 
NSString *output = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 
NSLog (@"%@", output); 
[output release]; 

然而,這會產生以下錯誤消息:

如果[$(PS -Ac | egrep的-o '搜索') ]。然後回顯1;其他回顯0; fi ;:沒有這樣的文件或目錄

你能告訴我怎樣才能正確實現這個shell命令的方式,允許我在代碼中捕獲輸出(1或0)? (我知道確定一個進程是否正在運行的其他方法,但我的問題的部分原因是要學習如何在Cocoa中實現shell腳本。)

非常感謝您對此有任何幫助問題。

+2

看看它是如何工作的,爲什麼依靠一個相對複雜的表達式爲初學者。看看你是否可以使用echo 1來工作。同樣因爲'沒有這樣的文件或目錄'消息,系統()直接調用本地目錄,尋找一個文件名'if ...'。我猜你需要用shell和shell的'-e'(執行選項?)包裝你的'腳本',產生簡單的大小寫測試'[task setArguments:[NSArray arrayWithObject:@「/ bin/bash -e'echo 1'「]]'。爲什麼不使用你的代碼來調用保存到文件系統的腳本?祝你好運。 – shellter

+1

Shell腳本由shell執行;從'system()'運行一個shell,你可以使用'system(「sh -c'echo moo'」)''。你最好從'system()'中獲取結果代碼而不是命令的輸出,然後你不需要'if'和'echo's:'system(「sh -c'ps -Ac | egrep -o Finder'「)'和'egrep'的退出碼將被返回,表示是否匹配。 – tripleee

+1

沒有必要測試ps |的輸出egrep的。而是測試egrep的返回值。 IOW,只需寫「if ps -Ac | egrep -o'Finder'>/dev/null」(或者只是使用pgrep!) –

回答

1

搶蘋果是怎麼做的,謝謝你的約儘可能在代碼中使用直接的解決方案一般指針。我通過JongAm公園的包裝器sysctl,以及蘋果的ps源代碼看去。整合需要一段時間,但我現在知道在哪裏尋找直接解決方案來獲取流程列表。

shellter和tripleee,感謝您的關於與shell命令交互的建議。根據你的建議,我有三種方法可以工作(!):

方法1使用system命令的返回碼(無需egrep -o):

BOOL processIsRunning = system("ps -Ac | grep 'ProcessName' > /dev/null") == 0; 

方法2使用NSTask與外殼-c選項(注意:-c而不是-e):

NSTask *task = [[NSTask alloc] init]; 
[task setLaunchPath:@"/bin/sh"]; 
[task setArguments:[NSArray arrayWithObjects:@"-c",@"ps -Ac | grep 'ProcessName'",nil]]; 
NSPipe *pipe = [NSPipe pipe]; 
[task setStandardOutput:pipe]; 
[task launch]; 
NSData *data = [[pipe fileHandleForReading] readDataToEndOfFile]; 
[task waitUntilExit]; 
[task release]; 
NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 
BOOL processIsRunning = [result length] > 0; 

方法3也使用NSTask與shell -c選項,但在這種情況下,要執行的命令是另一個具有其自己的外殼的-c選項(這是我經過多次試驗和錯誤才能找到的唯一方法,將if結構合併到要執行的命令中;當然,這是方式矯枉過正目前的問題):

NSTask *task = [[NSTask alloc] init]; 
[task setLaunchPath:@"/bin/sh"]; 
[task setArguments:[NSArray arrayWithObjects:@"-c",@"/bin/sh -c 'if [ \"$(ps -Ac | egrep -o 'ProcessName')\" = \"ProcessName\" ]; then echo 1; else echo 0; fi;'",nil]]; 
NSPipe *pipe = [NSPipe pipe]; 
[task setStandardOutput:pipe]; 
[task launch]; 
NSData *data = [[pipe fileHandleForReading] readDataToEndOfFile]; 
[task waitUntilExit]; 
[task release]; 
NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 
BOOL processIsRunning = [result intValue] == 1; 

謝謝大家精彩的幫助。

3

你就錯了。而不是問「我如何運行外部進程來執行X」,你應該問「我如何編寫代碼來執行X」。

你不需要使用外部腳本來獲取進程的列表。總的來說,出於性能和安全方面的原因,您應該總是嘗試使用API​​,而不是啓動外部任務。

在這種情況下你想要的API是在sysctl C接口。

JongAm Park爲使用sysctl編寫了Objective-C wrapper以獲取正在運行的進程的列表。在他的帖子上的評論中也有很好的觀點。

或者,你可以看到通過查看the source code for the ps command.

0

這裏不涉及可可在所有一般的答案:

如果你想從system()獲得輸出,不使用system(),使用popen()

+0

謝謝。我會研究popen()。解決問題的方法很多! – scolfax