tty 是一个简单而实用的小工具,用于打印当前标准输入所连接的终端设备文件名。在编写 Shell 脚本时,tty 常被用来判断脚本是否运行在交互式终端中,从而决定是否输出彩色文本或交互式提示。
tty 的名字来源于 Teletypewriter(电传打字机),这是早期 Unix 系统用于交互的物理终端设备。时至今日,我们仍然用 tty 来指代终端设备。
语法
tty [选项]
常用选项
| 选项 | 含义 |
|---|---|
-s
|
静默模式,不输出任何内容,仅通过退出码反映结果 |
--help
|
显示帮助信息 |
--version
|
显示版本信息 |
退出码含义
tty 的退出码是脚本判断的关键:
| 退出码 | 含义 |
|---|---|
| 0 | 标准输入是一个终端(TTY) |
| 1 | 标准输入不是终端 |
| 2 | 参数错误 |
| 3 | 发生写错误 |
基础用法
1. 查看当前终端设备
# 在本地终端执行 tty # 输出示例: /dev/pts/0 # 在 SSH 会话中执行 tty # 输出示例: /dev/pts/3 # 在虚拟控制台 (Ctrl+Alt+F2) 中执行 tty # 输出示例: /dev/tty2
2. 静默模式 - 仅检查退出码
# 静默检测是否在终端中运行 tty -s echo $? # 输出: 0(在终端中)或 1(不在终端中) # 在 cron 任务或管道中检测 echo "test" | tty -s echo $? # 输出: 1(管道不是终端)
3. 脚本中判断交互式环境
#!/bin/bash
# 检查是否在终端中运行,决定是否启用彩色输出
if tty -s; then
RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m' # No Color
echo -e "${GREEN}[INFO]${NC} 检测到交互式终端: $(tty)"
echo -e "${RED}[WARN]${NC} 请确认操作后继续..."
read -p "是否继续? (y/n) " confirm
else
echo "[INFO] 非交互模式运行,跳过确认步骤"
fi
4. 检查脚本是否被管道调用
#!/bin/bash
# 判断当前标准输入是否来自终端
if [ -t 0 ]; then
echo "脚本运行在交互式终端中"
else
echo "脚本通过管道或重定向接收输入"
echo "当前终端: $(tty 2>/dev/null || echo '无终端')"
fi
5. 多个终端场景对比
# 场景一: 直接登录 $ tty /dev/tty1 # 场景二: screen/tmux 会话中 $ tty /dev/pts/1 # 场景三: 通过 SSH 远程登录 $ ssh user@remote 'tty' /dev/pts/0 # 场景四: 在子 shell 中 $ (tty; tty) /dev/pts/1 /dev/pts/1 # 注意: 子 shell 继承父进程的终端 # 场景五: nohup 后台任务 $ nohup tty & $ cat nohup.out not a tty
6. 获取所有打开终端的进程
# 列出所有打开终端设备的进程及其终端
ps aux | awk '$7 ~ /^pts\// || $7 ~ /^tty/ {print $2, $7, $11}' | sort -k2
# 查看当前终端被哪些进程占用
ps -t $(tty)
# 统计系统中活跃的伪终端数量
ps aux | awk '$7 ~ /^pts\// {print $7}' | sort -u | wc -l
7. 在日志系统中标记终端来源
#!/bin/bash # 记录操作来源终端 LOG_FILE="/var/log/custom_ops.log" CURRENT_TTY=$(tty 2>/dev/null || echo "non-tty") TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S') echo "[$TIMESTAMP] [TTY:$CURRENT_TTY] [USER:$USER] 执行操作: $@" >> "$LOG_FILE" # 使用方式 # ./log_script.sh "备份数据库完成" # 日志内容: [2026-06-14 10:30:00] [TTY:/dev/pts/2] [USER:root] 执行操作: 备份数据库完成
8. 实现简单的终端消息定向发送
#!/bin/bash
# 向指定终端发送消息(需要写权限)
TARGET_TTY="/dev/pts/1"
if [ -w "$TARGET_TTY" ]; then
echo "==重要通知==" > "$TARGET_TTY"
echo "来自 $(whoami) 的消息 (终端: $(tty))" > "$TARGET_TTY"
echo "服务器将在 10 分钟后进行维护" > "$TARGET_TTY"
else
echo "错误: 没有向 $TARGET_TTY 写入的权限"
echo "请检查目标终端是否存在且可写"
fi
与相关命令的对比
tty 输出设备名,who 列出登录用户及其终端,w 还显示正在运行的命令。它们从不同角度回答"谁在用哪个终端"这个问题。
# tty - 仅当前终端的设备名 tty # /dev/pts/0 # who - 所有登录用户及其终端 who # alice pts/0 2026-06-14 10:00 # bob pts/1 2026-06-14 10:05 # w - 更详细,含正在执行的命令 w # 10:10:00 up 5 days, 2:30, 2 users, load average: 0.00, 0.01, 0.05 # USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT # alice pts/0 192.168.1.100 10:00 2:00 0.05s 0.01s bash # bob pts/1 192.168.1.101 10:05 0.00s 0.02s 0.00s w # [ -t FD ] - 测试文件描述符是否指向终端 [ -t 0 ] && echo "stdin 是终端" [ -t 1 ] && echo "stdout 是终端"
编程语言中的等价操作
# Python - 检测是否为终端
import sys
if sys.stdin.isatty():
print(f"终端设备: {os.ttyname(0)}")
else:
print("非终端输入")
# C 语言
#include <stdio.h>
#include <unistd.h>
int main() {
if (isatty(0)) {
printf("终端: %s\n", ttyname(0));
} else {
printf("非终端\n");
}
return 0;
}
常见问题
Q: 为什么 SSH 会话中 tty 显示 /dev/pts/N?
A: pts 是伪终端从设备(pseudo terminal slave),由 SSH 守护进程动态分配。每个 SSH 连接都会获得一个独立的 pts 设备号,这使得多个远程会话可以互不干扰地运行。
Q: cron 任务中 tty 返回什么?
A: cron 任务没有控制终端,因此 tty 会输出 not a tty 并以退出码 1 结束。这就是为什么交互式命令在 cron 中通常需要特殊处理。
Q: 如何强制为进程分配一个终端?
A: 使用 script 命令或 expect 工具可以创建伪终端环境,让那些依赖终端的程序正常运行。













