linux中shell脚本的编程使用
linux中shell脚本的编程使用
- 1.shell的初步理解
- 1.1 怎么理解shell
- 1.2 shell命令
- 2.shell编程
- 2.1 什么是shell编程
- 2.2 C语言编程 和 shell编程的区别
- 3.编写和运行第一个shell脚本程序
- 3.1 编写时需要注意以下几点:
- 3.1.1 shell脚本没有main函数,没有头文件。shell脚本文件中是使用bash解析器进行解析,所以必须在shell脚本中的第一行指明解析器的路径:
- 3.1.2 shell脚本中没有printf函数,要输出内容到终端上,必须使用shell命令---》echo
- 3.2 第一个shell程序 hello.sh
- 3.3 如何运行编写好的shell程序
- 4.变量
- 4.1 shell变量不需要声明数据类型,所有的变量默认都是字符串类型
- 4.2 shell语法中为变量赋值时,等号的左右两边不允许有空格
- 4.3 变量的引用,需要在变量前面加入美元符号$
- 4.4 变量种类
- 4.4.1 自定义变量
- 4.4.2 系统环境变量----env命令查看环境变量
- 4.5 位置变量(传递命令行参数和函数调用时传递参数)
- 注意:
- 5.shell编程符号
- 5.1 双引号 --> 作用: 把某些东西 变成 "值"
- 5.1.1 例如字符串中有空格,则必须使用"",如果没有空格,不加""也可以
- 5.1.2 在""内可以对变量进行引用
- 5.1.3 在""内部是可以使用shell命令,但是使用shell命令需要使用反引号``来括住命令
- 5.2 单引号 --->在单引号里面的内容 看做是纯粹的字符串
- 5.3 反引号--->把双引号中的命令标识出来,也就是将反引号中的内容当成一个shell命令进行解析
- 5.4 重定向符号 < << > >>
- 5.4.1 输出重定向 > >>
- 5.4.2 输入重定向
- 5.4.3 标准出错重定向
- 6.算术运算命令expr
- 7.字符串处理
- 8.获取输入
- 9.if分支语句
- 9.1 条件语句
- 10.test语句
- 10.1 字符串测试
- 10.2 整数测试
- 10.3 文件测试
- test的复合表达式
- 11.多路分支语句
- 11.1 格式
- 11.2 总结
- 11.3 举例
- 12.循环语句
- 12.1 for循环
- 12.2 while循环
- 12.3 until
- 12.4 break 和 continue
- 13.函数
- 注意:
1.shell的初步理解
1.1 怎么理解shell
\quad shell在英文中翻译为"贝壳",在贝壳内部就是linux系统内核,在贝壳外部就是用户。对于shell而言,就是用户与内核之间的媒介。是用户跟内核通信几种方式中的一种。
1.2 shell命令
\quad Linux命令指的是shell命令,大多数shell命令都是存放在/bin,当我们需要使用一个命令时,实际的流程:
1)打开一个Termial--》Termial终端实际上是运行了一个bash进程(bash命令解析器)
china 2356 1743 0 11:42 ? 00:00:11 /usr/lib/gnome-terminal/gnome-terminal-serve
china 2366 2356 0 11:42 pts/0 00:00:00 bash2)bash命令解析器会把bash命令提示符打印到终端上china@ubuntu:~$ --》命令行提示符。必须要有命令行,shell命令才会被bash解析器解析出来--》每次输完命令并且解析之后都会输出一条命令行提示符,然后再次等待下一次命令输入
3)所有在命令行上输入的命令,都是使用bash解析器进行解析china@ubuntu:~$ ls ---当按下回车的时候,就会被送到bash解析器进行解析!bash解析器这个应用程序在系统中的位置:china@ubuntu:~$ which bash/bin/bash
2.shell编程
2.1 什么是shell编程
\quad shell编程就是通过shell语法将shell命令组合起来,写入一个文件中。将来运行这个文件时,就会执行里面的每一行shell语法,这个文件称之为shell脚本文件。实现更加自动化和智能化。
2.2 C语言编程 和 shell编程的区别
C语言程序 | shell脚本程序 | |
---|---|---|
语法 | C语言语法 | shell语法 |
文件后缀 | xxx.c | xxx.sh |
文件存放位置 | 任意目录 | 除了共享目录之外,一般放在家目录 |
是否需要编译 | gcc编译 | 不需要编译,但是需要给权限 |
3.编写和运行第一个shell脚本程序
3.1 编写时需要注意以下几点:
3.1.1 shell脚本没有main函数,没有头文件。shell脚本文件中是使用bash解析器进行解析,所以必须在shell脚本中的第一行指明解析器的路径:
#!/bin/bash
#!是shell脚本中特殊标识符,后面必须跟着shell命令解析器的路径
3.1.2 shell脚本中没有printf函数,要输出内容到终端上,必须使用shell命令—》echo
NAMEecho - display a line of text --> 在终端上显示一行文本
SYNOPSISecho [SHORT-OPTION]... [STRING]...echo LONG-OPTION-e enable interpretation of backslash escapes --> 解析字符串上的转义符号
比如:china@ubuntu:~$ echo "hello world\n"hello world\nchina@ubuntu:~$ echo -e "hello world\n"hello world
3.2 第一个shell程序 hello.sh
#!/bin/bash
echo "hello world"
3.3 如何运行编写好的shell程序
3.3.1 先给权限(因为默认是没有执行权限的)
chmod 777 hello.sh 或者 chmod +x hello.sh
3.3.2 执行
./hello.sh
4.变量
4.1 shell变量不需要声明数据类型,所有的变量默认都是字符串类型
C语言: int a;
shell: str
4.2 shell语法中为变量赋值时,等号的左右两边不允许有空格
C语言 int a = 10;
shell str=helloworld
4.3 变量的引用,需要在变量前面加入美元符号$
echo $str 或者 echo ${str}
4.4 变量种类
4.4.1 自定义变量
str=hello
4.4.2 系统环境变量----env命令查看环境变量
HOME: 用户主目录
PATH: 命令搜索路径
LD_LIBRARY_PATH: 动态库搜索路径
PWD: 当前路径
使用命令改变环境变量:
export PATH=$PATH:/home/china/xxx
export PATH=/home/china/xxx
4.5 位置变量(传递命令行参数和函数调用时传递参数)
./hello.sh aaaa bbbb
$0 表示命令程序名 ./hello.sh
$1,$2,$3...$9 表示第一个到第九个参数的名字$1-->aaaa $2--->bbbb
$# 表示命令行参数的个数(不包含脚本名) 2
$* 包含所有命令行参数 aaaa bbbb
$? 表示前一个命令的退出状态(返回值)
shell命令执行成功: 0 执行失败: 非0
$$ 表示正在执行进程的ID号
注意:
(1)在脚本中修改的环境变量只在脚本及子脚本范围内有效,要想其在外边环境中生效,则需要前面加source
eg: source 1.sh
(2)如何使脚本(程序)后台执行
a.脚本(程序)后面加&符号,但是终端退出了,该进程也会结束
eg: ./a.out &
b.如果想让终端退出后,进程仍在:
eg: nohup ./a.out &
5.shell编程符号
5.1 双引号 --> 作用: 把某些东西 变成 “值”
5.1.1 例如字符串中有空格,则必须使用"“,如果没有空格,不加”"也可以
str=hello 正确
str="hello" 正确
str=hello world 不正确
str="hello world" 正确
5.1.2 在""内可以对变量进行引用
str=hello
echo "$str world"
5.1.3 在""内部是可以使用shell命令,但是使用shell命令需要使用反引号``来括住命令
china@ubuntu:~/shelldir$ date
2021年 08月 14日 星期六 20:36:11 CSTecho "today is date" ---->结果:today is date
echo "today is `date`" ---->结果:today is 2021年 08月 14日 星期六 20:37:56 CST
5.2 单引号 —>在单引号里面的内容 看做是纯粹的字符串
echo 'today is date' --->结果:today is date
str=hello
echo '$str world' --->结果:$str world 不能在单引号里面引用变量
5.3 反引号—>把双引号中的命令标识出来,也就是将反引号中的内容当成一个shell命令进行解析
echo "today is `date`" ---->结果:today is 2021年 08月 14日 星期六 20:37:56 CST
5.4 重定向符号 < << > >>
标准输入(0)/标准输出(1)/标准输错(2) 系统默认打开的文件描述符
5.4.1 输出重定向 > >>
\quad 命令的输出结果通常提交到标准输出设备(终端),但是也可以重新定个方向到其他位置,比如用一个文件来代替,这叫做输出重定向。在命令后添加>filename ,该命令(脚本)的输出就会写入到filename这个文件中,而不是写入终端。
china@ubuntu:~/shelldir$ ls ---命令解析的结果输出在终端上
1.sh 2.sh a.txt
china@ubuntu:~/shelldir$ ls >a.txt ---命令的输出结果重定向到文件a.txt中
china@ubuntu:~/shelldir$ cat a.txt
1.sh
2.sh
a.txt
china@ubuntu:~/shelldir$ ls >>a.txt ---以追加的方式重定向到文件a.txt中
china@ubuntu:~/shelldir$ cat a.txt
1.sh
2.sh
a.txt
1.sh
2.sh
a.txt
china@ubuntu:~/shelldir$ echo "hello world">a.txt --将一个字符串"hello world" 输出重定向到文件a.txt中
china@ubuntu:~/shelldir$ cat a.txt
hello world
5.4.2 输入重定向
\quad 命令的输入通常是从标准输入设备(键盘)中请求的,但是也可以重新定个方向到其他位置,比如从一个文件中请求,这叫做输入重定向。命令<filename 该命令所有的输入请求都来自filename。
比如:read str <1.txt 从1.txt中读取数据,存储到变量str中
5.4.3 标准出错重定向
\quad unix命令把大部分错误信息都写到这个设备里面。一般情况下,标准出错设备和标准输出设备是同一个设备(默认为终端)。标准出错也可以重定向到文件
命令 2 > filename
命令 2 >> filename china@ubuntu:~/shelldir$ asdsds 2>a.txt --把出错信息重定向到文件a.txt中
china@ubuntu:~/shelldir$ cat a.txt
asdsds:未找到命令
6.算术运算命令expr
expr主要是用于简单的整数计算,包括 加(+)、减(-)、乘(*)、除(/)、取余(%)
#!/bin/bash
a=10
b=20
val=`expr $a + $b` (注意:操作数与运算符,前后至少要有一个空格)
echo "val:$val" --->val:30
#!/bin/bash
a=10
b=20
val=`expr $a + $b \* 4` (且不支持括号)
echo "val:$val" --->val:90
7.字符串处理
计算字符串字符个数
str="hello world"
echo "${#str}" -->11
通配符:
* 代表任意长度的任意字符
? 代表一个长度的任意字符
[a-z]: 代表一个长度的a-z之内的字符
[az]: 代表一个长度,只能匹配a或者z的内容
[^az]: 代表一个指定范围a/z之外的字符 与[az]相反!%: 从右到左尽可能匹配少的字符
%%: 从右到左尽可能匹配多的字符
#: 从左到右尽可能匹配少的字符
##: 从左到右尽可能匹配多的字符
8.获取输入
read:在shell表示从终端输入
read val1
read -p "input data:" val1 val2 val3
read val<1.txt //从文本输入
注意:
1、以#开头的行,就是注释行
2、多行注释:
<<'COMMENT'
...
COMMENT
9.if分支语句
9.1 条件语句
第一种:
if command ; then...语句列表
fi
第二种:
if command ; then...语句列表
else...语句列表
fi
第三种:
if command ; then...语句列表
elif command ; then...语句列表
else...语句列表
fi
eg:read varif [ $var = "hello" ] ; thenecho "yes"elseecho "no"fi
如:从键盘上获取两个整数,比较大小,输出最大值
read -p "input two data:" val1 val2
if [ $val1 -gt $val2 ];thenecho "max:$val1"
elseecho "max:$val2"
fi
10.test语句
test语句可以测试三种对象:字符串、整数、文件属性
10.1 字符串测试
= 测试两个字符串内容是否完全一样
!= 测试两个字符串内容是否不一样
-Z(zero) 测试字符串是否为空,为空,返回true
-n(null) 测试字符串是否不为空,不为空,返回true
在测试字符串变量时,需要防止字符串为空的技巧:
==引用变量后加一个额外的字符: ==
test ${A}x = ${B}x
10.2 整数测试
a -eq b: equal测试两个整数是否相等
a -ne b: not equal 测试两个是否不相等
a -gt b: greater 测试a是否大于b
a -ge b: greater or equal 测试a是否大于等于b
a -lt b: little 测试a是否小于b
a -le b: little or equal 测试a是否小于等于b
10.3 文件测试
-d name 测试name是否是一个目录(dir)
-f name 测试name是否是一个普通文件(file)
-L name 测试name是否为符号链接文件(Link)
-r name 测试name文件是否存在并可读(read)
-w name 测试name文件是否存在并可写(write)
-x name 测试name文件是否存在并可执行(excute)
-s name 测试name文件是否存在并且长度不为0(size)
f1 -nt f2 测试f1 是否比f2更新(newer than)
f1 -ot f2 测试f1 是否比f2更旧(older than)
test命令可以用[]来简写
test expression <===> [ expression ]
test的复合表达式
\quad 组合了两个或两个以上的表达式称为复合表达式,你可以用test([])内置的的操作符,也可以用条件操作符(&& || !)来实现
1)使用test内置的操作符
test expr1 "test_buildin" expr2test_buildin:-a and-o or
2)使用条件操作符(&& || !)
test expr1 "op" test expr2
如:
test $A = '1' && test $B = '1'
@ [ $A = '1' ] && [ $B = '1' ]
11.多路分支语句
11.1 格式
case expression in
pattern1)
...语句列表
;; //作用类似与C语言的break,这里;;不能省
pattern2)
....语句列表
;;
patternn)
....语句列表
;;
*) ---其他值
....语句列表
;;
esac
11.2 总结
1)expression 既可以是一个变量、一个数字、一个字符串,还可以是一个数学计算表达式,或者是命令的执行结果,只要能够得到 expression 的值就可以。
2)pattern 可以是一个数字、一个字符串,甚至是一个简单的正则表达式。
3)case语句真正的功能强大之处在于它可以使用模式而不是固定的字符串匹配。一个模式是由一串正规字符和特殊的通配符组成的字符串,该模式可以用正则表达式。
11.3 举例
例子1:
执行程序后,从键盘中获取一个值
如果该值为1,则打印one
如果该值为2,则打印two
如果该值其他值,则打印error
read val
case $val in1)echo "one";;2)echo "two";;*)echo "error";;
esac
例子2:
#!/bin/bash
read -p "input data:" valcase $val in[0-9])echo "this is 0-9";;[a-d]|[m-z])echo "this is a-d m-z";; h*)echo "h.....";;[-]*)echo "---------";;*)echo "other";;
esac
12.循环语句
12.1 for循环
格式:
for 变量名 in 单词表
do语句列表
done
如:
for val in 1 2 3 4 5
doecho $val
done
执行结果:
china@ubuntu:~/shelldir$ chmod 777 for.sh
china@ubuntu:~/shelldir$ ./for.sh
1
2
3
4
5
如:
for val int $*
doecho $val
done
执行结果:
china@ubuntu:~/shelldir$ ./for.sh 1 2 3 4 5 6
1
2
3
4
5
6
=>for也可以写成C风格相同的for循环
for((i=1; i<=5; i++ ))
doecho "$i"
done
//双圆括号(())使得shell程序中可以使用C语言的for风格
例子:写一个脚本,求1到100的和
sum=0
for((i=1;i<=100;i++))
dosum=`expr $sum + $i`
doneecho "sum:$sum"
12.2 while循环
格式:
while 命令或表达式
do语句列表
done
===>也可以用C语言的while风格
while(())
do语句列表
done
比如:从键盘上获取一个最小值和最大值,打印他们两个之间的所有取值
read -p "min:" min
read -p "max:" max
while test $min -le $max
doecho "$min"min=`expr $min + 1`
done
如:写一个脚本,求1到100的和
sum=0
i=1
while [ $i -le 100 ]
dosum=`expr $sum + $i `i=`expr $i + 1`
done
echo "sum:$sum"
12.3 until
格式:
until 命令或表达式
do
done
until与while功能相似,所不同的是只有当测试的命令或表达式的值为假时,才执行循环体中的命令列表。若条件成立则退出循环。这一点与while恰好相反。
12.4 break 和 continue
- break n跳出n层循环
- continue n 跳到n层循环语句的下一轮循环去
- break 和 continue 后面不加n,则和C语言里面的含义一样
举例:
写一个脚本,实现可以不断地从键盘获取数据
如果获取的数据为 “exit” ,则退出
如果获取的数据小于100,则打印值
如果获取的数据是其他的,则打印 “other”
#!/usr/bin/bash<<'aaa'while((1))
doread -p "data:" dataif test $data = "exit" ;thenbreak elif [ $data -lt 100 ];thenecho "$data"elseecho "other"fidone
aaawhile((1))
doread -p "data:" datacase $data inexit)break;;[0-9])echo "$data";;[0-9][0-9])echo "$data";;*)echo "other";;esac
done
13.函数
格式:
function_name()
{...命令列表echo $1 $2 $3return 123
}
function_name:你自定义的函数名,名字的取法与C语言类似
函数的调用
function_name arg1 arg2 arg3
在函数内部 arg1==>$1 arg2==>$2 arg3==>$3
获取函数的返回值
function_name arg1 arg2 arg3
ret=$?
注意:
1、函数的返回值的大小不超过一个字节
2、SHELL没有变量作用域,如果出现重复变量名会认为是同一个。
比如:
get_sum()
{return `expr $1 + $2`
}
read var1;read var2
get_sum $var1 $var2
echo $?
练习:编写一个脚本,封装一个函数实现比较两个数的最大值并且返回
compare()
{if test $1 -gt $2;thenret=$1elseret=$2fi
}
read -p "input two data:" val1 val2
compare val1 val2
echo "max:$ret"
练习:编写一个脚本,实现一个函数求a+…+b的和
sum=0
get_sum()
{for(( i=$1;i<=$2;i++ ))dosum=`expr $sum + $i`done
}
read var1 var2
get_sum $var1 $var2
echo $sum