shell 脚本如何知道它是在 shell 的 CLI 上调用的?

shell 脚本如何知道它是在 shell 的 CLI 上调用的?

我想实现一个zsh脚本,其行为取决于是否直接在 shell 的 CLI 上调用。

我一开始以为脚本可以通过查找 的i值来做到这一点$-,但我错了。

事实上,当我从命令行运行下面的脚本时

#!/bin/zsh
printf -- '%s\n' "$-"

...我得到的输出不包括i1

我的 shell 脚本还有其他方法可以找出这些信息吗?

注意:zsh虽然我现在正在写剧本,但我也想知道bash剧本的答案是什么。如果答案取决于OS,我主要对 Linux 和 Darwin 感兴趣。


1569X如果有人想知道的话,脚本的输出是。

答案1

$-包含i何时 shell 本身是交互式 shell、何时发出提示、允许您在终端上输入和编辑命令行、进行作业控制等。

脚本通常由非交互式 shell 解释。如果您将脚本调用为./the-scriptzsh ./the-script,则该zsh实例不是交互式的。交互式 shell 解释脚本的唯一时间是当您告诉交互式 shell 使用source ./the-script或 之类的内容解释其中的代码时eval "$(<the-script)"

在这里,在我看来,您似乎更想知道脚本是否是从终端内调用的,就像您想知道用户是否可以通过终端与其进行交互一样。

[/命令test(内置于 zsh 和 bash 以及大多数其他类似 Bourne 的 shell 中,但也应该作为 POSIX 系统上的独立命令存在)可以通过其-t运算符告诉您。该-t运算符采用一个数字参数,它是文件描述符。

[ -t 0 ]或者test -t 0如果文件描述符 0 在终端设备上打开,则返回 true。文件描述符0是标准输入, 1 是标准输出, 2 是标准误,其他所有 fds 均不具有任何保留的特殊含义。

所以在你的脚本中,你可以这样做:

if [ -t 0 ]; then
  echo "I (this script) am taking input from a terminal, so likely from a user"
fi

if [ -t 1 ]; then
  echo "My output goes to a terminal device, so will likely be seen by a user"
  [ -t 2 ] && echo errors also go there.
fi

如果您想检查脚本是否从终端会话中运行,即使其输入和/或输出可能被重定向到终端设备之外的其他文件,您可以检查是否有终端附加到脚本的会话,例如:

if { true <> /dev/tty; } 2> /dev/null; then
  echo "there's a terminal device attached to my session"
fi

如果你想知道它是什么终端设备:

tty_on_stdin=$(tty)
tty_on_stderr=$(tty <&2)
{ tty_on_stdout=$(tty <&3); } 3>&1

(看本次后续问答与 fd 跳舞的原因 3)。

controlling_tty=$(LC_ALL=C ps -o tty= -p "$$")
[ "$controlling_tty" = '?' ] || controlling_tty=/dev/$controlling_tty

¹ 在早期test/[实现中,该参数是可选的并且[ -t ]是 的缩写[ -t 1 ]。 POSIX 不再允许这样[ "$var" ]做,因为这与[ -n "$var" ].尽管如此,你会发现ksh93仍然检查 stdout 是否转到 tty,[ -t ]尽管只有当-t是字面量时;var=-t; [ "$var" ]即使 stdout 不在终端上也返回 true。

相关内容