常见的shell
# 常见的shell 有哪些
Bourne Shell(/usr/bin/sh或/bin/sh)
Bourne Again Shell(/bin/bash)
C Shell(/usr/bin/csh)
K Shell(/usr/bin/ksh)
Shell for Root(/sbin/sh)
# 最常用的shell是Bash,也就是Bourne Again Shell。Bash由于易用和免费,在日常工作中被广泛使用,也是大多数Linux操作系统默认的Shell环境
重定向
python hello.py > output.txt # 标准输出到(文件)
python hello.py >> output.txt # 标准输出到(文件),追加
python hello.py 2> error.log # 标准错误到(文件)
python hello.py 2>&1 # 标准错误到标准输出
python hello.py 2>/dev/null # 标准错误到(空null)
python hello.py &>/dev/null # 标准输出和标准错误到(空null)
python hello.py < foo.txt # 将 foo.txt 提供给 python 的标准输入
系统环境变量
#Shell常见的系统环境变量
PATH 命令所示路径,以冒号为分割;
HOME 打印用户家目录;
SHELL 显示当前Shell类型;
USER 打印当前用户名;
ID 打印当前用户id信息;
PWD 显示当前所在路径;
TERM 打印当前终端类型;
HOSTNAME 显示当前主机名;
PS1 定义主机命令提示符的;
HISTSIZE 历史命令大小,可通过 HISTTIMEFORMAT 变量设置命令执行时间;
RANDOM 随机生成一个 0 至 32767 的整数;
颜色输出
字体颜色数字
#字体颜色31-37 默认=0,黑色=30,红色=31,绿色=32,黄色=33,蓝色=34,紫色=35,天蓝色=36,白色=3
#背景颜色41-47
echo -e "\e[31m红色文字\e[0m"
echo -e "\e[32m绿色文字\e[0m"
各参数解释说明:
-e 启用反斜杠转义的解释
\e 转义起始符,定义一个转义序列, 可以使用\033代替 可以定义变量RED='\033[31m'; GREEN='\033[32m'; NC='\033[0m'
[ 表示开始定义颜色
m 转义终止符,表示颜色定义完毕
再次使用 \e[ ,表示再次开启颜色定义,0表示使用默认的颜色,m表示颜色定义结束,所以最后的 \e[0m 的作用是恢复之前的配色方案
\e[0m也可以写成\033[0m
字体样式
#举例说明
echo -e "\e[1;33;41m test content \e[0m"
1表示高亮,33表示字体颜色为黄色,45表示背景色为红色
# 显示方式1-8
0 普通字符(复位或正常) 关闭所有属性
1 粗体字
2 弱化(降低强度) 未广泛支持
3 斜体 未广泛支持有时为反相显示
4 下划线
5 缓慢闪烁
6 快速闪烁
7 反显
8 隐藏 未广泛支持。
9 划除
语法检查调试
Shell本身提供一些调试方法选项:
-n,读一遍脚本中的命令但不执行,用于检查脚本中的语法错误。
-v,一边执行脚本,一边将执行过的脚本命令打印到标准输出。
-x,提供跟踪执行信息,将执行的每一条命令和结果依次打印出来。
使用这些选项有三种方法(注意:避免几种调试选项混用)
1.在命令行提供参数:sh -x script.sh 或者 bash -n script.sh
2.脚本开头提供参数:#!/bin/sh -x 或者 #!/bin/bash -x
3.在脚本中用set命令启用或者禁用参数,其中set -x表示启用,set +x表示禁用
流程控制
if
语法格式
if [ 条件测试 ]; then
# 条件为真时执行的命令
fi
if [ -e "/etc/passwd" ]; then
echo "文件 /etc/passwd 存在"
fi
字符串判断
if [[ str1 = str2 ]] # 当字符串 str1 和 str2 有相同内容、长度时为真
if [[ str1 != str2 ]] # 当字符串 str1 和 str2 不等时为真
if [[ -n "str1" ]] # 当字符串 str1 的长度大于 0(非空)时为真
if [[ -z "str1" ]] # 当字符串 str1 的长度为 0(空)时为真
if [[ str1 ]] # 当字符串 str1 为非空时为真
文件判断
文件存在且可读
if [ -e "$FILE" ] && [ -r "$FILE" ]; then
echo "文件存在且可读"
fi
[[ -h FILE ]] 符号链接
[[ -s FILE ]] 大小 > 0 字节
[[ -r FILE ]] 可读
[[ -w FILE ]] 可写
[[ -x FILE ]] 可执行文件
[[ f1 -nt f2 ]] f1 比 f2 新
[[ f1 -ot f2 ]] f2 比 f1 新
[[ f1 -ef f2 ]] 相同的文件
目录判断
if [ -d dir ]; 判断目录是否存在
数字判断
-eq 等于,应用于整型比较 equal;
-ne 不等于,应用于整型比较 not equal;
-lt 小于,应用于整型比较 letter;
-gt 大于,应用于整型比较 greater;
-le 小于或等于,应用于整型比较;
-ge 大于或等于,应用于整型比较;
-a 双方都成立(and) 逻辑表达式 –a 逻辑表达式;
-o 单方成立(or) 逻辑表达式 –o 逻辑表达式;
-z 空字符串;
-x 是否具有可执行权限
|| 单方成立;
判断用户是否存在
if id -u "nginx" >/dev/null 2>&1; then
echo "nginx用户存在"
fi
if-else语句
语法
if [ 条件测试1 ]; then
# 条件1为真时执行的命令
elif [ 条件测试2 ]; then
# 条件2为真时执行的命令
else
# 所有条件都为假时执行的命令
fi
案例:分数比较
read -p "请输入分数: " score
if [ $score -ge 90 ]; then
echo "优秀"
elif [ $score -ge 80 ]; then
echo "良好"
elif [ $score -ge 60 ]; then
echo "及格"
else
echo "不及格"
fi
for 循环
语法
for 变量名 in 取值列表; do
# 执行的操作
done
遍历数字范围
for i in {1..5}; do
echo $i # 依次打印1 2 3 4 5
done
或
for (( i=1; i<5; ++i)); do # 使用条件表达式
echo $i
done
遍历数组
arr=("apple" "banana" "orange" "grape")
for i in "${arr[@]}"; do
echo $i
done
结果:
apple
banana
orange
grape
arr=("apple" "banana" "orange" "grape")
for i in "${arr[*]}"; do
echo $i
done
结果:
apple banana orange grape
无限循环特定输入退出
# 用户输入 "exit" 才退出循环
for (( ; ; )); do
read -p "输入命令 (输入 exit 退出): " cmd
if [ "$cmd" = "exit" ]; then
echo "退出循环"
break
else
echo "执行: $cmd"
fi
done
while 循环
语法
while [ 条件测试 ]; do
# 要执行的命令
done
数字循环
count=1
while [ $count -le 100 ]; do
echo $count
count=$((count+1))
done
或
count=1
while ((count <= 100)); do # 使用条件表达式
echo $count
count=$((count+1))
done
1-100 的总和
#求 1-100 的总和
j=0
i=1
while ((i<=100))
do
j=`expr $i + $j`
((i++))
done
echo $j
无限循环特定输入退出
#只有输入CTRL+C才会退出循环
while true; do
echo "Press [CTRL+C] to stop.."
sleep 1
done
break 和 continue 语句
break 和 continue 语句
break 是终止循环。
continue 是跳出当前循环。
#示例 1:在死循环中,满足条件终止循环
while true; do
let N++
if [ $N -eq 5 ]; then
break
fi
echo $N
done
输出:1 2 3 4
#示例 2:举例子说明 continue 用法
N=0
while [ $N -lt 5 ]; do
let N++
if [ $N -eq 3 ]; then
continue
fi
echo $N
done
输出:1 2 4
# 打印 1-100 数字
i=0
while ((i<=100))
do
echo $i
i=`expr $i + 1`
done
case 选择语句
语法
case 变量 in
模式1)
命令1
;;
模式2)
命令2
;;
*)
默认命令
;;
esac
输入字符判断
#!/bin/bash
echo "请输入一个字符:"
read -n1 char # 只读取一个字符,无需按回车
echo # 换行,美观起见
case $char in
[a-z])
echo "小写字母"
;;
[A-Z])
echo "大写字母"
;;
[0-9])
echo "数字"
;;
*)
echo "特殊字符"
;;
esac
菜单创建
内置变量详解
$REPLY 变量的作用
$REPLY 是 read 命令的一个特殊变量。当使用 read 命令且没有明确指定变量名时,用户输入的内容会自动存储到 $REPLY 变量中。示例如下:
echo "请输入任意内容:"
read # 未指定变量名
echo "你输入的内容是:$REPLY"
运行结果:
请输入任意内容:
2
你输入的内容是:2
PS3:交互式菜单的提示符
- 作用:
PS3是 shell 的一个特殊环境变量,专门用于select命令的交互式菜单。当使用select命令创建菜单时,PS3的值会作为菜单的提示符显示出来,提示用户进行选择。 - 默认值:如果没有对
PS3进行设置,它的默认值是#?。
PS3="请选择操作(输入数字):"
select item in "查看文件" "创建文件" "退出"; do
case $REPLY in # $REPLY 存储用户输入的数字
1) ls ;;
2) touch new_file.txt ;;
3) exit ;;
*) echo "无效选择" ;;
esac
done
运行结果:
1) 查看文件
2) 创建文件
3) 退出
请选择操作(输入数字):
select 选择语句菜单创建
优点:
- 内置菜单:无需手动编写编号,自动生成数字选项(1, 2, 3…)。
- 简洁易用:只需定义选项和处理逻辑,无需额外循环。
- 自动处理输入:用户输入会自动存储在
$REPLY中,无需额外变量。
缺点:
- 样式固定:菜单格式固定(数字 + 选项),难以自定义样式。
- 只能输入数字:用户必须输入数字选项,输入非数字会提示错误。
- 无限循环:不输入有效选项会一直循环,需手动退出(如
exit)。
适用场景:简单的交互式菜单,无需复杂样式或输入验证。
# 选择mysql 版本
#!/bin/bash
PS3="Select a number: "
while true; do
select mysql_version in 5.1 5.6 quit;
do
case $mysql_version in
5.1)
echo "mysql 5.1"
break
;;
5.6)
echo "mysql 5.6"
break
;;
quit)
exit
;;
*)
echo "Input error, Please enter again!"
break
esac
done
done
for循环+数组菜单创建
优点:
- 动态生成菜单:通过数组管理选项,便于添加或删除菜单项。
- 自定义样式:可自由控制菜单格式(如添加前缀、颜色)。
- 代码简洁:选项较多时比
echo更易维护。
缺点:
- 手动计算索引:数组索引从 0 开始,需用
$((i+1))转换为 1-based 编号。 - 输入验证复杂:需额外代码处理非数字输入或越界选择。
- 缺乏内置循环:如需重复显示菜单,需手动添加循环。
适用场景:选项动态变化或需要批量生成菜单的场景。
#!/bin/bash
echo "欢迎使用菜单选项"
echo "请选择你要执行的操作:"
options=("选项1" "选项2" "选项3" "退出")
# 循环显示菜单选项
for option in "${options[@]}"
do
echo "$option"
done
# 读取用户的选择
read -p "请选择一个选项 (输入选项编号): " choice
# 判断用户的选择
if [[ $choice -eq 1 ]]; then
echo "你选择了选项1"
# 在这里添加选项1的逻辑代码
elif [[ $choice -eq 2 ]]; then
echo "你选择了选项2"
# 在这里添加选项2的逻辑代码
elif [[ $choice -eq 3 ]]; then
echo "你选择了选项3"
# 在这里添加选项3的逻辑代码
elif [[ $choice -eq 4 ]]; then
echo "你选择了退出"
# 在这里添加退出的逻辑代码
else
echo "无效的选择,请重新输入"
fi
结果如下:
欢迎使用菜单选项
请选择你要执行的操作:
选项1
选项2
选项3
退出
请选择一个选项 (输入选项编号):
使用 echo 命令和 read 命令
优点:
- 高度自定义:这种方式通常结合
case语句来处理用户的输入,可以清晰地列出所有选项,并且每个选项后都可以跟随特定的命令。例如,可以通过read命令读取用户的输入,然后使用case语句判断用户输入的值,并执行相应的命令,可以自由控制菜单样式(如添加颜色、图标)。 - 灵活输入:可结合
read选项(如-s隐藏输入、-n1限制单字符)。 - 单次交互:执行一次后退出,无需手动终止循环。
缺点:
- 手动管理编号:需自行维护选项编号与逻辑的对应关系。
- 代码冗余:选项较多时,
echo和case会变得冗长。 - 缺乏循环:如需重复显示菜单,需手动添加循环结构。
适用场景:需要自定义菜单样式或复杂输入验证的场景。
#!/bin/sh
while true; do
echo "1. 目录内容"
echo "2. 切换目录"
echo "3. 创建文件"
echo "4. 编辑文件"
echo "5. 删除文件"
echo "6. 退出菜单"
read -p "请输入选择(1-6): " input
case $input in
1) ls ;;
2) echo "Enter target directory: "
read dir
cd $dir ;;
3) echo "Enter a file name: "
read file
touch $file ;;
4) echo "Enter a file name: "
read file
vi $file ;;
5) echo "Enter a file name: "
read file
rm $file ;;
6) break ;;
*) echo "错误选择!" ;;
esac
done
几种方式对比结果
| 特性 | select | echo + read | for + 数组 |
|---|---|---|---|
| 代码复杂度 | 低(内置循环和编号) | 中(手动编写编号和循环) | 中(需处理数组索引) |
| 样式自定义 | 差(固定格式) | 好(完全自定义) | 好(可结合数组动态生成) |
| 输入验证 | 简单(只能输入数字) | 灵活(可结合 read 选项) | 灵活(需手动处理) |
| 选项动态性 | 差(需修改代码) | 差(需逐个修改 echo) | 好(通过数组管理) |
| 循环控制 | 自动循环(需手动退出) | 需手动添加循环 | 需手动添加循环 |
| 适用场景 | 简单菜单(如脚本内部选项) | 复杂样式或单次交互 | 选项动态变化的场景 |
函数数组
函数
Shell 函数很简单,函数名后跟双括号,再跟双大括号。通过函数名直接调用,不加小括号 # 函数语法 func() { command1 command1 …… } func # 直接调用函数名 #实例 #!/bin/bash func() { VAR=$((1+1)) return $VAR echo “This is a function.” } func echo $?数组
数组是相同类型的元素按一定顺序排列的集合。 格式:array=(元素 1 元素 2 元素 3 …) 用小括号初始化数组,元素之间用空格分隔。 定义方法 1:初始化数组 array=(a b c) 定义方法 2:新建数组并添加元素 array[下标]=元素 定义方法 3:将命令输出作为数组元素array=($(command))遍历数组
#方法 1:
#!/bin/bash
IP=(10.0.0.1 10.0.0.2 10.0.0.3)
for ((i=0;i<${#IP[*]};i++)); do
echo ${IP[$i]}
done
# bash test.sh
10.0.0.1
10.0.0.2
10.0.0.3
#方法 2:
#!/bin/bash
IP=(10.0.0.1 10.0.0.2 10.0.0.3)
for IP in ${IP[*]}; do
echo $IP
done</code></pre>
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END
