Shell脚本入门
GNU bash, version 4.4.23
0、前置知识
01、文本结构
1、脚本文件第一行指定解释器,用#!解释器表示
如/bin/bash、/usr/bin/python3
2、第二行为注释,用#修饰
3、其他的自由编写,注释也是
02、执行权限
脚本编写完成后会被执行,执行需要权限
0 无权限
1 r 读
2 w 写
4 x 执行
chmod o+x xx.sh #添加执行权限
03、如何执行
脚本文件中已经包含了解释器,权限足够的话,当前目录下直接即可执行
如 ./hi.sh
或者指定编译器bash hi.sh
如果脚本所在的路径存在于环境变量中,那么直接使用文件名即可执行(任意位置)
如hi.sh
#!/bin/bash
# this is shell script,name :hi.sh
echo Hello
./hi.sh即可输出Hello
1、基础语法
1.1、变量
Shell是脚本语言,定义变量比较随意,直接赋值即可,使用的时候,使用$取变量。
关键字readonly、unset用于定义只读和删除变量,local定义局部变量,在函数中演示
#!/usr/bin/bash
myVal="Hello" --直接定义即可
echo $myVal --使用$获取变量
myVal="World" --修改变量
echo "$myVal"
readonly myVal="ok" --定义为只读变量
myVal="nice" --语句非法,无法修改
unset myVal --删除变量myVal,但是只读变量无法删除,此时报错
1.2、引号
Shell中有单引号、双引号、反引号甚至不加引号
shell中可以不加引号,默认就是字符串
单引号代表不解析,原样输出字符串
双引号解析命令及变量,反引号用于使用命令,可以放在双引号中。
echo `ls` --反引号中使用命令 output: / Hi.sh
echo "当前目录下执行ls命令: `ls`" --将反引号嵌入双引号中
1.3、字符串
字符串(String)就是一系列字符的组合。字符串是 Shell 编程中最常用的数据类型之一(除了数字和字符串,也没有其他类型了,数组列表之类?)
字符串可以使用{}包裹,用来处理更加复杂的操作,如拼接、截取、长度等
str="Hello Shell"
echo "${str}" #Hello Shell
'#'用来取长度
echo "长度是:${#str}" #长度是:11
拼接字符串,直接放一起
echo "${str}""dd"
Hello Shelldd
': :截取字符串,位置:字符个数'
echo "截取字符串:${str:1:5}"
echo "截取字符串:${str::5}"
echo "截取字符串:${str:0-3:5}"
截取字符串:ello
截取字符串:Hello
截取字符串:ell
1.4、 $#、$*、$@、$?
Shell脚本执行时经常要从外部传递参数,在文件内部可以使用$接收。
Shell中的特殊字符,$n在文件中指外部参数,0指代本文件名,其他指代参数顺序。
$#指参数数量,$@和$*取所有参数。
$?是上个命令或者函数退出状态
./hi.sh a b c
echo $0 /usr/local/hi.sh
echo $1 a
echo $2 b
echo $3 c
echo "total num :$#" total num :3
echo "total:$@" total:a b c
echo $? 0 上个命令正常退出
1.5、数组
Shell 也支持数组,没有限制数组的大小,理论上可以存放无限量的数据,只支持一维数组。
使用x=(z y z)格式声明,使用x[n] 取值
arr=(1 2 3 4 5)
echo "默认从0开始: $arr"
echo "所有值: ${arr[*]}"
echo "数量: ${#arr[*]}" 还是使用'#'获取数量
默认从0开始: 1
所有值: 1 2 3 4 5
数量: 5
arr[6]="ok"
echo "所有值: ${arr[*]}"
所有值: 1 2 3 4 5 ok
unset arr[6] 删除元素
unset arr 删除数组
1.6、(())、流程
shell中的(())用来处理数学运算(let也行),使用if then fi else等关键字处理。
a=20
if ((a>30))
then
((a+=10))
echo $a
elif ((a<10))
then
echo $a
else
echo "no"
当然使用:分割后会好看一点
if ((a>30)) ; then
((a+=10))
echo $a
elif ((a<10)) ; then
echo $a
else
echo "no" ; fi
shell中的循环使用for控制,可以使用c或者python风格。也有while\unyil\select等循环,1.9中
#c风格的流程
for((i=0;i<10;i++))
do
echo "C-For: $i"
done
#python风格
for i in 0 2 3 4 5
do
echo "Python_For :$i"
done
1.7、函数
shell中的函数使用function声明,同样使用$取参数。
调用的时候直接使用函数名即可
function sum() {
n=0 //这里的变量外部也可以访问,使用local修饰则只能在函数中
for i in $@
do
((n+=i))
done
echo "$n"
}
sum 1 2 3 4 //10
echo $n //10
sum //0
echo $? //0 上一个命令或函数退出的状态,正常退出则为0
1.8、read
read 用于从命令行输入,像C的scan,python的input.
参数-p 显示提示信息,-a将数据给数组
read -p "Enter some information > " name url age //tom 10 www.google.com
echo $name $age $url //tom 10 www.google.com
read -a arr //a b c d
echo ${arr[*]} //a b c d
1.9、循环
shell中除了for循环外,还有while、until、select in循环以及case in结构
while、until循环
x=8
while ((x<10)) ; do
echo "ok"
((x+=1))
done
//ok
//ok
until和 while相反,用一个就行了。
select in循环
select in 循环用来增强交互性,它可以显示出带编号的菜单,用户输入不同的编号就可以选择不同的菜单,并执行不同的功能。
select in 是 Shell 独有的一种循环,非常适合终端(Terminal)这样的交互场景。
arr=("Shell" "Python" "JavaScript")
select x in ${arr[*]};do
echo "$x"
done
echo "You have selected $x"
1) Shell
2) Python
3) JavaScript
#? 1 //输入编号
#? Shell
2
Python
#? 3
#? JavaScript
^D //Crtl+D代表终止,所以上一个就是你的选择
You have selected JavaScript
select in 和用户交互,不会主动终止,使用break让其结束。
case in常和case in 一起用,用来处理条件。
case in )
echo "What is your favourite OS?"
select name in "Linux" "Windows" "Mac OS" "UNIX" "Android"
do
case $name in
"Linux")
echo "Linux是一个类UNIX操作系统,它开源免费,运行在各种服务器设备和嵌入式设备。"
break
;;
"Windows")
echo "Windows是微软开发的个人电脑操作系统,它是闭源收费的。"
break
;;
"Mac OS")
echo "Mac OS是苹果公司基于UNIX开发的一款图形界面操作系统,只能运行与苹果提供的硬件之上。"
break
;;
"UNIX")
echo "UNIX是操作系统的开山鼻祖,现在已经逐渐退出历史舞台,只应用在特殊场合。"
break
;;
"Android")
echo "Android是由Google开发的手机操作系统,目前已经占据了70%的市场份额。"
break
;;
*)
echo "输入错误,请重新输入"
esac
done
1) Linux
2) Windows
3) Mac OS
4) UNIX
5) Android
#? What is your favourite OS?
2
Windows是微软开发的个人电脑操作系统,它是闭源收费的。
1.10、test、[[]]
test 是 Shell 内置命令,用来检测某个条件是否成立。test 通常和 if 语句一起使用,并且大部分 if 语句都依赖 test。
test 命令有很多选项,可以进行数值、字符串和文件三个方面的检测。
test 命令比较奇葩,>、<、== 只能用来比较字符串,不能用来比较数字,比较数字需要使用 -eq、-gt
等选项;不管是比较字符串还是数字,test 都不支持 >= 和 <=。有经验的程序员需要慢慢习惯 test 命令的这些奇葩用法。
比较数字
read a
if test $a -eq 10; then
echo "=10"
elif test $a -gt 10 && test $a -lt 20 ;then
echo "20>a>10"
elif test $a -le 20 ; then
echo "<=20"
else
echo "no"
f
比较字符串
选 项 | 作 用 |
---|---|
-z str | 判断字符串 str 是否为空。 |
-n str | 判断宇符串 str 是否为非空。 |
str1 = str2 str1 == str2 | = 和== 是等价的,都用来判断 str1 是否和 str2 相等。 |
str1 != str2 | 判断 str1 是否和 str2 不相等。 |
str1 > str2 | 判断 str1 是否大于 str2。\> 是> 的转义字符,这样写是为了防止> 被误认为成重定向运算符。 |
str1 < str2 | 判断 str1 是否小于 str2。同样,\< 也是转义字符。 |
a=""
if test -z "$a" ; then
echo "ok"
fi
//ok
比较文件
文件类型判断 | |
---|---|
选 项 | 作 用 |
-b filename | 判断文件是否存在,并且是否为块设备文件。 |
-c filename | 判断文件是否存在,并且是否为字符设备文件。 |
-d filename | 判断文件是否存在,并且是否为目录文件。 |
-e filename | 判断文件是否存在。 |
-f filename | 判断文件是否存在,井且是否为普通文件。 |
-L filename | 判断文件是否存在,并且是否为符号链接文件。 |
-p filename | 判断文件是否存在,并且是否为管道文件。 |
-s filename | 判断文件是否存在,并且是否为非空。 |
-S filename | 判断该文件是否存在,并且是否为套接字文件。 |
文件权限判断 | |
选 项 | 作 用 |
-r filename | 判断文件是否存在,并且是否拥有读权限。 |
-w filename | 判断文件是否存在,并且是否拥有写权限。 |
-x filename | 判断文件是否存在,并且是否拥有执行权限。 |
-u filename | 判断文件是否存在,并且是否拥有 SUID 权限。 |
-g filename | 判断文件是否存在,并且是否拥有 SGID 权限。 |
-k filename | 判断该文件是否存在,并且是否拥有 SBIT 权限。 |
文件比较 | |
选 项 | 作 用 |
filename1 -nt filename2 | 判断 filename1 的修改时间是否比 filename2 的新。 |
filename -ot filename2 | 判断 filename1 的修改时间是否比 filename2 的旧。 |
filename1 -ef filename2 | 判断 filename1 是否和 filename2 的 inode 号一致,可以理解为两个文件是否为同一个文件。这个判断用于判断硬链接是很好的方法 |
[[]]
[[ ]]
是 Shell 内置关键字,它和 test 命令类似,也用来检测某个条件是否成立。
test 能做到的,[[ ]] 也能做到,而且 [[ ]] 做的更好;test 做不到的,[[ ]] 还能做到。可以认为 [[ ]] 是 test 的升级版,对细节进行了优化,并且扩展了一些功能。
a=""
if [[ -z $a ]]; then
echo "ok"
fi
//ok
[[]]支持正则表达式
a="okok"
if [[ $a=~^o ]]; then
echo "ok"
fi