Exécuter une commande de terminal à partir d'un Cacao app
Comment puis-je exécuter une commande de terminal (comme grep
) de mon Objective-C, Cocoa application?
- Je suis tout à fait d'énoncer une évidence: avec le bac à sable, vous ne pouvez pas simplement aller démarrer des applications qui ne sont pas dans votre bac à sable ET ils doivent être signés par vous pour permettre à ce
- ce n'est pas vrai du tout, du moins pas dans macOS. Un bac à sable macOS application peut exécuter les binaires dans des endroits tels que
/usr/bin
oùgrep
vie. - Pas de. Merci de me prouver le contraire 😉 sur les ist nstask ne s'exécutent pas dans votre bac à sable.
Vous devez vous connecter pour publier un commentaire.
Vous pouvez utiliser
NSTask
. Voici un exemple qui irait à l' '/usr/bin/grep foo bar.txt
'.NSPipe
etNSFileHandle
sont utilisés pour rediriger la sortie standard de la tâche.Pour de plus amples informations sur l'interaction avec le système d'exploitation à partir de votre Objectif-C application, vous pouvez voir ce document sur l'Apple Centre de Développement de l': L'interaction avec le Système d'Exploitation.
Edit: Inclus correctif pour NSLog problème
Si vous utilisez NSTask pour exécuter un utilitaire de ligne de commande via bash, vous devez inclure cette ligne magique pour garder NSLog de travail:
Une explication est ici: https://web.archive.org/web/20141121094204/https://cocoadev.com/HowToPipeCommandsWithNSTask
NSMutableData *data = [NSMutableData dataWithCapacity:512];
. Ensuite,while ([task isRunning]) { [data appendData:[file readDataToEndOfFile]]; }
. Et je "crois" vous devez disposer d'un plus[data appendData:[file readDataToEndOfFile]];
après le temps de la boucle de sortie.task.standardError = pipe;
dans l'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 lot de produits (dans la phase de copie de la construction) et puis
le script de lire et d'exécuter au moment de l'exécution. remarque: ce code est pour le script dans le privateFrameworks sous-chemin.
avertissement: ce pourrait être un risque de sécurité pour les produits déployés, mais pour notre propre développement, c'est un moyen facile de personnaliser les choses simples (comme l'hôte de rsync pour...) sans re-compilation de l'application, mais juste éditer le script shell dans le bundle.
Edit: Inclus correctif pour NSLog problème
Si vous utilisez NSTask pour exécuter un utilitaire de ligne de commande via bash, vous devez inclure cette ligne magique pour garder NSLog de travail:
En contexte:
Une explication est ici: http://www.cocoadev.com/index.pl?NSTask
kent article m'a donné une idée nouvelle. cette méthode runCommand n'a pas besoin d'un fichier de script, juste exécute une commande en ligne:
Vous pouvez utiliser cette méthode comme ceci:
Voici comment le faire en Swift
Ceci est basé sur inkit de l'Objective-C réponse ci-dessus. Il l'a écrit comme un catégorie sur
NSString
—Pour Swift, il devient un extension de
String
.extension String.runAsCommand() -> String
Utilisation:
ou tout simplement:
Exemple:
Note le
Process
résultat que de les lire à partir de laPipe
est unNSString
objet. Il pourrait être une erreur de chaîne et il peut aussi être une chaîne vide, mais il devrait toujours être unNSString
.Donc, tant qu'il n'est pas nul, le résultat peut lancer comme rapide
String
et retourné.Si pour une raison quelconque ne
NSString
peut être initialisé à partir du fichier de données, la fonction renvoie un message d'erreur. La fonction pourrait avoir été écrit pour revenir une optionString?
, mais ce serait difficile à utiliser et ne pas servir à des fins utiles, parce que c'est tellement improbable que cela se produise.Objective-C (voir ci-dessous pour Swift)
Nettoyé le code en haut à répondre à la rendre plus lisible, moins redondant, ajouté les avantages de une méthode de ligne de et dans un NSString catégorie
Mise en œuvre:
Utilisation:
Et si vous rencontrez des problèmes avec l'encodage de sortie:
Espère que c'est aussi utile à vous comme il le sera à l'avenir moi. (Hi, vous!)
Swift 4
Voici un rapide exemple, l'utilisation de
Pipe
,Process
, etString
Utilisation:
fourche, exec, et attendre devrait fonctionner, si vous n'êtes pas vraiment à la recherche d'un Objectif-C de manière spécifique.
fork
crée une copie du programme en cours d'exécution,exec
remplace le programme en cours d'exécution avec un nouveau, etwait
attend pour le sous-processus de sortie. Par exemple (sans contrôle d'erreur):Il y a aussi système, qui exécute la commande que si vous avez tapé à partir de la ligne de commande du shell. C'est plus simple, mais vous avez moins de contrôle sur la situation.
Je suis en supposant que vous travaillez sur une application Mac, de sorte que les liens sont à la documentation d'Apple pour ces fonctions, mais ils sont tous
POSIX
, de sorte que vous devriez être à utiliser sur n'importe quel conforme à POSIX système.Il y a aussi la bonne vieille POSIX système("echo-en "\007'");
Incorrect NSStringEncoding value 0x0000 detected. Assuming NSStringEncodingASCII. Will stop this compatibility mapping behavior in the near future.
J'ai écrit cette fonction "C", parce que
NSTask
est désagréable..oh, et par souci d'être complet /sans ambiguïté...
Ans plus tard,
C
est toujours un incroyable gâchis, pour moi.. et avec un peu de foi en ma capacité à corriger mon brut lacunes au - dessus de la seule branche d'olivier que je propose est un rezhuzhed version de @inket de la réponse qui est plus strict des os, pour mes collègues puristes /verbosité-haters...Custos Mortem dit:
Pour le blocage/appel non bloquant les questions concernant
NSTask
lire ci-dessous:Code Source de asynctask.m est disponible à GitHub.
Ou étant donné que l'Objectif C est juste C avec quelques OO couche sur le dessus, vous pouvez utiliser la posix conterparts:
Ils sont inclus à partir de unistd.h fichier d'en-tête.
Si le Terminal de commande nécessite des Privilèges d'Administrateur (aka
sudo
), l'utilisationAuthorizationExecuteWithPrivileges
à la place.Le suivant va créer un fichier nommé "com.stackoverflow.test" est le répertoire racine "/System/Library/Caches".
Outre plusieurs excellentes réponses ci-dessus, j'utilise le code suivant pour traiter la sortie de la commande en arrière-plan et d'éviter le mécanisme de blocage de
[file readDataToEndOfFile]
.