#c #macos #terminal #iterm2
#c #macos #терминал #iterm2
Вопрос:
Я ищу общий и безопасный способ запуска строки скрипта в терминалах. В stack exchange есть десятки вопросов и ответов, Но все они не могут правильно разделять или экранировать поля, не глобализировать, заключать в кавычки и т. Д., Поскольку большинство из них передают строку через несколько уровней сценариев (оболочки, osascript).
Мне это нужно в приложении на C , поэтому objc / cocoa также является опцией. Любое решение, которое выполняет эту работу, является хорошим решением. Наиболее близкими на данный момент являются командные файлы для Terminal.app, но он выводит путь к командному файлу в первой строке, а также работает только для Terminal.app.
Комментарии:
1. Часть вашей проблемы здесь заключается в том, что вам нужна оболочка для запуска. Вы не просто пытаетесь запустить исполняемые файлы с переданными аргументами, вы пытаетесь фактически интерпретировать другой язык. Для этого вам понадобится что-то вроде Terminal.app , XQuartz.app и т. Д., Если вы не хотите реализовать свою собственную оболочку на C или включить исходный код из оболочки с открытым исходным кодом (например, оболочки Bourne-Again ) в свой проект. Но в нынешнем виде этот вопрос кажется слишком широким.
2. Возможно, я был неясен. Я полностью хочу, чтобы оболочка интерпретировала то, что я отправляю. Проблема всех решений заключается в том, что строка не пересылается идеально.
3. Итак, вы хотите открыть приложение терминала Mac OS и запустить какой-нибудь скрипт bash построчно в пользовательском интерфейсе? Похоже, вы не хотели зависеть от Terminal.app из вашего вопроса.
4. Может быть, я просто не понимаю вашего вопроса, но, возможно, простое
std::system
— это то, что вы ищете?5. @scohe001 да. (хотя не уверен, что вы подразумеваете под построчно). «Возьмите строку и запустите ее в терминале, как если бы я ввел ее самостоятельно».
Ответ №1:
Это немного грубо по краям, но это сделает то, что вы хотите.
Как это работает?
Поскольку вы хотите что-то делать в пользовательском интерфейсе Mac, самым простым ответом будет Applescript. Эта программа создаст файл Applescript по адресу /tmp/terminal_runner.scpt
. Затем он запустит скрипт с osascript
помощью прямого вызова исполняемого файла при /usr/bin/osascript
использовании execv
.
Поскольку execv
это C-код, все немного запутано. Это также предполагает, что строка cmd
, которую вы запускаете, правильно экранирована, чтобы хорошо вписаться в сценарий Applescript.
#include <iostream>
#include <string>
#include <fstream>
#include <cstring>
#include <unistd.h>
#include <errno.h>
void run_cmd_(std::string cmd) {
const std::string executable = "osascript";
const std::string tmp_script_loc = "/tmp/terminal_runner.scpt";
std::ofstream fhand(tmp_script_loc);
fhand << "tell application "Terminal"" << std::endl
<< "activate" << std::endl
<< "if (exists window 1) and not busy of window 1 then" << std::endl
// Assumes cmd is nice and escaped
// vvv
<< "do script "" << cmd << "" in window 1" << std::endl
<< "else" << std::endl
// vvv
<< "do script "" << cmd << """ << std::endl
<< "end if" << std::endl
<< "end tell";
fhand.close();
char **argv = new char*[3];
argv[0] = new char[executable.size() 1];
std::strcpy(argv[0], executable.c_str());
argv[1] = new char[tmp_script_loc.size() 1];
std::strcpy(argv[1], tmp_script_loc.c_str());
argv[2] = NULL;
execv("/usr/bin/osascript", argv);
}
int run_cmd(std::string cmd) {
int pid = fork();
if(pid == -1) {
perror("fork fail");
return -1;
} else if(pid == 0) {
run_cmd_(cmd);
} else {
int status;
if(waitpid(pid, amp;status, WUNTRACED) == -1) {
perror("Error running command");
return -1;
}
return status;
}
return 0;
}
int main() {
std::string bash_cmd = "echo 'THIS IS A TEST'";
int ret = run_cmd(bash_cmd);
if(ret != 0) {
perror("Oh dear...");
}
}
Комментарии:
1. Может
bash_cmd
содержать двойные кавычки?2. @Phil да, но они должны быть экранированы. ie
bash_cmd = "echo \"example\"";