检测是否从命令行(终端)启动了macOS应用

时间:2018-10-07 10:53:12

标签: macos cmdline-args

我有一个GUI macOS应用程序,也可以从终端启动,带有可选的命令行参数。

使用参数启动时,我希望以“ cmdline”模式运行该应用程序,在该模式下,我不显示任何用户界面,而仅通过stdin + stdout进行通信。

我可以这样检测cmdline模式:

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

(arg 0始终是可执行文件的路径,因此任何其他args都将手动传递给args)。

现在,这是个大问题:

如果用户从终端调用我的应用程序而没有参数(通过在 Contents / MacOS 中调用应用程序的可执行文件,即不通过open cmd),我也喜欢进入cmdline模式。如何检测到这个?

注意:较旧的OS X版本确实传递了“ -psn ...”参数,该参数不存在时可用于检测来自cmdline的启动,但是最新的macOS版本似乎在启动时不再传递该参数。 Finder中的应用程序,因此我无法再将其用于检测。

更新

我意识到,通过检查某些环境变量的存在,我几乎可以正确解决此问题:

TERMPWD仅在从终端启动应用程序时设置,而不是在Finder中启动。

但是,我还想知道直接启动(可在Contents / MacOS dir中执行)与使用open命令启动之间的区别,因为我认为打开cmd等同于打开应用程序通过Finder或通过启动服务从另一个应用程序进行。

简而言之,问题还可能是:检测应用程序是否由启动服务启动


为进行记录,以下是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

但是,没有通过启动服务启动的应用程序具有唯一的环境值(例如,在Finder中双击时)。

1 个答案:

答案 0 :(得分:1)

如果您想知道哪个进程执行了程序,可以使用getppid()获取父进程ID,然后检查该进程以确定您是由交互式Shell进程还是Finder执行,或者launchctl等。

/sbin/launchd是PID 1-如果进程的父PID为1,则表示您是通过启动执行的。

否则,您是由另一个进程执行的-可能是交互式外壳程序,或者是另一个进程的子进程。您可以使用KERN_PROCARGS syscall with sysctl()通过其PID获得进程名称。

您可能还需要考虑使用isatty(STDIN):交互式shell具有TTY,非交互式shell具有其他功能,