我想实现一个zsh
脚本,其行为取决于是否直接在 shell 的 CLI 上调用。
我一开始以为脚本可以通过查找 的i
值来做到这一点$-
,但我错了。
事实上,当我从命令行运行下面的脚本时
#!/bin/zsh
printf -- '%s\n' "$-"
...我得到的输出不包括i
1。
我的 shell 脚本还有其他方法可以找出这些信息吗?
注意:zsh
虽然我现在正在写剧本,但我也想知道bash
剧本的答案是什么。如果答案取决于OS
,我主要对 Linux 和 Darwin 感兴趣。
1569X
如果有人想知道的话,脚本的输出是。
答案1
$-
包含i
何时 shell 本身是交互式 shell、何时发出提示、允许您在终端上输入和编辑命令行、进行作业控制等。
脚本通常由非交互式 shell 解释。如果您将脚本调用为./the-script
或zsh ./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。