系列文章目录
前言
Shell编程是一门非常有用的技能,无论你是一名系统管理员、开发人员还是普通用户。通过学习Shell编程,你可以轻松地自动化许多重复繁琐的任务,优化你的工作流程,提高工作效率。本文将介绍学习Shell编程的必要性以及如何开始学习Shell编程。无论你是初学者还是有一定经验的Shell编程者,本文都将对你有所帮助。
一、概述
1.shell的定义
Shell是一种命令行解释器,是在计算机操作系统中提供用户与操作系统交互的一种方式。通常Shell是指命令行界面,用户通过Shell界面可以输入命令并获得相应的操作结果。
2.shell的主要功能
(1)提供命令行界面:Shell提供了一个命令行界面,用户可以通过键盘输入命令来与操作系统进行交互。这种交互方式相对于图形用户界面更加高效,可以让用户快速地完成各种操作。
(2)管理文件和目录:Shell可以对文件和目录进行各种操作,如创建、删除、复制、移动、重命名等等。用户可以通过Shell在文件系统中进行各种操作,例如创建文件夹、查看文件内容、修改文件权限等。
(3)执行各种命令和程序:用户可以通过Shell执行各种命令和程序,如编译代码、运行脚本、启动服务等。Shell会将用户输入的命令解释并执行相应的操作。
(4)管理进程和系统资源:Shell可以管理和控制进程,包括启动、停止、暂停和重启进程,还可以查看和管理当前正在运行的进程。同时,Shell还可以管理系统资源,如内存、CPU等。
(5)配置系统和环境:Shell可以管理和配置系统设置、环境变量、网络配置等等。用户可以通过Shell配置网络连接,修改系统环境变量等等。
3.shell常见的解释器
解释器:一种命令解释器,主要作用是对命令进行运行和解释,将需要执行的操作传递给操作系统内核并执行
四种解释器:
#!/bin/bash(默认)
#!/bin/ksh
#!/bin/bsh
#!/bin/sh
注意:
shell脚本运行不一定需要解释器,有些脚本没有解释器也可以运行
4.shell脚本文件权限与脚本执行
- 执行shell脚本的方法:
方法一:sh 文件名
方法二:bash 文件名
方法三:./文件名
方法四:source 文件名
注意:
文件创建默认是没有执行权限的,所以要给加上权限:chmod u+x sh结尾的文件。
5.错误处理与调试
5.1错误处理与调试
- 在Bash中,常见的错误包括语法错误、运行时错误和逻辑错误。
5.1.1语法错误
语法错误通常是指脚本中出现了不符合 Bash 语法规范的语句,例如缺少引号、括号不匹配、变量名错误等等。这些错误会导致脚本无法正常执行。为了避免语法错误,可以使用 ShellCheck 等工具来检查代码。
5.1.2运行时错误
运行时错误通常是指脚本在执行过程中出现了问题,例如文件不存在、权限不足、内存不足等等。为了避免这些错误,可以在脚本中使用条件语句进行判断,以确保程序能够正确地运行。同时,还可以使用 try-catch 或者 trap 命令来捕捉和处理异常。
5.1.3逻辑错误
逻辑错误通常是指脚本的输出结果和预期不一致,例如变量赋值错误、循环条件错误、函数调用错误等等。为了避免逻辑错误,可以在编写脚本时进行严格的测试和校验,以确保程序的正确性。
5.2调试技巧与工具
5.2.1
- 在 Bash 中,可以使用 echo 命令输出调试信息来查看程序的执行情况。
5.2.2使用set命令
- 在 Bash 中,可以使用 set -x 命令来打开调试模式,这样所有执行的语句都会被输出到终端上。
示例:
#!/bin/bsh
testfunc1() {
echo this is testfunc1!
}
set -x
testfunc1
set +x
运行结果:
5.2.3使用调试器
Bash 提供了内置的调试器——bashdb,它可以帮助我们更方便地调试 Bash 脚本。
首先需要安装 bashdb,例如在 Ubuntu 系统上可以使用以下命令进行安装:
sudo apt-get install bashdb
然后在脚本文件中添加以下代码:
#!/bin/bsh -x
testfunc1() {
echo this is testfunc1!
}
testfunc1
最后运行以下命令即可进入调试模式:
bashdb script.sh
在调试模式下,可以使用类似 gdb 的命令来逐步执行脚本、查看变量值等等。
示例:
二、变量与符号
1.常用变量
- =:等于号赋值,a=15
- $a:调取a变量的值
- ${a}:调取a变量的值,当{a}后面有其他字符时,不会影响a的获取
- $?:判断上一条命令执行的结果,成功为0,失败为1
- $1-$9:返回对应的第几个参数
- $*:返回所有的参数的值是什么
- $#:返回参数的个数
- $?:显示上一条命令执行的结果,0表示执行成功,1或大于1表示执行失败
- $$: Shell本身的PID(ProcessID,即脚本运行的当前进程ID号)
2.常用符号
- > #输出重定向(覆盖)
- >> #输出重定向(追加)
- ; #执行多条命令
- | #管道符
- && #前一条命令执行成功才会执行后面
- || #前一条命令执行失败才会执行后面
- “” #输出变量识别通配符
- ‘’ #输出本身
- `` #优先执行,放在``中会识别成命令执行
- &>/dev/null #错误输出到无底洞
3.算术运算符及linux中的计算器
expr是一个用于计算表达式的命令行工具。它可以用于执行各种数学运算,比较和字符串操作。
3.1计算两个整数的和
expr 5 + 3 # 输出:8
方式一:expr $a + $b
方式二:echo $[a + b]
方式三:echo $((a + b))
3.2计算两个整数的差
expr 5 - 3 # 输出:2
方式一:expr $a - $b
方式二:echo $[a - b]
方式三:echo $((a - b))
3.3计算两个整数的积
expr 5 \* 3 # 输出:15
方式一:expr $a \* $b
方式二:echo $[a * b]
方式三:echo $((a * b))
3.4计算两个整数的商
expr 6 / 3 # 输出:2
方式一:expr $a / $b
方式二:echo $[a / b]
方式三:echo $((a / b))
3.5整数求余
方式一:expr $a % $b
方式二:echo $[a % b]
方式三:echo $((a % b))
3.6比较两个整数是否相等
expr 5 = 3 # 输出:0
3.7比较两个整数是否不相等
expr 5 != 3 # 输出:1
3.8获取字符串的长度获取字符串的长度
expr length "hello world" # 输出:11
3.9查找字符串中某个字符的位置(第一次出现的位置)
expr index "hello world" o # 输出:5
3.10 1.2+1.3 保留两位小数
借助bc计算器,保留多少为小数可以通过sacle,但是scale只对除法,取余数,乘法有效,对加减无效
示例:
echo "scale=2;(1.2 + 1.2)/1" | bc
运行结果:
4.条件判断
- 语法:[ 判断表达式 ]
4.1文件夹或者路径
-e:目标是否存在(exist)
-d:是否为目录(directory)
-f:是否为文件(file)
示例:
4.2权限
-r:是否有读权限(read)
-w:是否有写入权限(write)
-x:是否有执行权限(excute)
示例:
4.3整形数值比较
-eq:等于(equals)
-ne:不等于(not equals)
-gt:大于(greater than)
-lt:小于(lesser than)
-ge:大于或等于(greater or equal)
-le:小于或等于(lesser or equal)
示例:
4.4浮点型判断
[ `echo '1.4 < 1.6' | bc` -eq 1 ] && echo "YES"
示例:
4.4字符串判断
=:相等
!=:不相等
示例:
三、语法
1.输入与输出语句
1.1输入
- 语法:read -参数
-p:给出提示符,默认不支持”\n“换行
-s:隐藏输入的内容
-t:给出等待的时间,超出会推出read
-n:限制读取字符串的个数,触发时到临界的值会自动执行
-r:允许用户输入特殊字符,如 空格、/、\、?等
-a:赋值数组
-u:从给定文件描述符(fd=N)中读取数据
-d:表示delimiter,即定界符
-e:只用于互相交互的脚本,它将readline用于收集输入行
1.2输出
- 字体色范围:30-37
echo -e "\033[30m 黑色字 \033[0m"
echo -e "\033[31m 红色字 \033[0m"
echo -e "\033[32m 绿色字 \033[0m"
echo -e "\033[33m 黄色字 \033[0m"
echo -e "\033[34m 蓝色字 \033[0m"
echo -e "\033[35m 紫色字 \033[0m"
echo -e "\033[36m 天蓝字 \033[0m"
echo -e "\033[37m 白色字 \033[0m"
- 字背景颜色范围:40-47
echo -e "\033[40;37;5m 我们一起晒月亮!!! \033[0m"
echo -e "\033[41;30;5m 我们一起晒月亮!!! \033[0m"
echo -e "\033[42;34;5m 我们一起晒月亮!!! \033[0m"
echo -e "\033[43;34;5m 我们一起晒月亮!!! \033[0m"
echo -e "\033[44;30;5m 我们一起晒月亮!!! \033[0m"
echo -e "\033[45;30;5m 我们一起晒月亮!!! \033[0m"
echo -e "\033[46;30;5m 我们一起晒月亮!!! \033[0m"
echo -e "\033[47;34;5m 我们一起晒月亮!!! \033[0m"
echo -e "\033[41;30;5m 我们一起晒月亮!!! \033[0m"
- 特效
echo -e "\033[0m 无任何特效 \033[0m"
echo -e "\033[1m 高亮度 \033[0m"
echo -e "\033[4m 下划线 \033[0m"
echo -e "\033[5m 闪烁 \033[0m"
echo -e "\033[7m 反显 \033[0m"
echo -e "\033[8m 消隐 \033[0m"
echo -e "\033[nA 光标上移n行 \033[0m"
echo -e "\033[nB 光标下移n行 \033[0m"
echo -e "\033[nC 光标右移n字符 \033[0m"
echo -e "\033[nD 光标左移n字符 \033[0m"
echo -e "\033[y;xH 设置光标位置 \033[0m"
echo -e "\033[2J 清屏 \033[0m"
echo -e "\033[K 清除从光标到行尾的内容 \033[0m"
echo -e "\033[s 保存光标位置 \033[0m"
echo -e "\033[u 恢复光标位置 \033[0m"
echo -e "\033[?25l 隐藏光标 \033[0m"
echo -e "\033[?25h 显示光标 \033[0m"
2.循环控制语句
2.1 if循环控制(单分支与多分支)
2.1.1单个判断
语法:
if [ 执行条件 ]
then
执行语句
fi
2.1.2单个判断带else
语法:
if [ 执行条件 ]
then
执行语句
else
执行语句
fi
2.1.3多个判断
语法:
if [ 执行条件 ]
then
执行语句
elif [ 执行条件 ]
执行语句
.....
fi
2.2 for循环控制
语法1:
for 变量名 in 值1 值2 值3 ....
do
执行语句
done
语法2:
for i in {1..5}
do
echo $i
done
不同命令解释器的执行效果:
注意:
从 ubuntu 6.10 开始,ubuntu 就将先前默认的bash shell 更换成了dash shell;其表现为 /bin/sh 链接倒了/bin/dash而不是传统的/bin/bash。在ubuntu下打印:echo $SHELL 输出bash,会误导人。dash不支持这种C语言格式的for循环写法。
解决办法:
1、将默认shell更改为bash。(bash支持C语言格式的for循环)
sudo dpkg-reconfigure dash
在选择项中选No
2、直接使用bash检测:
bash -n xxx.sh
3、为了确保shell脚本的可移植性,直接更改shell脚本,使用shell支持的for循环格式:
for a inseq $num
语法3:
for((初值;条件;步长))
do
命令序列
done
2.3 while循环控制
语法:
while [ 执行条件 ]
do
执行语句
done
2.4 case循环控制
语法:
case 变量 in
值1)
执行动作1
;;
值2)
执行动作2
;;
值3)
执行动作3
;;
....
esac
3.函数与模块化
3.1 函数的定义与调用
函数定义
- 在Bash中,可以使用“function”关键字或者省略关键字的方式来定义函数。
示例:
#使用 function 关键字定义函数]
function functest1 {
echo this is test1
}
#省略 function 关键字
functest2() {
echo this is test2
}
函数调用
- 函数调用时需要使用函数名和参数列表,参数之间用空格分隔。
示例:
functest1
functest2
3.2 函数参数与返回值
传递参数
- 在Bash中,可以通过位置变量来传递参数。例如,$1 表示第一个参数,$2 表示第二个参数,以此类推。
- 在函数内部也可以使用特殊变量 $@ 或 $* 来获取所有传递的参数。
示例:
function functest1 {
echo $1 $2 !
}
functest2() {
echo Arguments:$@
}
functest1 Hello World
functest2 one two three
返回值
- 在Bash中,函数返回值可以使用“return”命令来设置,返回值为一个非负整数。
示例:
functest2() {
echo Arguments:$@
return 9
}
functest2 one two three
echo functest2 return $?
3.3 模块化编程
脚本分离
- 在Bash中,可以将脚本分解成多个文件,以实现模块化编程。
示例:
# 文件名:libfunc.sh
#!/bin/bsh
testfunc1() {
echo this is testfunc1!
}
-----------------------------------
# 文件名:main.sh
#!/bin/ksh
source libfunc.sh
testfunc1
运行结果:
模块导入与使用
- 在Bash中,可以通过“source”或“.”命令来导入其他脚本或库文件。
source libfunc.sh
或者
. libfunc.sh
这样就可以在当前脚本中使用被导入脚本中定义的函数和变量了。
四、示例
1.常用变量
示例:
#!/bin/sh
echo 当前执行的脚本为:$0
echo 第一个参数:$1
echo 第二个参数:$2
echo 第三个参数:$3
echo 第四个参数:$4
echo 输入参数总个数:$#
echo 输入的所有参数为:$*
运行符号:
2.常用符号
示例:
echo ls:`ls` #``括起来, 表示里面需要执行的是命令。Shell可以先执行``中的命令,将输出结果暂时保存,在适当的地方输出。
运行结果:
3.语法
3.1输入与输出
3.1.1输入
3.1.2输出
示例1:
示例2:
3.2循环控制语句
3.2.1 if循环控制(单分支与多分支)
示例1:
#!/bin/bash
count=0
while [ $count -lt 5 ]
do
if [ $count -eq 3 ]
then
echo -e "\033[31m$count\033[0m"
else
echo -e "\033[32m$count\033[0m"
fi
count=$((count + 1))
done
运行结果:
3.2.2 for循环控制
示例1:
#!/bin/sh
for i in 1 2 3 4 5 6
do
echo $i
done
运行结果:
示例2:
#!/bin/sh
for i in {1..10..2}
do
echo $i
done
运行结果:
示例3:
#!/bin/sh
for((i=0;i<=10;i++))
do
echo $i
done
运行结果:
3.2.3 while循环控制
示例1:
#!/bin/bash
count=0
while [ $count -lt 5 ]
do
if [ $count -eq 3 ]
then
echo -e "\033[31m$count\033[0m"
else
echo -e "\033[32m$count\033[0m"
fi
count=$((count + 1))
done
运行结果:
3.2.4 case循环控制
示例1:
#!/bin/sh
case $1 in
1)
echo this is 1!
;;
2)
echo this is 2!
;;
*)
echo this is default
;;
esac
运行结果:
示例2:
# 文件名:test.sh
#!/bin/bash
. output.sh
print $1 $2 $3 $4 $5 $6 $7 $8 $9
---------------------------------
# 文件名:output.sh
#!/bin/bash
print() {
case $# in
4)
echo -e "\033[$2;$3;${4}m$1 \033[0m"
;;
5)
echo -e "\033[$2;$3;$4;${5}m$1 \033[0m"
;;
6)
echo -e "\033[$2;$3;$4;$5;${6}m$1 \033[0m"
;;
7)
echo -e "\033[$2;$3;$4;$5;$6;${7}m$1 \033[0m"
;;
8)
echo -e "\033[$2;$3;$4;$5;$6;$7;${8}m$1 \033[0m"
;;
9)
echo -e "\033[$2;$3;$4;$5;$6;$7;$8;${9}m$1 \033[0m"
;;
*)
echo -e "\033[$2;$3;$4;$5;0m$1 \033[0m"
;;
esac
}
运行结果:
总结
总之,学习Shell编程可以为我们的工作和生活带来许多便利和效益。虽然需要一定的时间和精力投入,但是一旦掌握了这门技能,我们就可以更加高效地完成各种任务,提高自己的竞争力和职业发展前景。