¿Cómo puedo ejecutar un comando de terminal (como grep
) desde mi aplicación Objective-C Cocoa?
objective-c
cocoa
macos
perdido en el transito
fuente
fuente
/usr/bin
dondegrep
vive.Respuestas:
Puedes usar
NSTask
. Aquí hay un ejemplo que se ejecutaría '/usr/bin/grep foo bar.txt
'.NSPipe
yNSFileHandle
se utilizan para redirigir la salida estándar de la tarea.Para obtener información más detallada sobre cómo interactuar con el sistema operativo desde su aplicación Objective-C, puede ver este documento en el Centro de desarrollo de Apple: interacción con el sistema operativo .
Editar: Solución incluida para el problema NSLog
Si está utilizando NSTask para ejecutar una utilidad de línea de comandos a través de bash, entonces debe incluir esta línea mágica para mantener el NSLog funcionando:
Una explicación está aquí: https://web.archive.org/web/20141121094204/https://cocoadev.com/HowToPipeCommandsWithNSTask
fuente
NSMutableData *data = [NSMutableData dataWithCapacity:512];
. A continuación,while ([task isRunning]) { [data appendData:[file readDataToEndOfFile]]; }
. Y "creo" que debería tener uno más[data appendData:[file readDataToEndOfFile]];
después de las salidas del bucle while.task.standardError = pipe;
El artículo de Kent me dio una nueva idea. Este método runCommand no necesita un archivo de script, solo ejecuta un comando por una línea:
Puedes usar este método así:
fuente
en el espíritu de compartir ... este es un método que uso con frecuencia para ejecutar scripts de shell. puede agregar un script a su paquete de productos (en la fase de copia de la compilación) y luego hacer que el script se lea y se ejecute en tiempo de ejecución. nota: este código busca el script en la subruta privateFrameworks. advertencia: esto podría ser un riesgo de seguridad para los productos implementados, pero para nuestro desarrollo interno es una manera fácil de personalizar cosas simples (como qué host rsync para ...) sin volver a compilar la aplicación, sino simplemente editar el script de shell en el paquete.
Editar: Solución incluida para el problema NSLog
Si está utilizando NSTask para ejecutar una utilidad de línea de comandos a través de bash, entonces debe incluir esta línea mágica para mantener el NSLog funcionando:
En contexto:
Una explicación está aquí: http://www.cocoadev.com/index.pl?NSTask
fuente
Aquí se explica cómo hacerlo en Swift
Esto se basa en la respuesta Objective-C anterior de inkit. Lo escribió como una categoría en
NSString
- Para Swift, se convierte en una extensión deString
.extensión String.runAsCommand () -> String
Uso:
o solo:
Ejemplo:
Tenga en cuenta que el
Process
resultado que se lee delPipe
es unNSString
objeto. Puede ser una cadena de error y también puede ser una cadena vacía, pero siempre debe ser unaNSString
.Por lo tanto, siempre que no sea nulo, el resultado puede lanzarse como un Swift
String
y volver.Si por alguna razón no
NSString
se puede inicializar nada a partir de los datos del archivo, la función devuelve un mensaje de error. La función podría haberse escrito para devolver un opcionalString?
, pero sería difícil de usar y no tendría un propósito útil porque es muy poco probable que esto ocurra.fuente
Objetivo-C (ver abajo para Swift)
Limpié el código en la respuesta superior para hacerlo más legible, menos redundante, agregó los beneficios del método de una línea y lo convirtió en una categoría NSString
Implementación:
Uso:
Y si tiene problemas con la codificación de salida:
Espero que sea tan útil para ti como lo será para mi futuro. (¡Hola!)
Swift 4
He aquí un ejemplo Swift haciendo uso de
Pipe
,Process
yString
Uso:
fuente
fork , exec y wait deberían funcionar, si realmente no estás buscando una forma específica de Objective-C.
fork
crea una copia del programa actualmente en ejecución,exec
reemplaza el programa actualmente en ejecución por uno nuevo ywait
espera a que salga el subproceso. Por ejemplo (sin verificación de errores):También hay un sistema , que ejecuta el comando como si lo hubiera escrito desde la línea de comandos del shell. Es más simple, pero tienes menos control sobre la situación.
Supongo que está trabajando en una aplicación de Mac, por lo que los enlaces son a la documentación de Apple para estas funciones, pero son todas
POSIX
, por lo que debe usarlas en cualquier sistema compatible con POSIX.fuente
También hay un buen sistema POSIX antiguo ("echo -en '\ 007'");
fuente
Incorrect NSStringEncoding value 0x0000 detected. Assuming NSStringEncodingASCII. Will stop this compatibility mapping behavior in the near future.
Escribí esta función "C", porque
NSTask
es desagradable.oh, y en aras de ser completo / inequívoco ...
Años más tarde,
C
sigue siendo un desastre desconcertante para mí ... y con poca fe en mi capacidad para corregir mis graves deficiencias anteriores: la única rama de olivo que ofrezco es una versión rezhuzhed de la respuesta de @inket que es más que huesos , para mi compañero puristas / detestadores de verbosidad ...fuente
El Custodio Mortem dijo:
Para problemas de bloqueo / no bloqueo de llamadas con respecto a
NSTask
leer a continuación:El código fuente de asynctask.m está disponible en GitHub .
fuente
Además de las varias respuestas excelentes anteriores, utilizo el siguiente código para procesar la salida del comando en segundo plano y evitar el mecanismo de bloqueo de
[file readDataToEndOfFile]
.fuente
O como el objetivo C es solo C con alguna capa OO en la parte superior, puede usar las contrapartidas posix:
Se incluyen desde el archivo de encabezado unistd.h.
fuente
Si el comando Terminal requiere privilegio de administrador (también conocido como
sudo
), úseloAuthorizationExecuteWithPrivileges
en su lugar. Lo siguiente creará un archivo llamado "com.stackoverflow.test" es el directorio raíz "/ System / Library / Caches".fuente