全局变量与局部变量
bash ./hello.sh
和 sh ./hello.sh
在子bash环境下运行
source hello.sh
和 . hello.sh
在当前bash环境下运行
shell中变量的本质是在内存中开辟一个空间用来临时存储数据,具体包括:
全局变量、局部变量、系统预定义变量、用户自定义变量
全局变量可以在子bash中访问
局部变量只能在当前bash中访问,子bash和父bash都无法访问
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| 常用系统变量有 $HOME $PWD $SHELL $USER
查看所有全局系统变量 env 查看所有系统和局部变量 set 通过env | grep 变量名 来查找是否为全局变量 通过set | grep 变量名 来查找是否为局部变量
定义一个全局变量 1.先定义一个局部变量 2.使用export 变量名 将其变成了
定义一个只读变量(相当于常量) readonly key=value
删除变量,无法删除只读变量 unset key
|
一般规定自定义变量为小写字母,默认大写字母为系统预定义变量
特殊变量
$n
代表接受的参数,比如$1代表第一个参数,$4代表第四个参数,$${11}代表第十一个参数
$0代表当前脚本名称
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| #!/bin/bash echo '=========$n========' echo 1st:$1 echo 2st:$2 echo 3st:$3 echo $0
bash 1.sh =========$n======== 1st: 2st: 3st: 1.sh
bash 1.sh ws xhy 123 =========$n======== 1st:ws 2st:xhy 3st:123 1.sh
|
$#
获取输出参数的个数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| #!/bin/bash echo '=========$n========' echo 1st:$1 echo 2st:$2 echo 3st:$3 echo $0 echo $#
bash 1.sh ws xhy 123 =========$n======== 1st:ws 2st:xhy 3st:123 1.sh 3
|
$*和$@
代表命令行所有的参数,效果一致
$*使用空格隔开
$@是返回一个数组(后面可以用循环遍历提取出来)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| cat 1.sh #!/bin/bash echo '=========$n========' echo 1st:$1 echo 2st:$2 echo 3st:$3 echo $0 echo $# echo $* echo '=======' echo $@
bash 1.sh ws xhy 123 =========$n======== 1st:ws 2st:xhy 3st:123 1.sh 3 ws xhy 123 ======= ws xhy 123
|
$?
查看上一条命令是否正常执行
非0代表错误
shell运算符
expr
1 2 3 4
| 需要加空格 expr 10 + 10 expr 10 - 10 expr 10 \* 10
|
命令替换(在脚本中进行赋值)
1 2 3 4 5 6 7 8
| a=$(expr 10 + 10) 或 a=`expr 10 + 10` 或 a=$((10+10))
或(推荐) a=$[10+20]
|
条件判断
格式中括号,加空格
例如[ $a -eq $b]
1 2 3 4 5 6 7 8
| 值比较 -eq 等于 -ne 不等于 -lt 小于 -lt 小于等于 -gt 大于 -ge 大于等于 -n 不等于
|
文件权限判断
1 2 3 4 5 6
| -r 有读权限 -w 有写权限 -x 有执行权限
[ -x test.sh ] echo $?
|
文件类型判断
1 2 3 4 5 6
| -e 文件存在 -f 文件存在且为file -d 文件存在且为dir
[ -d ./ ] [ -f test.sh ]
|
多条件判断
1 2 3 4 5 6 7 8 9
| && 与 A && B 表示A执行成功后执行B
|| 或 A || B 表示A执行失败后执行B
[ $a -eq $b ] && "$a=$b" || echo "$a!=$b"
|
流程控制
条件判断
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| if语法: if [ xxx ] then xxx elif [ xxx ] then xxx else xxx fi
if [ xxx ];then xxx;fi
if语法的优化,类似于switch-case的用法 case语法结构:
case $a in "1") xxx ;; #表示匹配到之后,相当于break "2") xxx ;; *) #相当于default,另外所有的值 xxx ;; esac #表示结束
例: #!/bin/bash case $1 in "hello") echo "hello!" ;; "ee") echo "?" ;; *) echo "error" esac
bash 2.sh hello hello!
|
流程控制
一般约定for使用(()),而if使用[],但其实都可以用
for
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| for 基本语法1,跟传统c差不多 for ((i=0;i<=100;i++)) do sum=$[$sum+$i] done echo $sum
bash 2.sh 5050
基本语法2 常用,是一种可以用来遍历的方法 {}在shell中,是内部运算符,代表序列,而在python中要遍历使用range()即可
for a in {1..10} do sum=$[$a+$sum] done echo $sum
while
|
while(不推荐)
1 2 3 4 5 6 7 8 9 10
| #!/bin/bash i=0 while [ $i<=100 ] do # sum=$[$sum+$i] # i=$[$i+1] let sum+=a let a++ done echo $sum
|
shell函数
shell中函数分为系统函数和自定义函数
系统函数
实际上系统命令就是系统函数
比如date
或date +%s
获取时间戳
1 2 3
| #!/bin/bash filename="$1_log_$(date +%s)" echo $filename
|
常用系统函数
basename:获取文件名称,删除所有前缀,直接显示出文件名称字符串
1 2 3 4 5 6 7 8 9 10
| 例 basename /usr/local/redis/redis.conf 输出 redis.conf
basename /usr/local/redis/redis.conf .conf 输出redis
获取名称: $0会同时获取文件路径 $(basename $0 .sh)
|
dirname同理获取绝对路径,应该很好理解
1 2
| path=$(cd $(dirname $0);pwd) name=$(basename $0 .sh)
|
自定义函数
感觉没什么特色值得记,略过
需要通过function
关键字来进行函数的声明
再进行调用
1 2 3 4 5
| function add(){ s=$[$1 + $2] return $s } add "第一个参数" "第二个参数"
|
应用案例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| 1.写一个归档脚本
#!/bin/bash # 首先判断输入参数个数是否为1 if [ $# -ne 1 ];then echo "参数个数错误!应该输入一个参数作为归档目录名" exit fi
# 从参数中获取目录名称,查看目录名称是否存在 if [ -d $1 ];then echo else pause echo "目录不存在!" exit fi
# 获取绝对路径 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
# 开始归档目录文件 echo "开始归档..." pause
# -c 归档 z 压缩 f 可视化 tar -czf $DEST $DIR_PATH/$DIR_NAME
# 判断上面归档文件操作是否成功 if [ $? -eq 0 ] then pause echo "归档成功" echo "归档的文件为:$DEST" else echo "归档出现问题!" fi exit
2.把脚本加入cronjob来运行,每天运行一次 0 2 * * * /脚本位置
|
剪切cut
现在已经被AWK取代了,但是AWK复杂很多,cut还是简单记一笔
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| cut [选项] 文件名 -f 列号,第几列(竖的) -d 分隔符,例如|、空格等,默认为制表符 -c 按字符进行切割,后面加上使用第几列
例: cat /root/test.txt 172.16.2.166 xhy 192.168.10.100 eth0 wangsheng 172.16.2.135:two:three:four:five:zhz
cut -d "" -f 2 /root/test.txt 输出 192.168.10.100 eth0 wangsheng
cat /root/test | grep zhz | cut -d ":" -f 2,6 输出 two:zhz
cat /root/test | grep zhz | cut -d ":" -f 4- 输出 four:five:zhz
例: ifconfig | grep ens33 -A 2 | grep inet | cut -d "" -f 10
|