Akemi

Shell零碎知识

2024/07/15

全局变量与局部变量
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中函数分为系统函数和自定义函数
系统函数
实际上系统命令就是系统函数
比如datedate +%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
CATALOG
  1. 1. 特殊变量
  • shell运算符
  • 条件判断
  • 流程控制
  • 流程控制
  • shell函数
  • 应用案例
  • 剪切cut