【问题标题】:How to run a commandline in a terminal (Terminal, iterm2, etc)如何在终端中运行命令行(终端、iterm2 等)
【发布时间】:2022-01-12 22:26:44
【问题描述】:

我正在寻找一种在终端中运行脚本字符串的通用且安全的方法。有几十个关于堆栈交换的问答,但所有都无法正确地进行字段分隔或转义,不要使用 glob、引用等,因为它们中的大多数都通过多个级别的脚本(shell、osascript )。

我在 C++ 应用程序中需要这个,所以 objc/cocoa 也是一个选项。任何可以完成工作的解决方案都是一个很好的解决方案。到目前为止最接近的是 Terminal.app 的命令文件,但它在第一行打印命令文件的路径,并且也仅适用于 Terminal.app。

【问题讨论】:

  • 这里的部分问题是您需要一个 shell 来运行。您不只是尝试使用传递的参数启动可执行文件,而是尝试实际解释另一种语言。为此,您将需要 Terminal.app、XQuartz.app 等,除非您愿意在 C++ 中实现自己的 shell 或在您的项目。但就目前而言,这个问题似乎太宽泛了。
  • 也许我不清楚。我完全想要一个 shell 来解释我发送的内容。所有解决方案的问题是字符串没有完美转发。
  • 那么您想打开 Mac OS 终端应用程序并在 UI 中逐行运行一些 bash 脚本吗?听起来您不想从您的问题中依赖 Terminal.app。
  • 也许我只是不明白你的问题,但也许简单的std::system 就是你要找的?
  • @scohe001 是的。 (虽然不确定你的意思是逐行)。 “获取一个字符串并在终端中运行它,就像我自己输入一样”。

标签: c++ macos terminal iterm2


【解决方案1】:

它的边缘有点粗糙,但这会做你想要的。

它是如何工作的?

既然您想在 Mac UI 中做事,最简单的答案就是 Applescript。该程序将在/tmp/terminal_runner.scpt 创建一个Applescript 文件。然后它将通过使用execv 直接调用/usr/bin/osascript 的可执行文件来使用osascript 运行脚本。

由于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, &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...");
    }
}

【讨论】:

  • bash_cmd 可以包含双引号吗?
  • @Phil 是的,但它们必须被转义。即bash_cmd = "echo \\\"example\\\"";
猜你喜欢
  • 2019-12-22
  • 2021-02-17
  • 2018-09-23
  • 2021-12-09
  • 2020-03-02
  • 2013-01-15
  • 1970-01-01
  • 1970-01-01
  • 2021-10-24
相关资源
最近更新 更多