Определить, было ли запущено приложение macOS из командной строки (Терминал)

У меня есть приложение MacOS с графическим интерфейсом, которое также может запускаться из терминала с необязательными аргументами командной строки.

При запуске с аргументами мне нравится запускать приложение в режиме "cmdline", где я не отображаю никакой интерфейс, а вместо этого общаюсь только через stdin + stdout.

Я могу обнаружить этот режим cmdline следующим образом:

BOOL cmdMode = NSProcessInfo.processInfo.arguments.count > 1;

(аргумент 0 всегда является путем к исполняемому файлу, поэтому любые другие аргументы будут передаваться аргументами вручную).

Теперь вот большой вопрос:

Если пользователь вызывает мое приложение без аргументов из Терминала (вызывая исполняемый файл приложения в Contents/MacOS, т.е. не через open cmd), мне также нравится переходить в режим cmdline. Как мне это обнаружить?

Примечание. В более старых версиях OS X передавался аргумент "-psn ...", который, если он отсутствует, мог использоваться для обнаружения запуска из cmdline, но последние версии macOS, похоже, больше не передают этот аргумент при запуске приложений из Искатель, поэтому я не могу использовать это для обнаружения больше.

Обновить

Я понимаю, что могу почти правильно решить эту проблему, проверив наличие определенных переменных среды:

TERM а также PWD устанавливаются только при запуске приложения из терминала, но не из Finder.

Тем не менее, я также хотел бы иметь возможность отличить прямой запуск (исполняемый файл в каталоге Contents/MacOS) от запуска с open команда, поскольку я считаю open cmd эквивалентным открытию приложения через Finder или из другого приложения через Launch Services.

Короче говоря, вопрос также может быть: Определить, было ли приложение запущено с помощью Launch Services


Для записи, вот значения из environ(), Те, которые отмечены звездочкой, присутствуют только при вызове из Terminal.app, но не при запуске из Finder:

    __CF_USER_TEXT_ENCODING=0x1F5:0x0:0x0
*   _=/Applications/Myapp.app/Contents/MacOS/Myapp
    Apple_PubSub_Socket_Render=/private/tmp/com.apple.launchd.laVQnD7IXl/Render
    HOME=/Users/username
*   LANG=en_US.UTF-8
*   LC_ALL=en_US.UTF-8
*   LC_CTYPE=UTF-8
    LOGNAME=username
    PATH=/usr/local/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
*   PWD=/Users/username
    SHELL=/bin/bash
*   SHLVL=1
    SSH_AUTH_SOCK=/private/tmp/com.apple.launchd.KeHv8KNuuk/Listeners
*   TERM_PROGRAM_VERSION=388.1.2
*   TERM_PROGRAM=Apple_Terminal
*   TERM_SESSION_ID=EF2C59E6-D661-45BE-B7EF-7A0E71158C8D
*   TERM=xterm-color
    TMPDIR=/var/folders/hm/ycnxcbwx8xl1v7008k8wnpjh0000gn/T/
    USER=username
    XPC_FLAGS=0x0
    XPC_SERVICE_NAME=0

Однако отсутствуют дополнительные значения, уникальные для приложений, запускаемых с помощью Launch Services (например, при двойном щелчке в Finder).

1 ответ

Решение

Если вы хотите узнать, какой процесс выполнил вашу программу, вы можете использовать getppid() чтобы получить идентификатор родительского процесса, затем проверить этот процесс, чтобы определить, был ли он выполнен интерактивным процессом оболочки, или Finder, или launchctl, и т. д.

/sbin/launchd is PID 1 - если PID родительского процесса равен 1, вы были запущены launchd.

В противном случае вы были выполнены другим процессом - возможно, интерактивной оболочкой или как подпроцесс другого процесса. Вы можете использовать KERN_PROCARGS системный вызов сsysctl() чтобы получить имя процесса по его PID.

Вы также можете рассмотреть возможность использования isatty(STDIN) также: у интерактивных оболочек есть TTY, у неинтерактивных оболочек нет других процессов.

Другие вопросы по тегам