Shell 编程在我们的日常开发工作中非常实用,目前 Linux 系统下最流行的运维自动化语言就是 Shell 和 Python 了。 这篇文章我会简单总结一下 Shell 编程基础知识,带你入门 Shell 编程!
目录
一、为什么要学 Shell?
学一个东西,我们大部分情况都是往实用性方向着想。从工作角度来讲,学习 Shell 是为了提高我们自己工作效率,提高产出,让我们在更少的时间完成更多的事情。
很多人会说 Shell 编程属于运维方面的知识了,应该是运维人员来做,我们做后端开发的没必要学。我觉得这种说法大错特错,相比于专门做 Linux 运维的人员来说,我们对 Shell 编程掌握程度的要求要比他们低,但是 Shell 编程也是我们必须要掌握的!
目前 Linux 系统下最流行的运维自动化语言就是 Shell 和 Python 了。
两者之间,Shell 几乎是 IT 企业必须使用的运维自动化编程语言,特别是在运维工作中的服务监控、业务快速部署、服务启动停止、数据备份及处理、日志分析等环节里,shell 是不可缺的。Python 更适合处理复杂的业务逻辑,以及开发复杂的运维软件工具,实现通过 web 访问等。Shell 是一个命令解释器,解释执行用户所输入的命令和程序。一输入命令,就立即回应的交互的对话方式。
另外,了解 shell 编程也是大部分互联网公司招聘后端开发人员的要求。下图是我截取的一些知名互联网公司对于 Shell 编程的要求。
二、什么是 Shell?
简单来说“Shell 编程就是对一堆 Linux 命令的逻辑化处理”。
三、shell脚本编写规范
四、Shell 编程的 Hello World
学习任何一门编程语言第一件事就是输出 HelloWorld 了!下面我会从新建文件到 shell 代码编写来说下 Shell 编程如何输出 Hello World。
(1)新建一个文件 helloworld.sh :
touch helloworld.sh
扩展名为 sh(sh 代表 Shell)(扩展名并不影响脚本执行,见名知意就好,如果你用 php 写 shell 脚本,扩展名就用 php 好了)
(2) 使脚本具有执行权限:
chmod +x helloworld.sh
(3) 使用 vim 命令修改 helloworld.sh 文件:
vim helloworld.sh
(vim 文件------>进入文件----->命令模式------>按 i 进入编辑模式----->编辑文件 ------->按 Esc 进入底行模式----->输入:wq/q! (输入 wq 代表写入内容并退出,即保存;输入 q!代表强制退出不保存。))
helloworld.sh 内容如下:
#!/bin/bash
#第一个shell小程序,echo 是linux中的输出命令。
echo "helloworld!"
shell 中 # 符号表示注释。shell 的第一行比较特殊,一般都会以#!开始来指定使用的 shell 类型。在 linux 中,除了 bash shell 以外,还有很多版本的 shell, 例如 zsh、dash 等等...不过 bash shell 还是我们使用最多的。
(4) 运行脚本:
./helloworld.sh
(注意:一定要写成 ./helloworld.sh
,而不是 helloworld.sh
,运行其它二进制的程序也一样,直接写 helloworld.sh
,linux 系统会去 PATH 里寻找有没有叫 helloworld.sh 的,而只有 /bin, /sbin, /usr/bin,/usr/sbin 等在 PATH 里,你的当前目录通常不在 PATH 里,所以写成 helloworld.sh
是会找不到命令的,要用./helloworld.sh
告诉系统说,就在当前目录找。)
五、shell变量
1 用户自定义变量
var=1 #var-test
var=$var+1
echo $var #打印的结果是什么呢?
1+1
-
在
var=$var+1
这一行中,$var+1
并不会被解释为数学运算,而是被当作字符串拼接。 -
因此,
$var+1
的值实际上是"1+1"
,而不是数字2
。
为了达到想要的效果(即输出结果是2)有以下几种表达方式:
如下面这个shell代码:
var=1 #var-test
var=$((var + 1))
echo $var
这时候输出结果就是2
2 环境变量
常用的环境变量
PATH 决定了 shell 将到哪些目录中寻找命令或程序
HOME 当前用户主目录
HISTSIZE 历史记录数
LOGNAME 当前用户的登录名
HOSTNAME 指主机的名称
SHELL 当前用户 Shell 类型
LANGUAGE 语言相关的环境变量,多语言可以修改此环境变量
MAIL 当前用户的邮件存放目录
PS1 基本提示符,对于 root 用户是#,对于普通用户是$
使用 Linux 已定义的环境变量:
查看当前用户目录:
echo $HOME
查看当前用户 Shell 类型:
echo $SHELL命令
使用自己定义的变量:
#!/bin/bash
#自定义变量hello
hello="hello world"
echo $hello
echo "helloworld!"
Shell 编程中的变量名的命名的注意事项:
- 命名只能使用英文字母,数字和下划线,首个字符不能以数字开头,但是可以使用下划线(_)开头。
- 中间不能有空格,可以使用下划线(_)。
- 不能使用标点符号。
- 不能使用 bash 里的关键字(可用 help 命令查看保留关键字)。
六、Shell 字符串入门
字符串是 shell 编程中最常用最有用的数据类型(除了数字和字符串,也没啥其它类型好用了),字符串可以用单引号,也可以用双引号。这点和 Java 中有所不同。
在单引号中:所有的特殊符号,如$和反引号都没有特殊含义。
在双引号中:除了"$"、"\"、反引号和感叹号(需开启 history expansion
),其他的字符没有特殊含义。
单引号字符串:
#!/bin/bash
name='xiaoliang'
hello='Hello, I am $name!'
echo $hello
输出内容:
Hello, I am $name!
双引号字符串:
#!/bin/bash
name='SnailClimb'
hello="Hello, I am $name!"
echo $hello
输出内容:
Hello, I am xiaoliang!
七、Shell 字符串常见操作
拼接字符串:
#!/bin/bash
name="xioaliang"
# 使用双引号拼接
greeting="hello, "$name" !"
greeting_1="hello, ${name} !"
echo $greeting $greeting_1
# 使用单引号拼接
greeting_2='hello, '$name' !'
greeting_3='hello, ${name} !'
echo $greeting_2 $greeting_3
输出结果:
hello, xioaliang ! hello, xioaliang !
hello, xioaliang ! hello, ${name} !
获取字符串长度:
#!/bin/bash
#获取字符串长度
name="xiaoliang"
# 第一种方式
echo ${#name} #输出 9
# 第二种方式
expr length "$name";
输出结果:
9
9
使用 expr 命令时,表达式中的运算符左右必须包含空格,如果不包含空格,将会输出表达式本身:
expr 6+6 // 直接输出 5+6
expr 6 + 6 // 输出 12
对于某些运算符,还需要我们使用符号\
进行转义,否则就会提示语法错误。
expr 6 * 6 // 输出错误
expr 6 \* 6 // 输出36
截取子字符串:
简单的字符串截取:
#从字符串第 1 个字符开始往后截取 9 个字符
str="xiaoliang is a great man"
echo ${str:0:9} #输出:xiaoliang
八、Shell 数组
bash2.x以上 支持一维数组(不支持多维数组),下标从0开始,并且没有限定数组的大小。
1 使用 declare -a
声明数组
在 Bash 中,可以使用 declare -a
来显式地声明一个数组变量。-a
选项告诉 declare
命令将变量声明为数组类型。声明后,可以通过多种方式为数组赋值。
#!/bin/bash
# 声明一个数组变量
declare -a variable
# 直接赋值
variable=("item1" "item2" "item3")
# 打印数组的所有元素
echo "数组的所有元素: ${variable[@]}"
直接赋值给数组
在 Bash 中,也可以不使用 declare -a
声明,直接通过赋值语句创建数组。
#!/bin/bash
# 直接创建并赋值数组
variable=("apple" "banana" "cherry")
# 打印数组的所有元素
echo "数组的所有元素: ${variable[@]}"
按索引赋值
可以通过指定数组的索引来为特定位置的元素赋值。数组的索引从 0 开始。
#!/bin/bash
# 声明并赋值数组
variable=("red" "green" "blue")
# 引用数组的第一个元素(索引为0)
first_element=${variable[0]}
echo "数组的第一个元素: $first_element"
# 引用数组的第二个元素(索引为1)
second_element=${variable[1]}
echo "数组的第二个元素: $second_element"
2 引用所有元素
可以使用 ${variable[@]}
或 ${variable[*]}
来引用数组的所有元素。两者的主要区别在于,当在双引号中使用时,"${variable[@]}"
会将数组的每个元素作为一个单独的单词传递,而 "${variable[*]}"
会将数组的所有元素合并成一个单词。
如下面代码:
#!/bin/bash
variable=("word1" "word2" "word3")
for i in "${variable[@]}"; do
echo "Using @, current element: $i"
done
for i in "${variable[*]}"; do
echo "Using *, current element: $i"
done
输出结果为:
Using @, current element: word1
Using @, current element: word2
Using @, current element: word3
Using *, current element: word1 word2 word3
下面给大家一个关于数组操作的 Shell 代码示例,通过该示例大家可以知道如何创建数组、获取数组长度、获取/删除特定位置的数组元素、删除整个数组以及遍历数组。
#!/bin/bash
array=(1 2 3 4 5);
# 获取数组长度
length=${#array[@]}
# 或者
length2=${#array[*]}
#输出数组长度
echo $length #输出:5
echo $length2 #输出:5
# 输出数组第三个元素
echo ${array[2]} #输出:3
unset array[1]# 删除下标为1的元素也就是删除第二个元素
for i in ${array[@]};do echo $i ;done # 遍历数组,输出:1 3 4 5
unset array; # 删除数组中的所有元素
for i in ${array[@]};do echo $i ;done # 遍历数组,数组元素为空,没有任何输出内容
九、Shell 基本运算
Shell 编程支持下面几种运算符
- 算数运算符
- 关系运算符
- 布尔运算符
- 字符串运算符
- 文件测试运算符
算数运算符
a=10,b=20
以减法运算符做一个简单的示例(注意:不是单引号,是反引号):
#!/bin/bash
a=3;b=3;
val=`expr $a - $b`
echo "Total value : $val" #输出:Total value : 0
关系运算符
关系运算符只支持数字,不支持字符串,除非字符串的值是数字。
通过一个简单的示例演示关系运算符的使用:
#!/bin/bash
score=90;
maxscore=100;
if [ $score -eq $maxscore ]
then
echo "A"
else
echo "B"
fi
输出结果:
B
逻辑运算符
#!/bin/bash
a=$(( 1 && 0))
echo $a;# 输出:0
逻辑与运算只有相与的两边都是1,与的结果才是1;否则与的结果是0
字符串运算符
下面举一个简单例子:
#!/bin/bash
a="hello"
b="world"
# 检测两个字符串是否相等
if [ "$a" = "$b" ]; then
echo "Strings are equal."
else
echo "Strings are not equal."
fi
# 检测两个字符串是否不相等
if [ "$a" != "$b" ]; then
echo "Strings are not equal."
fi
# 检测字符串长度是否为0
empty_str=""
if [ -z "$empty_str" ]; then
echo "String is empty."
fi
# 检测字符串长度是否不为0
non_empty_str="not empty"
if [ -n "$non_empty_str" ]; then
echo "String is not empty."
fi
# 检测字符串是否为空(另一种写法)
if [ "$str" ]; then
echo "String is not null."
fi
输出:
Strings are not equal.
Strings are not equal.
String is empty.
String is not empty.
文件相关运算符
举例:
file_path="/path/to/file.txt"
# 检查文件是否存在
if [ -e "$file_path" ]; then
echo "File exists."
fi
# 检查文件是否是普通文件
if [ -f "$file_path" ]; then
echo "It's a regular file."
fi
# 检查文件是否有可执行权限
if [ -x "$file_path" ]; then
echo "File is executable."
fi
十、shell流程控制
If 条件语句
假设我们要根据数字的大小输出不同的信息:
#!/bin/bash
number=10
if [ $number -lt 10 ]; then
echo "数字小于10"
elif [ $number -eq 10 ]; then
echo "数字等于10"
else
echo "数字大于10"
fi
输出结果:
数字等于10
For 循环语句
下面是打印数字1到5的例子:
#!/bin/bash
for i in 1 2 3 4 5
do
echo "数字是:$i"
done
输出结果:
数字是:1
数字是:2
数字是:3
数字是:4
数字是:5
While 循环语句
使用while循环打印数字1到5:
#!/bin/bash
count=1
while [ $count -le 5 ]
do
echo "数字是:$count"
let count+=1
done
输出结果:
数字是:1
数字是:2
数字是:3
数字是:4
数字是:5
Shell 函数
一个简单的函数,用于打印问候语:
#!/bin/bash
greet() {
echo "你好,$1!"
}
greet "世界"
输出结果:
你好,世界!
一个带参数的函数,计算两个数字的和:
#!/bin/bash
add() {
local num1=$1
local num2=$2
local sum=$((num1 + num2))
echo "数字 $num1 和$num2 的和是:$sum"
}
add 3 4
输出结果:
数字 3 和 4 的和是:7