Wie kann ich einen Terminalbefehl (wie grep
) in meiner Objective-C Cocoa-Anwendung ausführen ?
objective-c
cocoa
macos
lostInTransit
quelle
quelle
/usr/bin
denen siegrep
leben.Antworten:
Sie können verwenden
NSTask
. Hier ist ein Beispiel, das '/usr/bin/grep foo bar.txt
' ausführen würde .NSPipe
undNSFileHandle
werden verwendet, um die Standardausgabe der Aufgabe umzuleiten.Ausführlichere Informationen zur Interaktion mit dem Betriebssystem in Ihrer Objective-C-Anwendung finden Sie in diesem Dokument im Apple Development Center: Interaktion mit dem Betriebssystem .
Bearbeiten: Enthaltene Korrektur für NSLog-Problem
Wenn Sie NSTask verwenden, um ein Befehlszeilenprogramm über Bash auszuführen, müssen Sie diese magische Zeile einfügen, damit NSLog funktioniert:
Eine Erklärung finden Sie hier: https://web.archive.org/web/20141121094204/https://cocoadev.com/HowToPipeCommandsWithNSTask
quelle
NSMutableData *data = [NSMutableData dataWithCapacity:512];
. Dannwhile ([task isRunning]) { [data appendData:[file readDataToEndOfFile]]; }
. Und ich "glaube", dass Sie[data appendData:[file readDataToEndOfFile]];
nach dem Beenden der while-Schleife noch eine haben sollten .task.standardError = pipe;
Kents Artikel brachte mich auf eine neue Idee. Diese runCommand-Methode benötigt keine Skriptdatei, sondern führt nur einen Befehl in einer Zeile aus:
Sie können diese Methode folgendermaßen verwenden:
quelle
im Geiste des Teilens ... ist dies eine Methode, die ich häufig verwende, um Shell-Skripte auszuführen. Sie können Ihrem Produktpaket ein Skript hinzufügen (in der Kopierphase des Builds) und das Skript dann zur Laufzeit lesen und ausführen lassen. Hinweis: Dieser Code sucht nach dem Skript im Unterpfad privateFrameworks. Warnung: Dies könnte ein Sicherheitsrisiko für bereitgestellte Produkte darstellen. Für unsere interne Entwicklung ist es jedoch eine einfache Möglichkeit, einfache Dinge (z. B. den Host, auf den synchronisiert werden soll ...) anzupassen, ohne die Anwendung neu zu kompilieren, sondern nur die zu bearbeiten Shell-Skript im Bundle.
Bearbeiten: Enthaltene Korrektur für NSLog-Problem
Wenn Sie NSTask verwenden, um ein Befehlszeilenprogramm über Bash auszuführen, müssen Sie diese magische Zeile einfügen, damit NSLog funktioniert:
Im Zusammenhang:
Eine Erklärung finden Sie hier: http://www.cocoadev.com/index.pl?NSTask
quelle
So geht's in Swift
Dies basiert auf der obigen Objective-C-Antwort von inkit. Er schrieb es als Kategorie auf
NSString
- Für Swift wird es eine Erweiterung vonString
.Erweiterung String.runAsCommand () -> String
Verwendung:
oder nur:
Beispiel:
Beachten Sie, dass das
Process
ausgelesene ErgebnisPipe
einNSString
Objekt ist. Es kann eine Fehlerzeichenfolge sein und es kann auch eine leere Zeichenfolge sein, aber es sollte immer eine seinNSString
.Solange es nicht Null ist, kann das Ergebnis als Swift gewertet
String
und zurückgegeben werden.Wenn aus irgendeinem Grund überhaupt nichts
NSString
aus den Dateidaten initialisiert werden kann, gibt die Funktion eine Fehlermeldung zurück. Die Funktion hätte geschrieben werden können, um ein optionales Element zurückzugebenString?
, aber das wäre umständlich zu verwenden und würde keinen nützlichen Zweck erfüllen, da dies so unwahrscheinlich ist.quelle
Ziel-C (siehe unten für Swift)
Der Code in der oberen Antwort wurde bereinigt, um ihn lesbarer und weniger redundant zu machen. Außerdem wurden die Vorteile der einzeiligen Methode hinzugefügt und wurde zu einer NSString-Kategorie
Implementierung:
Verwendung:
Und wenn Sie Probleme mit der Ausgabecodierung haben:
Ich hoffe, es ist für Sie genauso nützlich wie für die Zukunft von mir. (Hallo Du!)
Swift 4
Hier ist ein Swift Beispiel macht Verwendung von
Pipe
,Process
undString
Verwendung:
quelle
Fork , Exec und Wait sollten funktionieren, wenn Sie nicht wirklich nach einem Objective-C-spezifischen Weg suchen.
fork
Erstellt eine Kopie des aktuell ausgeführten Programms,exec
ersetzt das aktuell ausgeführte Programm durch ein neues undwait
wartet, bis der Unterprozess beendet ist. Zum Beispiel (ohne Fehlerprüfung):Es gibt auch ein System , das den Befehl so ausführt, als hätten Sie ihn über die Befehlszeile der Shell eingegeben. Es ist einfacher, aber Sie haben weniger Kontrolle über die Situation.
Ich gehe davon aus, dass Sie an einer Mac-Anwendung arbeiten. Die Links beziehen sich also auf die Apple-Dokumentation für diese Funktionen, aber sie sind alle vorhanden
POSIX
. Sie sollten sie daher auf jedem POSIX-kompatiblen System verwenden.quelle
Es gibt auch ein gutes altes POSIX- System ("echo -en '\ 007'");
quelle
Incorrect NSStringEncoding value 0x0000 detected. Assuming NSStringEncodingASCII. Will stop this compatibility mapping behavior in the near future.
Ich habe diese "C" -Funktion geschrieben, weil sie
NSTask
widerlich ist.oh, und um vollständig / eindeutig zu sein ...
Jahre später
C
ist es für mich immer noch ein verwirrendes Durcheinander ... und mit wenig Vertrauen in meine Fähigkeit, meine oben genannten groben Mängel zu korrigieren - der einzige Olivenzweig, den ich anbiete, ist eine rezhuzhed Version von @ inkets Antwort , die für meinen Kollegen kaum Knochen enthält Puristen / Ausführlichkeitshasser ...quelle
Custos Mortem sagte:
Bei blockierenden / nicht blockierenden Anrufproblemen
NSTask
lesen Sie bitte Folgendes:Der Quellcode von asynctask.m ist bei GitHub verfügbar .
quelle
Zusätzlich zu den oben genannten hervorragenden Antworten verwende ich den folgenden Code, um die Ausgabe des Befehls im Hintergrund zu verarbeiten und den Blockierungsmechanismus von zu vermeiden
[file readDataToEndOfFile]
.quelle
Oder da Ziel C nur C mit einer OO-Schicht darüber ist, können Sie die Posix-Gegenstücke verwenden:
Sie sind in der Header-Datei unistd.h enthalten.
quelle
Wenn für den Terminal-Befehl Administratorrechte (auch bekannt als Administratorrechte
sudo
) erforderlich sind , verwenden SieAuthorizationExecuteWithPrivileges
stattdessen. Im Folgenden wird eine Datei mit dem Namen "com.stackoverflow.test" erstellt. Dies ist das Stammverzeichnis "/ System / Library / Caches".quelle