1.入门
[root@localhost /]# mkdir ./scripts/
[root@localhost /]# cd ./scripts/
[root@localhost scripts]# touch hello.sh
[root@localhost scripts]# vim hello.sh
hello.sh
#!/bin/bash/
echo "你好,世界"
[root@localhost scripts]# ls
hello.sh
[root@localhost scripts]# sh ./hello.sh
你好,世界
[root@localhost scripts]# bash ./hello.sh
你好,世界
#或者,加可执行权限,再直接./hello.sh 执行
#第一种是在子bash环境下运行,第二种是在当前bash环境下运行
#运行#type source 可以看到source是shell一个内嵌
#子bash中设置变量,父bash不可见
[root@localhost scripts]# chmod +x hello.sh
[root@localhost scripts]# ./hello.sh
你好,世界
[root@localhost scripts]# source ./hello.sh
你好,世界
2.变量
全局变量:嵌套的子bash可以访问
局部变量:只有当前bash能访问,父、子bash均不能访问
常用系统变量
$HOME、$PWD、$SHELL、$USER
查看当前所有系统变量 env
查看当前所有变量 set
3.用户自定义变量
语法,name=value
=左右不能有空格;声明变量无需$,但是使用时需要$;定义字符串需要引号
[root@localhost scripts]# amax=1000
[root@localhost scripts]# bmax="你好 星期三"
[root@localhost scripts]# echo $amax $bmax
1000 你好 星期三
[root@localhost scripts]# env | grep amax
[root@localhost scripts]# set | grep amax
amax=1000
#set看变量是否为局部变量,env是全局变量
#用法 set | grep 变量名
通过export 变量名声明全局变量
子bash中修改父bash的全局变量,只会在当前环境下生效,父bash中还是原样不会被修改
4.只读变量和撤销变量
弱类型,理解成全都是字符串,要进行数值运算,使用$((a+b))、$[a+b]
[root@localhost scripts]# hello=10+10
[root@localhost scripts]# echo $hello
10+10
[root@localhost scripts]# hello=$((10+10))
[root@localhost scripts]# echo $hello
20
[root@localhost scripts]# hello=$[10+20]
[root@localhost scripts]# echo $hello
30
只读变量:readonly声明后,不许修改
[root@localhost scripts]# readonly hello=111
[root@localhost scripts]# echo $hello
111
[root@localhost scripts]# hello=1234
-bash: hello: 只读变量
撤销变量:定义后可以unset撤销,只读变量不能撤销
[root@localhost scripts]# age=18
[root@localhost scripts]# echo $age
18
[root@localhost scripts]# unset age
[root@localhost scripts]# echo $age
[root@localhost scripts]# unset hello
-bash: unset: hello: 无法反设定: 只读 variable
5.特殊变量
$n代表可接受参数,n是数字,$1-9,表示第1-9个参数,10以上用${10},$0表示当前脚本名称
hello.sh
#!/bin/bash
echo "你好,$1"
[root@localhost scripts]# ./hello.sh 小王
你好,小王
hello.sh
$n 用单引号,表示字符串,而不是变量
#!/bin/bash/
echo '$n'
echo 1st:$1
echo 2nd:$2
echo $0
[root@localhost scripts]# ./hello.sh
$n
1st:
2nd:
./hello.sh
[root@localhost scripts]# ./hello.sh 王 李
$n
1st: 王
2nd: 李
./hello.sh
$# 获取输入参数个数
hello.sh
#!/bin/bash/
echo '$n'
echo 1st:$1
echo 2nd:$2
echo $0
echo $#
[root@localhost scripts]# ./hello.sh
$n
1st:
2nd:
./hello.sh
0
[root@localhost scripts]# ./hello.sh 王 李
$n
1st: 王
2nd: 李
./hello.sh
2
$*,$@,代表命令行所有参数,$*把参数1234 456 看作一个整体,$@ 把每个数据分开,换行显示 没有循环遍历时,二者效果一致。
$? 最后一次执行命令的状态
命令正确执行,返回0。非零就是运行错误
[root@localhost scripts]# echo $?
0
[root@localhost scripts]# hello.sh
bash: hello.sh: 未找到命令...
[root@localhost scripts]# echo $?
127
6.运算符
表达式expr,expr 10 + 10,其中10,+,10分别时表达式三个参数。要有空格,不能写成expr 10+10。乘不能直接写*,因为其通常是作为通配符,表示0或多个字符,要转义\*,如expr 10 \* 5。
赋值给变量时用a=$(expr 10 + 5),或者a =`expr 12 + 12`
$((10 + 123))或者$[ 11 * 22 ]也可以实现
()或者[]中不需要转义\*,是因为括号里并没有进行数学运算,在expr表达式里就需要转义,因为它执行了数学运算。
[root@localhost scripts]# expr 10+10
10+10
[root@localhost scripts]# expr 10 + 10
20
[root@localhost scripts]# expr 10 * 3
expr: 语法错误
[root@localhost scripts]# expr 10 \* 3
30
[root@localhost scripts]# c=expr 10 + 15
bash: 10: 未找到命令...
[root@localhost scripts]# c="expr 10 + 15"
[root@localhost scripts]# echo $c
expr 10 + 15
[root@localhost scripts]# c=$(expr 10 + 15)
[root@localhost scripts]# echo $c
25
[root@localhost scripts]# s=$[(5 + 5) * 9]
[root@localhost scripts]# echo $s
90
7.条件判断
等于 =
test $a = 10,=前后加空格,避免被解析成一个整体
[ a = b ],前后必须有空格
不等于 !=
[root@localhost scripts]# a=10
[root@localhost scripts]# test $a = 10
[root@localhost scripts]# echo $?
0
[root@localhost scripts]# test $a = 11
[root@localhost scripts]# echo $?
1
[root@localhost scripts]# test $a=11
[root@localhost scripts]# echo $?
0
[root@localhost scripts]# [ $a = 11 ]
[root@localhost scripts]# echo $?
1
[root@localhost scripts]# [ $a=11 ]
[root@localhost scripts]# echo $?
0
[root@localhost scripts]# [ $a != 11 ]
[root@localhost scripts]# echo $?
0
[root@localhost scripts]# [ $a!=10 ]
[root@localhost scripts]# echo $?
0
两个值比较
-eq | equal | -ne | not equal |
-lt | less than | -le | less equal |
-gt | greater than | -ge | greater equal |
用法:[ $a -eq $b ]
[root@localhost ~]# a=10
[root@localhost ~]# b=10
[root@localhost ~]# [ $a -eq $b ]
[root@localhost ~]# echo $?
0
[root@localhost ~]# a=20
[root@localhost ~]# [ $a -ne $b ]
[root@localhost ~]# echo $?
0
[root@localhost ~]# [ $a -le $b ]
[root@localhost ~]# echo $?
1
[root@localhost ~]# [ $a -ge $b ]
[root@localhost ~]# echo $?
0
文件权限判断
-r,-w,-x,读写执行
[root@localhost scripts]# [ -r yunsuan.sh ]
[root@localhost scripts]# echo $?
0
文件类型判断
-e,文件是否存在
-f,存在且是file类型
-d,存在且是directory类型
[root@localhost scripts]# [ -e yunsuan.sh ]
[root@localhost scripts]# echo $?
0
[root@localhost scripts]# [ -f yunsuan.sh ]
[root@localhost scripts]# echo $?
0
[root@localhost scripts]# [ -d yunsuan.sh ]
[root@localhost scripts]# echo $?
1
多条件判断
&&,与,两者都成立
||,或,二者有一成立。第一个条件失败后再执行第二个条件的判断
[root@localhost scripts]# [ -e yunsuan.sh ] && [ 10 -ge 10 ]
[root@localhost scripts]# echo $?
0
衍生:类似三元运算符
&& ||,如:
[root@localhost scripts]# [ $a -eq $b ] && echo "$a=$b" || echo "$a!=$b"
20!=10
8.流程控制
if条件判断,格式:
if [条件]; then
语句;
fi
#或者
if [条件]
then
语句
fi
[root@localhost scripts]# if [ $a != 10 ]; then echo "ok"; fi
ok
第二种要以文件方式才可运行
#!/bin/bash
if [ "$1"x != "10"x ]
then
echo "ok"
fi
多条件判断时&&,||不能写在中括号[]里,但是可以用-a,-o连接,and,or
[root@localhost scripts]# if [ $a = 20 -a $b = 10 ]; then echo "ok"; fi
ok
[root@localhost scripts]# if [ $a = 10 -o $b = 10 ]; then echo "ok"; fi
ok
if else,条件分支
#!/bin/bash
if [ "$1" -lt 18 ]
then
echo "未成年"
else
echo "成年人"
fi
if elif else,多分支
#!/bin/bash
if [ "$1" -lt 18 ]
then
echo "未成年"
elif [ "$1" -lt 35 ]
then
echo "青年"
elif [ "$1" -lt 65 ]
then
echo "壮年"
else
echo "老年"
fi
case,多条件分支
case "$1" in
1)
echo "value is 1"
;;
2)
echo "value is 2"
;;
3)
echo "value is 3"
;;
*)
echo "其他数字"
;;
esac
for循环
#!/bin/bash
sum=0
# 双小括号里面可以使用运算符<=
for (( i=0; i<=100; i++ ))
do
# 或者sum=$[ $sum+$i ],不过推荐下面这种写法
sum=$(( sum + i ))
done
echo $sum
for in
#!/bin/bash
for os in linux windows macos
do
echo $os
done
内部运算符{},
{}表示一个序列,从1到100可以表示为{1..100}
#!/bin/bash
for i in {1..100}
do
sum=$((sum+i))
done
echo $sum
$*,$@
#!/bin/bash
echo '=======$*========'
for param in "$*"
do
echo $param
done
echo '=======$@========'
for param in "$@"
do
echo $param
done
运行结果:
[root@localhost scripts]# ./for4_test.sh 10 20 30
=======$*========
10 20 30
=======$@========
10
20
30
while循环
#!/bin/bash
i=0
sum=0
while [ $i -le 100 ]
do
sum=$((sum + i))
i=$((i+1))
# 可以用let,如let sum+=i
# let i++
done
echo $sum
9.读取控制台输入
read 选项 参数
选项:
-p,提示信息
-t,等待时间,秒。不添加-t表示一直等待
参数:
变量:指定读取变量名
#!/bin/bash
read -t 10 -p "input a name:" name
echo "welcome, $name"
10.系统函数
date,
获取时间戳date +%s,date后加空格是要把+%s传递给date,不加空格表示date+%s是一个字符串
[root@localhost scripts]# cat sy_fun_test.sh
#!/bin/bash
filename="$1_log_$(date +%s)"
echo $filename
[root@localhost scripts]# ./sy_fun_test.sh file.sh
file.sh_log_1710361088
basename
获取文件名,basename [string/pathname][suffix]
至少有一个路径的/符号,只会截取/后面的内容。suffix表示要去掉的后缀名。
[root@localhost scripts]# basename /scripts/cmd_test.sh
cmd_test.sh
[root@localhost scripts]# basename /abc/def/cmd_test.sh
cmd_test.sh
[root@localhost scripts]# basename /abc/def/cmd_test.sh .sh
cmd_test
$0,获取当前文件名,带路径的,相对、绝对路径
[root@localhost scripts]# cat basename_test.sh
#!/bin/bash
echo '======$0====='
echo "当前文件名:$(basename $0 .sh)"
[root@localhost scripts]# ./basename_test.sh
======$0=====
当前文件名:basename_test
dirname
获取绝对路径,去掉文件名
[root@localhost scripts]# dirname /scripts/basename_test.sh
/scripts
[root@localhost scripts]# cat basename_test.sh
#!/bin/bash
echo '======$0====='
echo "当前文件名:$(basename $0 .sh)"
# cd先切换到脚本所在目录。pwd只会打印当前目录绝对路径。
echo "当前路径名:$(cd $(dirname $0); pwd)"
[root@localhost scripts]# ./basename_test.sh
======$0=====
当前文件名:basename_test
当前路径名:/scripts
[root@localhost scripts]# /scripts/basename_test.sh
======$0=====
当前文件名:basename_test
当前路径名:/scripts
11.自定义函数
语法
function 函数名(){
//函数体
return 返回值
}
[root@localhost scripts]# cat fn_test.sh
#!/bin/bash
function add(){
sum=$(($1 + $2))
echo "the sum is $sum"
}
read -p "input param1:" a
read -p "input param2:" b
add $a $b
# 运行结果
[root@localhost scripts]# ./fn_test.sh
input param1:11
input param2:22
the sum is 33
可以使用$?获取返回值,但是返回值只能是0~255
#!/bin/bash
function add(){
sum=$(($1 + $2))
echo $sum
}
read -p "input param1:" a
read -p "input param2:" b
sum=$(add $a $b)
echo "the sum is $sum"
echo "the square of sum is $(($sum * $sum))"
# 结果
[root@localhost scripts]# ./fn_test.sh
input param1:1000
input param2:2000
the sum is 3000
the square of sum is 9000000
12.归档文件
需求:目录归档脚本,input一个目录名称,将目录下所有文件按天归档保存,并将归档日期附加在文档文件名上,放在根目录下(/archive)
归档命令:tar,-c归档,-z压缩文件
#!/bin/bash
# 判断输入参数个数
if [ $# != 1 ]
then
echo "参数个数错误"
exit
fi
# 查看输入路径参数是否存在
if [ -d $1 ]
then
echo "检测到目录"
else
echo
echo "路径不存在"
echo
exit
fi
# 获取文件绝对路径
dir_name=$(basename $1)
dir_path=$(cd $(dirname $1); pwd)
# 获取当前日期
date=$(date +%Y%m%d) # 使用 %Y 获取四位年份
# 归档文件名
file=archive_${dir_name}_$date.tar.gz # 修正了命令替换和变量引用
# 生成归档文件的路径
dest=/archive/$file
# 开始归档
tar -czf $dest $dir_path/$dir_name # 修正了变量名
# 判断归档是否成功
if [ $? -eq 0 ]
then
echo "归档成功"
echo "归档的文件为$dest"
else
echo "归档失败"
fi
13.定时归档
crontab
命令:
crontab -l
: 列出当前用户的crontab
文件内容。crontab -e
: 编辑当前用户的crontab
文件。crontab -r
: 删除当前用户的crontab
文件。
[root@localhost scripts]# crontab -e
*/1 * * * * date >> /scripts/crontab_test.txt
0 2 * * * /scripts/delay_archive.sh /scripts
#分钟,小时,日,月,周,其中/1表示每隔1分钟
# 每天2点执行一次归档
14.正则
cat /etc/passwd | grep root
常用特殊字符:
^,匹配一行的开头
cat /etc/passwd | grep ^a
$,匹配一行的结束
cat /etc/passwd | grep a$
^$,匹配空字符
[root@localhost scripts]# cat delay_archive.sh | grep -n ^$
27:
38:
39:
40:
.,任意一个字符
cat /etc/passwd | grep r..t
*,前一个字符出现0次或多次
cat /etc/passwd | grep r.*t
[],范围
cat /etc/passwd | grep r[a-z]*t
\,转义,在如下实例中,只能用单引号',不能用双引号“,会被转义。
单引号会保留字符串内所有字符的字面值,所以grep '\$'
是正确的用法来匹配包含美元符号的行
[root@localhost scripts]# cat delay_archive.sh | grep '\$'
if [ $# != 1 ]
if [ -d $1 ]
dir_name=$(basename $1)
dir_path=$(cd $(dirname $1); pwd)
date=$(date +%y%m%d)
file=archive_${dir_name}_$date.tar.gz
dest=/archive/$file
tar -czf $dest $dir_path/$dir_name
if [ $? -eq 0 ]
echo "归档的文件为$dest"
匹配手机号
-E
选项用于启用扩展正则表达式(Extended Regular Expressions),这允许你使用更多的正则表达式功能,比如 +
、?
、{}
和 |
等
[root@localhost scripts]# echo "14747696666" | grep -E '^1[3-9][0-9]{9}$'
14747696666
15.cut文本处理工具
cut 选项参数 filename
选项参数 | 功能 |
-f | 列号,取第几列 |
-d | 分隔号,指定分隔号固定分隔,默认是\t |
-c |
[root@localhost scripts]# cut -d " " -f 1 custs_test.txt
程
序
员
你
好
[root@localhost scripts]# cat /etc/passwd | grep bash$
root:x:0:0:root:/root:/bin/bash
www:x:1000:1000::/home/www:/bin/bash
[root@localhost scripts]# cat /etc/passwd | grep bash$ | cut -d ":" -f 1,7
root:/bin/bash
www:/bin/bash
# 5-,表示6-7列,包括7
[root@localhost scripts]# cat /etc/passwd | grep bash$ | cut -d ":" -f 5-
root:/root:/bin/bash
:/home/www:/bin/bash
# 裁剪ip
[root@localhost scripts]# ifconfig ens33 | grep netmask | cut -d " " -f 10
192.168.199.154