shell脚本编程总结
shell是什么;
Shell是系统的用户界面,提供了用户与内核进行交互操作的一种接口。它接收用户输入的命令并把它送入内核去执行。
实际上Shell是一个命令解释器,它解释由用户输入的命令并且把它们送到内核。不仅如此,Shell有自己的编程语言用于对命令的编辑,它允许用户编写由shell命令组成的程序。Shell编程语言具有普通编程语言的很多特点,比如它也有循环结构和分支控制结构等,用这种编程语言编写的Shell程序与其他应用程序具有同样的效果。
Linux提供了像MicrosoftWindows那样的可视的命令输入界面--X Window的图形用户界面(GUI)。它提供了很多桌面环境系统,其操作就像Windows一样,有窗口、图标和菜单,所有的管理都是通过鼠标控制。GNOME。
shell的种类
每个Linux系统的用户可以拥有他自己的用户界面或Shell,用以满足他们自己专门的Shell需要。
同Linux本身一样,Shell也有多种不同的版本。主要有下列版本的Shell: Bourne Shell:是贝尔实验室开发的。
BASH:是GNU的Bourne Again Shell,是GNU操作系统上默认的shell。
Korn Shell:是对Bourne SHell的发展,在大部分内容上与Bourne Shell兼容。
C Shell:是SUN公司Shell的BSD版本。
Z Shell:The last shell you’ll ever need! Z是最后一个字母,也就是终极Shell。它集成了bash、ksh的重要特性,同时又增加了自己独有的特性.
我们在系统上常用的shell是 bash
既然是编程,那么编程所常有的概念,在shell中的体现是怎样的呢?
事实上编程中所用到的变量,函数,数组,字符串,条件判断, 循环结构在shell中都能体现.
shell脚本语法
第一行必须顶格写并指明以下所使用的shell
#!/bin/bash
#!/usr/bin/python
#!/bin/tcsh
各种shell 如bash,python,tcsh任君选择使用.
定义变量
shell语言是非类型的解释型语言,强类型语言编程时需要事先声明变量,并声明其类型 shell编程中给一个变量赋值就是定义变量.
shell的变量是无类型的,所以用户想让它当字符时就是字符,想让它当数字就是数字。
当然,我们还可以用 declare来指定其数据类型
declare
-r 只读变量 =>相当于其它语言的常量吧,赋值后不能修改
-a 数组
-i 整型
-f 函数
在linux支持的所有shell中,都可以用赋值符号(=)为变量赋值. 如:
abc=7 (不能在等号两侧留下空格 )
name=abc
在变量赋值之后,只需在变量前面加一个$去引用.
echo $abc
7
echo $name
abc
声明只读变量方法一
[robert@ca2 CA]$ declare -r nb=100
[robert@ca2 CA]$ nb=101
-bash: na: readonly variable =>当尝试改变只读变量的时候,系统会发出警告,提醒这是只读变量
声明只读变量之方法二 将变量变成常量[只读变量]
[robert@ca2 CA]$ readonly na=100
[robert@ca2 CA]$ echo $na
100
[robert@ca2 CA]$ na=20
-bash: na: readonly variable =>当尝试改变只读变量的时候,系统会发出警告,提醒这是只读变量
shell脚本之条件判断
有if语句作为条件选择分支
语法 if 条件判断;then
执行语句
elif 条件判断;then
执行语句
fi if条件判断结束符
有case作为条件选择分支
#!/bin/bash
switch=6
case $switch in
[0-9])
echo $switch
;;
[a-z])
echo $switch
;;
esac
说到if语句结构,就得提及到条件测试
命令执行作为条件测试依据
如grep 'root' /etc/passwd 将运行命令成功与否作为判断条件
if grep 'root' /etc/passwd;then
echo "root 用户存在"
else
echo "root 用户不存在"
fi
shell脚本之 case选择分支
比较运算:
>, <, >=, <=, ==, !=
条件判断中,存在各种判断, 各种测试类型如下
测试类型:根据比较时的操作数的类型
整型测试:整数比较
字符测试:字符串比较
文件测试:判断文件的存在性及属性等
注意:比较运算通常只在同一种类型间进行
整型测试:
-gt: 例如 [ $num1 -gt $num2 ]
-lt:
-ge:
-le:
-eq:
-ne:
字符串测试:
双目
>: [[ "$str1" > "$str2" ]]
<:
>=
<=
==
!=
单目:
-n String: 是否不空,不空则为真,空则为假
-z String: 是否为空,空则为真,不空则假
bash条件测试之文件测试:
-a file
True if file exists.
-b file
True if file exists and is a block special file.
-c file
True if file exists and is a character special file.
-d file
True if file exists and is a directory.
-e file
True if file exists.
-f file
True if file exists and is a regular file.
-g file
True if file exists and is set-group-id.
-h file
True if file exists and is a symbolic link.
-k file
True if file exists and its ''sticky'' bit is set.
-p file
True if file exists and is a named pipe (FIFO).
-r file
True if file exists and is readable.
-s file
True if file exists and has a size greater than zero.
-t fd True if file descriptor fd is open and refers to a terminal.
-u file
True if file exists and its set-user-id bit is set.
-w file
True if file exists and is writable.
-x file
True if file exists and is executable.
-O file
True if file exists and is owned by the effective user id.
-G file
True if file exists and is owned by the effective group id.
-L file
True if file exists and is a symbolic link.
-S file
True if file exists and is a socket.
-N file
True if file exists and has been modified since it was last read.
file1 -nt file2
True if file1 is newer (according to modification date) than file2, or if file1 exists and file2 does not.
file1 -ot file2
True if file1 is older than file2, or if file2 exists and file1 does not.
file1 -ef file2
True if file1 and file2 refer to the same device and inode numbers.
-o optname
True if shell option optname is enabled. See the list of options under the description of the -o option to the set builtin
below.
-a FILE
-e FILE: 存在则为真;否则则为假;
-f FILE: 存在并且为普通文件,则为真;否则为假;
-d FILE: 存在并且为目录文件,则为真;否则为假;
-L/-h FILE: 存在并且为符号链接文件,则为真;否则为假;
-b: 块设备
-c: 字符设备
-S: 套接字文件
-p: 命名管道
-s FILE: 存在并且为非空文件则为值,否则为假;
-r FILE
-w FILE
-x FILE
file1 -nt file2: file1的mtime新于file2则为真,否则为假;
file1 -ot file2:file1的mtime旧于file2则为真,否则为假;
shell脚本之for in 循环
格式 for 变量 in 集合;do 语句体 ; done 循环结束标识
详细案例如下
declare -i sum=0
for i in {1..9};do
let sum+=$i //sum=$[$sum+$i] 中括号相加
done
echo $sum
let计算
shell脚本之for 循环
#!/bin/bash
for ((i=0;$i<10;i++));do
echo $i
done
shell脚本之while 循环
num=0
while true ;do
let num++
if [ $num -gt 10 ];then
break
fi
done
echo $num
shell脚本之until 循环 ==>与while循环不同的是,until的条件判断中,条件不成立,循环会继续进行
num=0
until [ $num -gt 10 ];do
let num++
done
echo $num
shell 脚本之函数使用
function test {
echo "$1 do you want test function"
}
test 'robert'
shell脚本之数组
数组是编程中,存储控制数据非常重要的一个手段和方式,但遗憾的是 linux的shell只支持一维数组
数组其实也是一种变量,不同的是,这个特殊类型的变量内,还可以存其它的变量.
数组的使用
数组名+索引
数组元素
索引的表示方式:
数字索引:a[index]
a[0], a[1]
bash 4.0的关联数组
a[hello], a[hi]
declare -a 索引数组
-A 关联数组
支持稀疏格式:
数组的赋值:
一次对一个元素赋值:
a[0]=0
a[1]=1
a[2]=2
a[3]=3
直接赋值:
arr=(0 1 2 3)
按索引进行赋值:
a=([0]=0 [3]=3 [2]=2 [1]=1)
用户输入:
read -a arr 用户输入的方式生成数组
数组的访问:
用索引访问:
ARRAY[index]
如 a=([0]=0 [3]=3 [2]=2 [1]=1)
echo a[0]访问索引为0的数组
0 ==>结果为0
数组的长度:
[robert@ca2 ~]$ array=([0]=0 [3]=3 [2]=2 [1]=1)
[robert@ca2 ~]$ echo ${#array[@]}
4
从数组中挑选某元素:
${ARRAY[@]:offset:number}
切片:
offset: 偏移的元素个数
number: 取出的元素的个数
[robert@ca2 ~]$ array=([0]=0 [3]=3 [2]=2 [1]=1)
[robert@ca2 ~]$ echo ${array[@]:1:2}
1 2
${ARRAY[@]:offset}:取出偏移量后的所有元素
[robert@ca2 ~]$ echo ${array[@]:1}
1 2 3
${ARRAY[@]}: 取出所有元素
[robert@ca2 ~]$ echo ${array[@]}
0 1 2 3
使用@和*的不同
$@: 每个参数是一个独立的串
$*: 所有参数是一个串
数组如果想作为对数传入给函数使用,怎么办呢?
#!/bin/bash
function myarr {
#echo $@
#exit 0
newarr=(echo "$@") 接收时转化为数组
echo ${newarr[@]}
}
myarray=(12 23 34 45)
myarr ${myarray[@]} ==>注,为函数传递数组作为变量,需要注意,要将其转化为N个参数传入
在编程中,字符串的操作是相当频繁常用的
字符串
字符串切片:
${string:offset:length} 从左向右取,依稀量,加长度, 如果只指定偏移量,则偏移后,取所有字串
取尾部的指定个数的字符:
${string: -length} 加个 " - " 号,则是从右向左取
取子串:基于模式
${variable#*word}:在variable中存储字串上,自左而右,查找第一次出现word,删除字符开始至此word处的所有内容;
[root@localhost ~]# url=www.baidu.com
[root@localhost ~]# echo $url
www.baidu.com
[root@localhost ~]# echo ${url#*.} 从左到右,取第一次出现的.号,并从左开始第一个字符删除到第一次出现的字符,
baidu.com
[root@localhost ~]# echo ${url##*.} 再加一个# 是贪婪模式,找到从左到右,最后一次出现的 . 并从头到 . 删除
com
${variable##*word}:在variable中存储字串上,自左而右,查找最后一次出现word,删除字符开始至此word处的所有内容;
file='/var/log/messages'
${file#*/}: 返回的结果是var/log/messages
${file##*/}: 返回messages
${variable%word*}: 在variable中存储字串上,自右而左,查找第一次出现word,删除此word处至字串尾部的所有内容;
${variable%%world*}:在variable中存储字串上,自右而左,查找最后一次出现word,删除此word处至字串尾部的所有内容;
file='/var/log/messages'
${file%*/}: 返回的结果是/var/log
${file%%*/}: 返回结果为空
phonenumber='010-110-8'
${phonenumber%%-*}
${phonenumber##*-}
url="http://www.magedu.com:80"
遍历访问一个字符串(默认是以空格分开的,当字符串是由其他字符分隔时可以参考 2)
#!/bin/bash
str="a --m"
for i in $str
do
echo $i
done
array
声明数组 myarray=(1 2 3 )
打印数组 echo ${myarray[@]}
1 2 3
访问数组的长度 ${#myarray[@]}
[root@localhost ~]# echo ${#myarray[@]}
3
#直接输出的是数组的第一个元素
echo $array
#用下标的方式访问数组元素
echo ${array[1]}
#输出这个数组
echo ${array[@]}
#输出数组中下标为3的元素的长度
echo ${#array[3]}
#输出数组中下标 为1到3的元素
echo ${array[@]:1:3}
#输出数组中下标大于2的元素
echo ${array[@]:2}
#输出数组中下标小于2的元素
echo ${array[@]::2}
字符串
字符串切片:
${string:offset:length} 从左向右取,依稀量,加长度, 如果只指定偏移量,则偏移后,取所有字串
取尾部的指定个数的字符:
${string: -length} 加个 " - " 号,则是从右向左取
取子串:基于模式
${variable#*word}:在variable中存储字串上,自左而右,查找第一次出现word,删除字符开始至此word处的所有内容;
[root@localhost ~]# url=www.baidu.com
[root@localhost ~]# echo $url
www.baidu.com
[root@localhost ~]# echo ${url#*.} 从左到右,取第一次出现的.号,并从左开始第一个字符删除到第一次出现的字符,
baidu.com
[root@localhost ~]# echo ${url##*.} 再加一个# 是贪婪模式,找到从左到右,最后一次出现的 . 并从头到 . 删除
com
${variable##*word}:在variable中存储字串上,自左而右,查找最后一次出现word,删除字符开始至此word处的所有内容;
file='/var/log/messages'
${file#*/}: 返回的结果是var/log/messages
${file##*/}: 返回messages
${variable%word*}: 在variable中存储字串上,自右而左,查找第一次出现word,删除此word处至字串尾部的所有内容;
${variable%%world*}:在variable中存储字串上,自右而左,查找最后一次出现word,删除此word处至字串尾部的所有内容;
file='/var/log/messages'
${file%*/}: 返回的结果是/var/log
${file%%*/}: 返回结果为空
phonenumber='010-110-8'
${phonenumber%%-*}
${phonenumber##*-}
url="http://www.magedu.com:80"
遍历访问一个字符串(默认是以空格分开的,当字符串是由其他字符分隔时可以参考 2)
#!/bin/bash
str="a --m"
for i in $str
do
echo $i
done
1.长度
[root@localhost ~]$ test='I love china'
[root@localhost ~]$ echo ${#test}
12
${#变量名}得到字符串长度
2.截取字串
[root@localhost ~]$ test='I love china'
[root@localhost ~]$ echo ${test:5}
e china
[root@localhost ~]$ echo ${test:5:10}
e china
${变量名:起始:长度}得到子字符串
3.字符串删除
[root@localhost ~]$ test='//tmp/boot.ini'
[root@localhost ~]$ echo ${test#/}
/tmp/boot.ini
[root@localhost ~]$ echo ${test#*/}
/tmp/boot.ini
[root@localhost ~]$ echo ${test##*/}
boot.ini
[root@localhost ~]$ echo ${test%/*}
c:/windows
[root@localhost ~]$ echo ${test%%/*}
${变量名#substring正则表达式}从字符串开头开始配备substring,删除匹配上的表达式。
${变量名%substring正则表达式}从字符串结尾开始配备substring,删除匹配上的表达式。
注意:${test##*/},${test%/*} 分别是得到文件名,或者目录地址最简单方法。
4.字符串替换
[chengmo@localhost ~]$ test='/tmp/boot.ini'
[chengmo@localhost ~]$ echo ${test/\//\\}
/tmp/boot.ini
[chengmo@localhost ~]$ echo ${test//\//\\}
/tmp/boot.ini