Comment puis-je exécuter une commande de terminal (comme grep
) à partir de mon application Objective-C Cocoa?
objective-c
cocoa
macos
lostInTransit
la source
la source
/usr/bin
endroit oùgrep
vit.Réponses:
Vous pouvez utiliser
NSTask
. Voici un exemple qui fonctionnerait '/usr/bin/grep foo bar.txt
'.NSPipe
etNSFileHandle
sont utilisés pour rediriger la sortie standard de la tâche.Pour plus d'informations sur l'interaction avec le système d'exploitation à partir de votre application Objective-C, vous pouvez voir ce document sur le Centre de développement d'Apple: Interagir avec le système d'exploitation .
Edit: correction incluse pour le problème NSLog
Si vous utilisez NSTask pour exécuter un utilitaire de ligne de commande via bash, vous devez inclure cette ligne magique pour que NSLog fonctionne:
Une explication est ici: https://web.archive.org/web/20141121094204/https://cocoadev.com/HowToPipeCommandsWithNSTask
la source
NSMutableData *data = [NSMutableData dataWithCapacity:512];
. Ensuite,while ([task isRunning]) { [data appendData:[file readDataToEndOfFile]]; }
. Et je "crois" que vous devriez en avoir un de plus[data appendData:[file readDataToEndOfFile]];
après la sortie de la boucle while.task.standardError = pipe;
L'article de Kent m'a donné une nouvelle idée. cette méthode runCommand n'a pas besoin d'un fichier de script, exécute simplement une commande par une ligne:
Vous pouvez utiliser cette méthode comme ceci:
la source
dans un esprit de partage ... c'est une méthode que j'utilise fréquemment pour exécuter des scripts shell. vous pouvez ajouter un script à votre bundle de produits (dans la phase de copie de la build), puis faire lire et exécuter le script au moment de l'exécution. remarque: ce code recherche le script dans le sous-chemin privateFrameworks. avertissement: cela pourrait être un risque pour la sécurité des produits déployés, mais pour notre développement en interne, c'est un moyen facile de personnaliser des choses simples (comme l'hôte à rsync ...) sans recompiler l'application, mais simplement éditer le script shell dans le bundle.
Edit: correction incluse pour le problème NSLog
Si vous utilisez NSTask pour exécuter un utilitaire de ligne de commande via bash, vous devez inclure cette ligne magique pour que NSLog fonctionne:
Dans le contexte:
Une explication est ici: http://www.cocoadev.com/index.pl?NSTask
la source
Voici comment le faire dans Swift
Ceci est basé sur la réponse Objective-C de inkit ci-dessus. Il l'a écrit comme une catégorie sur
NSString
- Pour Swift, cela devient une extension deString
.extension String.runAsCommand () -> String
Usage:
ou juste:
Exemple:
Notez le
Process
résultat tel qu'il est lu dansPipe
est unNSString
objet. Il peut s'agir d'une chaîne d'erreur et peut également être une chaîne vide, mais elle doit toujours être unNSString
.Donc, tant qu'il n'est pas nul, le résultat peut être converti en Swift
String
et renvoyé.Si, pour une raison quelconque, aucun ne
NSString
peut être initialisé à partir des données du fichier, la fonction renvoie un message d'erreur. La fonction aurait pu être écrite pour renvoyer une optionString?
, mais ce serait maladroit à utiliser et ne servirait à rien car il est peu probable que cela se produise.la source
Objectif-C (voir ci-dessous pour Swift)
Nettoyé le code dans la première réponse pour le rendre plus lisible, moins redondant, ajouté les avantages de la méthode à une ligne et transformé en une catégorie NSString
La mise en oeuvre:
Usage:
Et si vous rencontrez des problèmes avec l'encodage de sortie:
J'espère que c'est aussi utile pour vous que pour moi. (Salut toi!)
Swift 4
Voici un exemple de l' utilisation de la prise Swift
Pipe
,Process
etString
Usage:
la source
fork , exec et wait devraient fonctionner si vous ne cherchez pas vraiment une méthode spécifique à Objective-C.
fork
crée une copie du programme en cours d'exécution,exec
remplace le programme en cours d'exécution par un nouveau etwait
attend la fin du sous-processus. Par exemple (sans vérification d'erreur):Il y a aussi le système , qui exécute la commande comme si vous l'avez tapée à partir de la ligne de commande du shell. C'est plus simple, mais vous avez moins de contrôle sur la situation.
Je suppose que vous travaillez sur une application Mac, donc les liens sont vers la documentation d'Apple pour ces fonctions, mais ils sont tous
POSIX
, vous devriez donc les utiliser sur n'importe quel système compatible POSIX.la source
Il y a aussi un bon vieux système POSIX ("echo -en '\ 007'");
la source
Incorrect NSStringEncoding value 0x0000 detected. Assuming NSStringEncodingASCII. Will stop this compatibility mapping behavior in the near future.
J'ai écrit cette fonction "C", car elle
NSTask
est désagréable ..oh, et pour être complet / sans ambiguïté…
Des années plus tard,
C
c'est toujours un gâchis déconcertant, pour moi .. et avec peu de foi en ma capacité à corriger mes défauts grossiers ci-dessus - la seule branche d'olivier que j'offre est une version rezhuzhed de la réponse de @ inket qui est la plus fine des os , pour mon collègue puristes / haineux de la verbosité ...la source
Custos Mortem a déclaré:
Pour les problèmes d'appels bloquants / non bloquants concernant la
NSTask
lecture ci-dessous:Le code source de asynctask.m est disponible sur GitHub .
la source
En plus des nombreuses excellentes réponses ci-dessus, j'utilise le code suivant pour traiter la sortie de la commande en arrière-plan et éviter le mécanisme de blocage de
[file readDataToEndOfFile]
.la source
Ou puisque l'objectif C est juste C avec une couche OO sur le dessus, vous pouvez utiliser les contre-parties posix:
Ils sont inclus dans le fichier d'en-tête unistd.h.
la source
Si la commande Terminal Server requiert un privilège administrateur (aka
sudo
), utilisezAuthorizationExecuteWithPrivileges
plutôt. Ce qui suit va créer un fichier nommé "com.stackoverflow.test" qui est le répertoire racine "/ System / Library / Caches".la source