You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在bash脚本中获取当前运行的终端模拟器?

问题描述

我正在开发一款类似neofetch的系统信息报告工具betterfetch,目前功能正常,但在bash环境下无法正确获取当前终端模拟器。

我尝试过以下命令:

readlink "/proc/$(cat /proc/$(echo $$)/stat|cut -d ' ' -f 4)/exe"
ps -o comm= -p $(ps -o ppid= -p $$)

这些命令直接在终端执行时能返回正确的终端模拟器,但放到bash脚本里只会返回bash或/usr/bin/bash。

以下是工具的完整代码:

#!/bin/sh

# yes. no logos. because why not?

# source the config file
if [ "$colorsoff" = "" ]; then
    colorsoff=0
fi

[ -e /etc/betterfetchrc ] && . /etc/betterfetchrc 2> /dev/null
[ -e ~/.betterfetchrc ] && . ~/.betterfetchrc 2> /dev/null

CURRENT_VERSION_FILE="/etc/betterfetch-version"  # Path to the file containing the current version
REMOTE_VERSION_URL="https://raw.githubusercontent.com/sctech-tr/betterfetch/main/betterfetch-version"

# Fetch the remote version from the URL
REMOTE_VERSION=$(curl -s $REMOTE_VERSION_URL)

# Read the current version from the version file
if [ -f "$CURRENT_VERSION_FILE" ]; then
  CURRENT_VERSION=$(cat "$CURRENT_VERSION_FILE")
else
  echo "error: current version file not found."
  exit 1
fi

# Compare the remote version with the current version
if [ "$REMOTE_VERSION" != "$CURRENT_VERSION" ]; then
  echo "betterfetch ($REMOTE_VERSION) is available! you are currently on version $CURRENT_VERSION."
  exit 0
fi



# the meat and potatoes, actual fetch

# only set these if they are not already set by the config file
[ -z "$os" ] && . /etc/os-release 2>/dev/null || export os="Unknown"
[ -z "$host" ] && host=$(cat /proc/sys/kernel/hostname)
[ -z "$kernel" ] && kernel=$(sed "s/version // ; s/ (.*//" /proc/version)
[ -z "$uptime" ] && uptime=$(uptime -p 2>/dev/null | sed "s/up //")
[ -z "$shell" ] && shell=$(printf "$SHELL" | sed "s/\/bin\///" | sed "s/\/usr//")
[ -z "$de" ] && de=$(echo $XDG_CURRENT_DESKTOP)
[ -z "$terminal" ] && terminal=$(readlink "/proc/$(cat /proc/$(echo $$)/stat|cut -d ' ' -f 4)/exe")

printf "$USER@$host\n"
printf "OS           $os\n"
printf "Kernel       $kernel\n"
printf "Uptime       $uptime\n"
printf "Shell        $shell\n"
printf "DE           $de\n"
printf "Terminal     $terminal\n"
if [ "$colorsoff" != 1 ]; then
    printf "\033[0;31m● \033[0;32m● \033[0;33m● \033[0;34m● \033[0;35m● \033[0;36m● \033[0;37m●\033[0m\n"
fi
解决方案

问题根源是脚本的进程父链:在bash中执行脚本时,脚本的直接父进程是bash,而bash的父进程才是终端模拟器。之前的命令只取了一级父进程,所以拿到的是bash而非终端。

你需要遍历进程树,直到找到符合终端特征的进程。可以用下面的方法替换原来的终端获取逻辑:

首先在脚本中添加这个函数:

# 遍历进程树查找终端模拟器
get_terminal() {
    local pid=$$
    while true; do
        local ppid=$(ps -o ppid= -p "$pid" | tr -d ' ')
        # 到达根进程(init/systemd)就停止
        if [ "$ppid" -eq 1 ]; then
            break
        fi
        local exe=$(readlink -f "/proc/$ppid/exe" 2>/dev/null)
        # 匹配常见终端模拟器,可根据需要扩展列表
        case "$exe" in
            */gnome-terminal|*/konsole|*/xterm|*/alacritty|*/kitty|*/terminator|*/rxvt|*/st|*/urxvt|*/wezterm|*/foot)
                echo "$(basename "$exe")"
                return 0
                ;;
        esac
        pid="$ppid"
    done
    # 找不到时返回环境变量TERM的值,或默认提示
    echo "${TERM:-Unknown Terminal}"
}

然后替换原来的terminal赋值行:

[ -z "$terminal" ] && terminal=$(get_terminal)

说明

  • 函数从当前脚本进程($$)开始,逐层向上遍历父进程
  • 每一层检查父进程的可执行文件路径,匹配常见终端
  • 到达根进程(pid 1)时停止,避免无限循环
  • 若未找到终端,会 fallback 到TERM环境变量的值,保证不会为空
  • 可以根据需要扩展case里的终端路径列表,覆盖更多小众终端

内容的提问来源于stack exchange,提问作者sctech-tr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 17:44:52