ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

OpenEuler Shell编程:定制登录界面与规范脚本版权头

OpenEuler Shell编程:定制登录界面与规范脚本版权头 我在 openEuler 服务器上折腾 Shell 的时候最常被问到两个问题能不能把这台机器的登录界面改得不一样还有你脚本开头那堆井号注释、版权信息到底有没有必要今天这篇“我教你 OpenEuler Shell 编程 04”就把这两件事一起解决掉构建自己的登录界面以及给 Shell 脚本做一套规范的头部版权信息。适合刚把 Shell 语法基础过完、想在服务器上做点实际效果的读者纯命令行环境同样适用不需要装图形桌面。实际上登录界面这个任务是很多初学者第一个能“看得见摸得着”的 Shell 项目你能把变量、条件判断、循环、函数、文件操作全用上版权头则能把脚本从“自己能用”变成“可以在团队里流传”。别嫌弃这俩目标基础真正维护过几十台机器、看过别人写的烂脚本的人都会明白这两块内容的价值。1. 整体设计与思路拆解1.1 登录界面到底拆成几块要构建登录界面先别急着改文件。Linux 的登录过程在概念上分得很清楚内核启动、引导程序、显示管理器如果有图形桌面、getty 服务、login 程序、登录 Shell。我们在 openEuler 上通过 Shell 能动手脚的是“getty 显示提示符之前”和“login 验证通过之后”这两个阶段。登录前阶段你可以在 tty 终端上看到 /etc/issue 文件输出的内容登录后阶段会看到 /etc/motd 文件输出的内容然后登录 Shell 会依次读取 /etc/profile、/etc/profile.d 下的脚本、以及用户自己的 .bash_profile 和 .bashrc。把这些环节理清定制界面就有了清晰的发力点用 /etc/issue 画一个“前端广告牌”用 motd 和 profile.d 画一个“后端信息面板”如果你还想更极致一点可以在用户登录后直接进入一个自定义菜单这个菜单就是“你自己的登录界面”。这里我要特别强调一个容易误解的地方很多人说的“登录界面”默认指图形登录界面比如 GNOME 桌面的欢迎页。但我们做运维、做服务器管理时更多面对的是纯文本终端不管是物理机上的 tty还是通过远程 SSH 登录进去的会话看到的都是同一套 getty/login/Shell 机制。图形登录界面不是 Shell 编程能搞定的领域而且对服务器来说是多余的负担文本登录界面的定制才是 Shell 脚本真正使上劲的地方。1.2 为什么说“自己构建”而不是装个桌面很多新手一看到系统自带的登录界面朴素第一反应是给 openEuler 装个 GNOME 或 KDE 桌面环境。这个思路不能说错但对服务器来说性价比很低装桌面会拉进来一大批依赖包占用大量磁盘和内存还可能在无显示器或远程管理场景下遇到显卡驱动、渲染兼容问题。更关键的是服务器上绝大多数管理动作都是在 SSH 终端里完成的你给一台没有接显示器、放在机房角落的机器装个图形登录界面除了多占资源几乎没有任何正向收益。Shell 方案的好处在于轻量、可脚本化、可批量复制。你在一台机器上把自定义脚本调好直接 scp 到几十台服务器上就能统一生效。信息展示可以做成动态的——机器的 IP 地址、负载、内存余量、关键服务状态都可以在登录时自动刷出来。这些东西如果靠人工去一台台看效率极低写成脚本显示在登录界面上维护人员一登进去就全明白了。还有一个非常实在的价值如果你负责维护的服务器使用者并不全是经验丰富的运维工程师甚至有些新同事连free -h、df -h都不太熟悉那你完全可以在登录后给他们弹出一个菜单界面上面列着“查看系统状态、清理临时文件、启动某服务”之类的选项让他们按数字键操作。这相当于用 Shell 给命令行套了一层“防呆壳”能让很多误操作在源头被拦住。1.3 版权头为什么值得单独写一篇说句得罪人的话我见过太多线上脚本第一行写了 shebang第二行就开始写业务逻辑完全没有作者、日期、用途、版本这些信息。脚本出了问题同事需要翻聊天记录才能搞清楚这是谁写的、当时为什么要这么写过三个月你自己回来看也可能一脸茫然。版权头并不是形式主义。它解决的是三个实际问题第一归属问题这是一个脚本的“身份信息”至少要让后来维护的人知道原作者是谁第二时间线问题创建日期和修改日期能帮你快速判断这段逻辑是什么时期的产物是否已经被新方案替代第三传播边界问题在开源文化浓厚的 openEuler 生态里代码被 copy 是很常见的一个清晰的许可证声明能让别人合法地使用和分发你的脚本而不是拿了就跑、出了问题互相甩锅。所以我把登录界面和版权头放在同一篇里讲是因为它们本质上都在做同一件事让你的 Shell 脚本更专业、更可维护。登录界面是展示给别人看的能力版权头是保护你自己和协作效率的能力。2. 核心配置与原理那些藏在 /etc 里的开关2.1 /etc/issue 与 /etc/issue.net登录前的第一张脸/etc/issue 是 getty 在显示“login:”提示符之前打印出来的文本文件作用范围是本地 tty 终端。这个文件里可以放普通文本也可以放一些特殊转义序列\l显示当前终端名比如 tty1\r显示内核版本\n显示主机名\m显示硬件架构。顺手还能拼上 ANSI 颜色码让纯文本不再是死板的白字。还有一个容易被忽略的文件是 /etc/issue.net它是给网络登录使用的传统上主要服务于 telnet。现代 SSH 登录一般不走这个文件除非你在 sshd 配置里显式设置了 Banner 指向某个文件。因此如果你测试发现改了 /etc/issue 后 SSH 进来看不到效果不用奇怪这是正常现象SSH 有自己的欢迎横幅机制。本地终端要测试请按 CtrlAltF2 切换到另一个 tty或者直接在虚拟机控制台上查看。改文件之前有一个铁律先备份。cp /etc/issue /etc/issue.$(date %F)一行命令的事但能让你在把界面写花之后随时回滚。这个习惯必须养成后面改 motd、改 profile.d 同样适用。2.2 /etc/motd 与 /etc/profile.d登录后的第二张脸/etc/motd全称是 Message Of The Day在用户完成身份验证之后、进入 Shell 之前显示。它适合放“静态内容”比如公司规范提示、重要告警、关机维护通知。但注意Motd 只是一个文本文件本身不支持动态命令执行。如果你想让每次登录都显示当前内存用量、磁盘剩余空间那就得靠 Shell 脚本。openEuler 默认会在 /etc/profile 里遍历加载 /etc/profile.d/*.sh 下所有以 .sh 结尾的文件。这是一个标准的扩展点你可以把自己的欢迎脚本丢进去让它跟着所有用户登录自动执行。和修改用户个人的 ~/.bashrc 相比放在 /etc/profile.d 下能做到全局统一新用户登录也生效对运维场景特别友好。顺带说一句执行顺序系统先加载 /etc/profile接着加载 /etc/profile.d 下的脚本然后才轮到用户自己的 ~/.bash_profile、~/.bashrc。如果在多个地方写了同样的欢迎语后加载的会覆盖前加载的显示位置所以别把同样的输出同时塞进多个文件避免刷屏。2.3 ANSI 颜色与转义字符让黑底白字变好看文本终端显示颜色全靠 ANSI 转义序列格式是ESC[参数m。在 Shell 脚本里ESC 一般写成\033或\e。比如\033[31m表示红色\033[32m绿色\033[33m黄色\033[34m蓝色\033[0m重置回默认颜色。可以把颜色定义成变量后面引用时既直观又统一。RED\033[31m GREEN\033[32m YELLOW\033[33m RESET\033[0m echo -e ${GREEN}[OK]${RESET} system is running这里有个新手必踩的坑echo 默认不解释转义序列必须加-e参数或者直接用printf。如果你写echo \033[32mOK\033[0m终端会原样把\033[32m打印出来而不是变成绿色。另外配置文件里写 ANSI 颜色时要注意不同终端对颜色支持程度不一样老式终端可能只能显示 8 色256 色和真彩色不一定都支持所以我建议在 /etc/issue 里只用基础 16 色别追求太花哨。2.4 Shell 脚本注释块版权信息不是乱写的Shell 脚本里每行以#开头的都是注释但版权头并不是随便堆几个#就行。它有一套约定俗成的写法脚本第一行必须是 shebang也就是#!/usr/bin/env bash或#!/bin/bash指定解释器版权头紧跟在 shebang 之后逐行写清楚脚本名、用途、作者、创建时间、修改时间、版本、许可证等字段。为什么 shebang 必须放在第一行因为内核在 exec 脚本时会读取文件第一行来判断用哪个解释器来运行。如果第一行是注释、空行甚至是带 BOM 的编码就会导致bad interpreter之类的错误。这个问题在实际运维中经常出尤其是从 Windows 编辑过的脚本传到 Linux 上文件开头被加了一个看不到的 BOM 字符脚本瞬间就“坏了”。所以我在后面讲自动生成版权头的函数时专门处理了 BOM 和 shebang 顺序问题。3. 实操构建个性化登录界面3.1 准备工具figlet、toilet、lolcat打开终端先确认软件源可用然后安装三个美化工具figlet 生成 ASCII 艺术字toilet 是 figlet 的增强版支持彩色和不同的渲染效果lolcat 能输出彩虹渐变效果。dnf install -y figlet toilet lolcat如果 openEuler 官方源里没有 lolcat别硬刚直接跳过它只用 figlet 配合 ANSI 颜色一样能做出漂亮效果内网环境尤其不要浪费时间折腾第三方源能用的工具组合才是好组合。安装完之后先随便试一下figlet OpenEuler toilet -f mono12 -F metal Welcome注意 tty 文本终端对字体支持有限如果 figlet 默认字体出现乱码或者宽度超出一行可以切换字体figlet -f slant OpenEuler。斜体字、宽体字、标准字选一个在终端里不会折行、观感合适的就行。3.2 登录前界面动态生成 /etc/issue/etc/issue 是静态文件但服务器 IP 地址经常变化你想让登录前界面显示当前 IP就不能直接写死。我的做法是写一个生成脚本在系统启动时重新生成 /etc/issue。先创建/usr/local/sbin/gen-issue.sh#!/usr/bin/env bash # # gen-issue.sh: 动态生成 /etc/issue HOSTNAME_SHORT$(hostname -s) KERNEL_VERSION$(uname -r) ARCH$(uname -m) IP_ADDR$(hostname -I | awk {print $1}) { printf \033[1;32m figlet -f slant OpenEuler Server printf \033[0m printf Hostname : %s\n $HOSTNAME_SHORT printf Kernel : %s\n $KERNEL_VERSION printf Arch : %s\n $ARCH printf IP Addr : %s\n $IP_ADDR printf \n } /etc/issue这段脚本把系统信息收集起来重定向写入 /etc/issue。之后要让它开机能执行openEuler 上最简单的方式是使用 rc.local编辑/etc/rc.d/rc.local在末尾加一行/usr/local/sbin/gen-issue.sh然后给 rc.local 加执行权限。如果发现重启后没有生效通常是 rc-local.service 没启用执行systemctl enable rc-local.service再试。无论你的机器是 x86 还是 aarch64 架构这套脚本都能正常工作uname系列命令会自动给出对应的架构标识。3.3 登录后欢迎界面/etc/motd 与 welcome.sh登录前有了一张“广告牌”登录后我建议给用户一张“仪表盘”显示系统当前状态。静态提示放在 /etc/motd动态状态放在 /etc/profile.d/welcome.sh。先写 /etc/motd内容随意比如Welcome to OpenEuler. All operations are logged. Unauthorized access is prohibited.然后在 /etc/profile.d/ 下创建 welcome.sh#!/usr/bin/env bash # # welcome.sh: 用户登录后显示系统信息 GREEN\033[32m YELLOW\033[33m RED\033[31m RESET\033[0m load$(uptime | awk -Fload average: {print $2}) mem_total$(free -h | awk /^Mem:/{print $2}) mem_used$(free -h | awk /^Mem:/{print $3}) disk_root$(df -h / | awk NR2{print $5 used, $4 free}) printf ${GREEN}System:${RESET} %s\n $(hostname -s) printf ${GREEN}Load:${RESET}%s\n $load printf ${GREEN}Memory:${RESET} %s / %s\n $mem_used $mem_total printf ${GREEN}Disk /:${RESET} %s\n $disk_root注意几点awk -Fload average:是从 uptime 输出里切出负载值free -h在内存很小或很大的机器上显示单位不同但 / 段和 total 段一般都在。脚本放在 /etc/profile.d 下所有用户登录都会看到。如果你不想让普通用户看到全部信息可以加个判断if [ $USER root ]; then ... fi把密集内容限制给管理员看。3.4 把登录界面升级成一个菜单如果你想让定制更近一步可以在用户登录后直接进入一个菜单用这个菜单充当“登录界面”。原理就是在用户的 .bashrc 末尾调用一个菜单脚本。先创建/usr/local/bin/login_menu.sh#!/usr/bin/env bash # # login_menu.sh: 登录后的自定义操作菜单 show_menu() { clear echo echo Welcome to OpenEuler Server echo 1. View system status echo 2. Check running services echo 3. Enter normal shell echo q. Exit / logout echo } while true; do show_menu read -rp Please select: choice case $choice in 1) uptime free -h echo Press Enter to continue... read -r ;; 2) systemctl list-units --typeservice --staterunning echo Press Enter to continue... read -r ;; 3) echo Launching normal shell... exec bash ;; q|Q) echo Goodbye. exit 0 ;; *) echo Invalid option. Try again. sleep 1 ;; esac done然后在/etc/skel/.bashrc或者单用户~/.bashrc末尾加一行[ -x /usr/local/bin/login_menu.sh ] /usr/local/bin/login_menu.sh菜单脚本里的exec bash很关键它用 bash 替换当前菜单进程等用户退出交互 Shell 时能直接结束 SSH 会话或 tty 登录不会重新弹回菜单避免死循环。这套设计特别适合交给不太熟悉命令的同事用日常巡检直接选 1、选 2不会误打误撞进系统目录乱翻。4. 实操为脚本加上规范的头部版权信息4.1 头注释该写哪些字段我写脚本头注释的时候默认包含这几个字段脚本名、用途描述、作者、联系邮箱、创建日期、最后更新日期、版本号、许可证、依赖说明。有些公司还要求加“修改历史”字段记录每次变更的版本号、时间和原因。字段不是越多越好但“脚本名、用途、作者、日期、许可证”这五样我是强烈建议写全的。为什么联系邮箱很重要因为脚本总有一天会出 bug别人发现问题后能顺着邮箱找到你没有联系信息问题就只能自己扛或者被绕过。许可证同样重要哪怕你只是在公司内部流传也建议写一句“仅限内部使用未经授权禁止分发”或者用开源社区常见的 MIT、GPL 声明按照自己的意图说明。这不算法律文书但能有效表明作者的立场减少日后纠纷。4.2 一个干净的标准模板我给团队内部定了一个模板下面这个是我现在最常用的版本#!/usr/bin/env bash # # script-name : system_info.sh # description : Print basic system information # author : yourname youexample.com # created : 2025-01-10 # updated : 2025-06-15 # version : 1.2.0 # license : MIT # usage : bash system_info.sh # note : This script is called by /etc/profile.d. #解释一下几个容易被忽略的细节。第一注释列用空格对齐别用 Tab因为不同编辑器对 Tab 的宽度解析不一致贴到 issue、邮件或者评审系统里容易错位。第二字段名用连字符script-name而不是下划线这是许多开源项目的习惯也方便以后用 grep 去搜。第三版本号建议用语义化版本主版本号.次版本号.修订号比如 1.2.0 表示有两次功能更新、一次修订这样别人看到版本号就能判断脚本的迭代阶段。4.3 写个 add_header 函数自动插入版权头手敲版权头不仅累而且不同脚本很容易写得五花八门。我直接把自动插入模板的函数放到了系统全局配置文件里让所有用户都能调用。下面是一个可以放进 /etc/profile.d/header_function.sh 的版本add_header() { local target$1 if [ -z $target ]; then echo Usage: add_header script-file return 1 fi if [ ! -f $target ]; then echo File not found: $target return 1 fi if grep -q ^# script-name $target 2/dev/null; then echo Header already exists. return 1 fi local tmp_file tmp_file$(mktemp) { if ! head -1 $target | grep -q ^#!; then echo #!/usr/bin/env bash fi cat EOF # # script-name : script.sh # description : TODO # author : yourname youexample.com # created : $(date %F) # updated : $(date %F) # version : 0.1.0 # license : MIT # usage : bash script.sh # note : TODO # EOF cat $target } $tmp_file mv $tmp_file $target chmod x $target echo Header added to $target }这里有一个非常关键的细节创建临时文件时我用的是EOF而不是EOF。单引号EOF会告诉 Bash 不要展开 heredoc 里的$符号否则模板里的$(date %F)会被立即执行成日期字符串写得就没意义了。我见过太多人栽在这个地方自动生成的版权头日期全写成了同一个固定值根本起不到记录时间的作用。函数逻辑也很直接先检查目标文件是否存在、是否已有版权头如果没有再检查第一行是不是 shebang是就把模板插到 shebang 后面不是就先补 shebang 再插模板。最后用临时文件替换原文件并加上执行权限。这样你新建脚本后只要执行add_header myscript.sh一个规范的头部就自动生成了。5. 常见问题与排查技巧实录5.1 常见故障速查表这几种情况我在 openEuler 上都实际遇到过整理成一张速查表方便各位对号入座。现象常见原因解决思路修改 /etc/issue 后本机没变化当前 tty 没有被重新刷新或者你改错文件切换到其他 tty 测试确认 /etc/issue 未发生权限异常确认脚本不是覆盖了它SSH 登录不显示 /etc/issueSSH 登录默认不读取 /etc/issue改用 sshd 的 Banner 配置或通过 motd/profile.d 显示信息/etc/motd 没生效SSH 配置或 PAM 未启用 motd 模块检查 sshd_config 的 PrintMotd 参数检查 /etc/pam.d/login 是否有 pam_motdprofile.d 脚本不执行扩展名不是 .sh、没有执行权限、脚本有语法错误确认文件名以 .sh 结尾给脚本加可执行权限用 bash -n 检查语法输出 ANSI 颜色全是乱码echo 没加 -e或者颜色序列写错使用 echo -e或改用 printf检查 \033 是否转成了 Tab 字符自动插版权头后脚本无法执行文件开头出现 BOM或 shebang 被挤到第二行用 sed 删除开头 BOM重构自动函数确保 shebang 保持在第一行5.2 三个我踩过的坑第一个坑是输出了颜色变量却被终端当成普通字符串。原因很简单变量里面的\033被赋值后echo 不会自动解释它。我后来统一用 printf 或者 echo -e很少再出问题。第二个坑是 rc.local 不生效。我在做动态 issue 时把生成命令写进 /etc/rc.d/rc.local结果重启后 /etc/issue 纹丝不动。排查了半天发现 rc.local 没有执行权限systemd 也没有启用 rc-local.service。openEuler 上要先把这两个条件补齐rc.local 里的命令才会在启动末尾执行。这个坑几乎每个初做系统定制的人都会踩一次。第三个坑是登录菜单脚本写得太“狠”。最初我在菜单里的“进入普通 Shell”分支用了exit设想用户退出 Shell 后回到菜单结果用户一登录就进入菜单再选普通 Shell 退出后直接退出了 SSH 会话根本回不到菜单。改成exec bash后问题解决。5.3 最后一个经验改文件前先备份这个习惯我强调过好几次但值得最后再说一遍每次准备改动 /etc/issue、/etc/motd 或任何 systemd 配置之前先花两秒钟复制一份备份文件哪怕只是加了个.bak后缀。我吃过不止一次亏有一次手滑把 motd 里的引号写成了中文全角引号登录提示立刻显示异常。没有备份的话你还得靠记忆恢复原文有备份的话一条cp命令就回到正常状态。版权头这件事也一样不要嫌模板字段多。我个人的体会是给每一个正式发布的脚本都写上“谁写的、哪天写的、干什么用的”两个月后再回来看代码你能省下大量回忆时间如果脚本被同事拿去改过几次版权头里的更新历史更是帮你看清代码演进的脉络。这套组合做下来登录界面是给别人看的专业感版权头是给自己和同事留的后路一个负责“面子”一个负责“里子”。最后再分享一个小技巧把 add_header 函数放到全局 profile.d 后记得用bash -n检查语法但凡 heredoc 写错一个引号所有用户登录都会报错那样就不是加分项而是事故源了。
返回列表