通过 Shell 中的各种命令, 开发者和运维人员可以对服务器进行维护工作。
但每次都手动输入命令, 工作效率太低, 而且很容易出错, 尤其是需要维护大量服务器时。
为了能够对服务器批量执行操作, 我们可以将需要执行的命令写入文件, 批量执行, 这种文件便是 Shell 脚本。
Shell 脚本一般是以 .sh
结尾的文本文件, 当然, 也可以省略扩展名。
脚本文件第一行通过注释的方式指明执行脚本的程序。
在 Shell 脚本中, #
开头的文本是注释, 但第一句 #!
开头的这句话比较特殊, 他会告诉 Shell 应该使用哪个程序来执行当前脚本。
常见方式有:
#!/bin/sh
#!/bin/bash
#!/usr/bin/env bash
Python 脚本的第一句一般是 #!/usr/bin/env python
创建 cpu-count.sh 文件
将下面文本写入 cpu-count.sh 中
#!/bin/bash
echo "Hello"
echo "I am `whoami`"
echo "I love Linux"
echo "The CPU in my PC has `cat /proc/cpuinfo |grep -c processor` cores"
exit 0
执行 chmod a+x cpu-count.sh
对脚本授予可执行权限
输入 ./cpu-count.sh
执行脚本
查看脚本的退出状态: echo $?
定义
变量的定义与其他语言差距不大, 需要注意的是赋值前后没有空格。
# 变量定义: 等号前后没有空格
a=12345
b=xyz
使用变量时, 变量名前面加上 $
符
echo "---$a---\n===$b==="
printf "---$a---\n===$b===\n"
echo "---$a---\n===$b==="
echo '---$a---\n===$b==='
定义当前Shell下的全局变量
定义: export ABC=9876543210123456789
定义完后, 在终端里用 source 加载脚本: source ./test.sh
常用的系统环境变量
$PATH
: 可执行文件目录$PWD
: 当前目录$HOME
: 家目录$USER
: 当前用户名$UID
: 当前用户的 uidread -p "请输入一个数字:" num
echo "您输入的是:$num"
在shell里支持三种引号,它们的使用场景以及效果会有差异。
echo `ls -a /home/chris` # 打印 /home/chris目录下的所有文件和文件夹
name=zhangsan
echo "大家好,我是$name" # 大家好,我是zhangsan
name=zhangsan
echo '大家好,我是$name' # 大家好,我是$name
name=zhangsan
echo ${name} # zhangsan
echo $name # zhangsan
$# 代表传入参数的个数
$@ 代表传入参数的列表
$0 代表脚本本身
$1 代表传入的第一个参数,$2,$3...以此类推
$* 以字符串方式显示所有传入的参数
$$ 脚本运行的进程ID
$? 显示最后命令的退出状况,0表示没有错误
echo $(ls /home/wubantu/Desktop) # 列出当前用户的桌面上的所有文件和文件夹
echo $((1+1)) # 2
1 #!/bin/bash
2 read -p "请输入一个字符串:" str
3 echo "您输入的字符串是:"$str
4
5 name=zhangsan
6
7 echo "您的名字是:"$name
8 echo "传入参数的个数是:"$#
9 echo "传入参数的列表是:"$@
10 echo "传入脚本本身是:"$0
11 echo "传入的第一个参数是:"$1
12 echo "脚本运行的进程ID是:"$$
13 echo "显示最后命令的退出状况是:"$?
14
15 echo "列出用户桌面上所有文件夹和文件"$(ls /home/wubantu/Desktop)
16
17 echo "1+1的值是:"$((1+1))
# 结果是:
请输入一个字符串:hello
您输入的字符串是:hello
您的名字是:zhangsan
传入参数的个数是:0
传入参数的列表是:
传入脚本本身是:bash
传入的第一个参数是:
脚本运行的进程ID是:6054
显示最后命令的退出状况是:0
列出用户桌面上所有文件夹和文件
1+1的值是:2
if
分支控制语句完整格式为:
if command;then
commands
elif command;then
commands
else
commands
fi
if
语句检查判断的依据实际上是, 后面所跟的命令的状态码: 0 为 true, 其他值 为 false if ls /xxx;then
echo 'exist xxx'
else
echo 'not exist xxx'
fi
[ ... ]
shell 提供了一种专用做条件测试的语句 [ ... ]
这一对方括号本质上是一个命令, 里面的条件是其参数, 所以 [
的后面和 ]
的前面必须有空格, 否则会报错。
他可以进行三种比较
用法:
if [ condition ];then
commands
fi
3.条件列表
数值比较
Condition | 说明 |
---|---|
n1 -eq n2 | 检查n1是否与n2相等 |
n1 -ge n2 | 检查n1是否大于或等于n2 |
n1 -gt n2 | 检查n1是否大于n2 |
n1 -le n2 | 检查n1是否小于n2 |
n1 -lt n2 | 检查n1是否小于n2 |
n1 -ne n2 | 检查n1是否不等于n2 |
字符串比较
Condition | 说明 |
---|---|
str1 = str2 | 检查str1是否和str2相同(注意:等号两边要加空格) |
str1!=str2 | 检查str1是否和str2不同 |
str1检查str1是否小于str2(需要使用[[]]) |
|
str1>str2 | 检查str1是否大于str2(需要使用[[]]) |
-n str1 | 检查str1的长度是否非0(变量需要添加双引号) |
-z str1 | 检查str1的长度是否为0 |
文件比较
Condition | 说明 |
---|---|
-d file | 检查file是否存在并且是一个目录 |
-e file | 检查file是否存在 |
-f file | 检查file是否存在并且是一个文件 |
-r file | 检查file是否存在并且可读 |
-w file | 检查file是否存在并且可写 |
-x file | 检查file是否存在并且可执行 |
-s file | 检查file是否存在并且非空 |
-O file | 检查file是否存在并且属于当前用户所有 |
-G file | 检查file是否存在并且所属组与当前用户相同 |
file1 -nt file2 | 检查file1是否比file2新 |
file1 -ot file2 | 检查file1是否比file2旧 |
case "$var" in
exp1)
command1
;;
exp2)
command2
;;
exp3)
command3
;;
*)
comman4
;;
esac
例子:
#!/bin/bash
read -p "请输入数字:" num
case $num in
0)
echo 星期日
;;
1)
echo 星期一
;;
2)
echo 星期二
;;
3)
echo 星期三
;;
4)
echo 星期四
;;
5)
echo 星期五
;;
6)
echo 星期六
;;
*)
echo 其他
;;
esac
# 结果
请输入数字:2
星期二
for 变量 in 序列
do
要执行的命令
done
for i in `seq 1 10`
do
if [ $[ $i % 2] == 0 ]
then
echo "偶数: $i"
else
echo "奇数: $i"
fi
done
结果:
奇数: 1
偶数: 2
奇数: 3
偶数: 4
奇数: 5
偶数: 6
奇数: 7
偶数: 8
奇数: 9
偶数: 10
seq START END
语句用来产生一个数字序列$[ NUM1 + NUM2 ]
语句用来进行基本的数学运算[[ ... ]]
语句用来更方便的进行比较判断 for ((i=0; i<10; i++))
do
echo "num is $i"
done
结果:
num is 0
num is 1
num is 2
num is 3
num is 4
num is 5
num is 6
num is 7
num is 8
num is 9
函数定义
定义时 function
不是必须的,可以省略
function foo() {
echo "---------------------------"
echo "Hello $1, nice to meet you!"
echo "---------------------------"
}
在终端或脚本中直接输入函数名即可,不需要小括号
传参也只需将参数加到函数名后面,以空格做间隔,像正常使用命令那样
foo arg1 arg2 arg3 ...
bar() {
echo "执行者是 $0"
echo "参数数量是 $#"
echo "全部的参数 $@"
echo "全部的参数 $*"
if [ -d $1 ]; then # 检查传入的第一个参数是否是文件夹
for f in `ls $1`
do
echo $f
done
elif [ -f $1 ]; then
echo "This is a file: $1" # 如果不是文件夹, 直接显示文件名
else
echo 'not valid' # 前面都不匹配显示默认语句
fi
}
bar $1
结果:
执行者是 bash
参数数量是 0
全部的参数
全部的参数
01-体验.sh
02-引号的使用.sh
03-变量的使用.sh
04-$符号的使用.sh
05-if语句的使用.sh
06-case语句
07-for语句.sh
08-C语言风格.sh
09-函数的参数.sh
hello.py
ppp
sss
test.sh
ttt
数组中可以存放多个值。Bash Shell 只支持一维数组(不支持多维数组),初始化时不需要定义数组大小。
与大部分编程语言类似,数组元素的下标由0开始
Shell 数组用括号来表示,元素用"空格"符号分割开,语法格式如下:
array_name=(value1 ... valuen)
同时,也可以直接使用下标来定义一个数组。
nums[0]=1
nums[1]="good"
nums[2]=yes
使用下标可以直接修改数组里的数据。
arr=(hello good "yes" a 12)
arr[0] = hi
使用$和下标可以获取一个数组里的数据,但是注意需要使用{}来包裹变量。
语法格式:
${arr[index]}
示例:
arr=(hello good "yes" a 12)
echo ${arr[0]}
使用*或者@作为下标,可以获取数组里的所有数据。
arr=(hello good "yes" a 12)
echo ${arr[*]}
echo ${arr[@]}
结果:
hello good yes a 12
hello good yes a 12
在获取所有数据的前面添加# 可以获取到数组的长度
arr=(hello good "yes" a 12)
echo ${#arr[*]}
echo ${#arr[@]}
结果:
5
5
数组的遍历
#!/bin/bash
arr=(hello good 12 'yes' hi)
for((i=0;i)
结果:
bash: 11-遍历数组.sh: line 4: syntax error: unexpected end of file
#!/bin/bash
arr=(hello good 12 'yes' hi)
for ele in ${arr[*]}
do
echo $ele
done
结果:
hello
good
12
yes
hi