shell每日三题大神之路:第三天
🏋️ 例题 1:静默读密码
read -rsp "Password: " pw
echo # 换行
if [[ $pw == secret ]]; thenecho "Login ok"
elseecho "Wrong pwd"
fi
知识点1:read的用法
read是shell中专门用来获取标准输入的命令,具有多种参数应用于不同场景,参数如下:
参数 | 作用 |
---|---|
-r | 关掉反斜杠转义(99% 场景都要加) |
-p | 直接给出提示符(read -p "name: " name) |
-s | 静默输入(密码不回显) |
-n N | 读够 N 个字符就停 |
-t S | 超时 S 秒自动结束(备注:超时退出时返回代码是1) |
-a array | 把整行按空格切成数组 |
-d delim | 自定义行结束符(默认是换行) |
知识点2:测试语法易错点
牢记扩展测试符中,变量,运算符,字符串之间需要用空号隔开。
🏋️ 例题 2:带超时读菜单
#!/usr/bin/bash
while true;do
read -rn 1 -t 5 -p 'choice[1-5]' choice || { echo -e "\n超时输入,请重新输入";(exit 1)}
if [[ $? == "1" ]];then
continue
else
case $choice in
1) echo "choice is 1" ;;
2) echo "choice is 2" ;;
3) echo "choice is 3" ;;
*) echo "none choice" ;;
esac
fi
break
done
知识点1:case的用法需要牢记
知识点2:{}与()的区别
{}:代码块,将多条命令打包到本地shell中执行
():子shell命令组:将多条命令打包到一个子shell中执行,环境是隔离的。
在 Bash 里,{}
和 ()
看起来很相似,但底层行为完全不同,记住一句话即可:
()
一定开子进程;{}
永远不开子进程,只是“打包”命令。
语法 | 是否开子 shell | 变量/函数是否隔离 | 示例 |
---|---|---|---|
{ cmd1; cmd2; } | ❌ 否 | ❌ 共享 | a=1; { a=9; }; echo $a → 9 |
( cmd1; cmd2 ) | ✅ 是 | ✅ 隔离 | a=1; (a=9); echo $a → 1 |
注意:
{}
内每条命令后必须加;
(或换行),且左大括号后要有空格:{ echo 1; echo 2; } >log.txt
()
末尾可省略分号:(echo 1; echo 2)
知识点3:return和exit的区别
exit 与 return 的底层差异可以概括为一句话:
exit 终止整个进程;return 只结束当前函数 / source 调用层,进程仍在。
作用对象
指令 | 作用对象 | 场景 |
---|---|---|
exit [n] | 整个 Shell 进程 | 脚本顶层、交互式 Shell、函数、source 文件——任何地方 |
return [n] | 当前函数或 source 脚本 | 仅能在 函数 或 被 source 的脚本 里使用 |
疑问:为什么return作用于source的脚本中呢
两者最大的不一样在于是否结束掉那个运行shell的进程,exit会结束掉shell进程,但是return不会,他在source中只是结束掉了那个shell从读取脚本命令的这个过程并且返回一个代码,原来脚本的后续命令仍然会继续。
执行模型:没有新的进程或子 Shell
source filename
(或. filename
)执行时,当前 Shell 进程通过open()
/read()
逐行读取文件内容,并在 同一个解释器上下文 中立即执行,相当于把文件内容“嵌入”到当前脚本中。因此,文件里的任何变量、函数、别名都直接写入 当前 Shell 的全局符号表,无需复制或隔离。
int source_builtin(list *words) {int fd = open(...);int status = 0;while (line = read_line(fd)) {status = execute_command(line); /* ← 逐行执行 */if (current_token == TOKEN_RETURN) {/* 解析 return <n> */status = parse_return_value();break; /* 停止继续读取文件 */}}close(fd);return status; /* 此时成为 source 命令的退出码 */ }
🏋️ 例题 5:整行变数组
read -ra nums -p "输入若干数字: "
sum=0
for n in "${nums[@]}"; do((sum += n))
done
echo "Sum = $sum"
知识点1:
遍历数组的方式需要用${array[@]}的格式来做,直接用array返回的是array名字或者0
知识点2:
shell中一般碰到需要数字运算的时候都要用(())或者$(())来完成,不然默认都是字符串碰到运算就会寄。
知识点3:
echo -e
的作用是 “启用反斜杠转义”,让字符串里的转义序列真正生效。
默认情况下,echo
会把反斜杠当成普通字符原样输出;加了 -e
之后,下面这些序列就会被解释成对应的控制字符:
转义符 | 含义说明 |
---|---|
\n | 换行 |
\t | 水平制表符(Tab) |
\r | 回车,光标移到行首 |
\b | 删除前一个字符 |
\c | 输出到此结束,不再追加换行 |
\a | 响铃(BEL) |
\\ | 反斜杠本身 |
\033[31m … | 终端颜色码(ANSI 颜色) |