关于shell编程需要记忆(基础)

关于shell编程需要记忆(基础)

写完shell脚本要用chmod命令加上x(执行)权限

一、shell基础

一、通配符

文件名的扩展成为通配,通配定义了一套使用特殊字符的规则。当输入文件名作为参数的命令时,可以使用特定的通配符去匹配多个文件

表1-1-1 常用的通配符

符号含义
*匹配任意字符的0次或多次出现
?匹配任意零个或单个字符
[ ]匹配字符串中所限定的任何一个字符
[^ ]或[! ]表示反向选择,匹配不在该字符串的任意字符
{string1,string2,…}匹配其中一个指定的字符串

1.*(星号)

eg:匹配所有以”.png”结尾的,星号可放在任意位置,匹配任意一段字符。

ls *.png
1

2.?(问号)

?匹配任意单个字符

?*y匹配以任意单个字符开头以*y结尾的文件名

总而言之:?与*号不同,?只能匹配一个字符

3.[](一对方括号)

[ .]中无论有多少个字符,都只代表某一个字符。例如:[hfchg]匹配以*[ ]中**任意一个字符开头,以任意内容结尾的。

“-“可以指定范围例如:[a-z]匹配a-z之间任意一个字符。

4.[^]或者 [!]

表示反向选择 例如:[^Aa]* 表示匹配不以A或者a开头的任意文件名。

5.{}

匹配其中一个指定的字符串,

例如:{string1,string2} 表示依次以string1、string2与单个文件名进行完整匹配。

二、引号

1.’’单引号

被单引号括起来的所有内容都是普通字符,就算特殊字符也不再有特殊含义。

2.””双引号

由双引号括起来的字符(除$、倒引号和转义字符””以外)均是普通字符。

​ “$”:代表引用变量的值

​ “`”:倒引号代表引用命令

[root@localhost ~]# name=xiaopeng
[root@localhost ~]# echo '$name'
$name
[root@localhost ~]# echo "$name"
xiaopeng
12345

三、输入、输出重定向符

表1-3-1 常用的输入、输出重定向

类型符号作用
标准输入重定向command <file将文件作为命令的输入
command <<分界符从标准输入中读入,直到遇见分界符才停止
标准输出重定向command >file以覆盖的方式,把command正确输出结果输出到file文件中
command >>file以追加的方式,把command正确输出结果输出到file文件中
标准错误输出重定向command 2>file以覆盖的方式,把command的错误结果输出到file文件中
command 2>>file以追加的方式,把command的错误结果输出到file文件中

标准输入stdin、标准输出stdout和错误输出stderr的文件描述符分别是0、1、2。(一般0和1可以不写)

如果要把正确的结果和错误的结果都保存到一个文件里,可以用 ls >file 2>&1

如果既不想把输出结果保存到文件里面也不想显示在屏幕上,那么可以把命令的所有结果重定向到 /dev/null,可以把/dev/null当成系统的垃圾箱,任何放入垃圾箱的数据都会被丢弃,无法恢复。

四、命令执行操作符

1.顺序执行

使用”;”连接多条命令,这些命令会依次执行,个命令之间没有任何逻辑关系,就算有一条命令报错后面也会继续执行。它与写成多行命令是等价的

2.逻辑与

如果使用”&&“连接多条命令,那么这些命令之间就有了逻辑关系,只有第一条命令正确执行了,”&&”连接的第二条命令才会执行。

3.逻辑或

使用”||”连接多条命令,则只有前一条命令执行错误,后一条命令才会执行。

系统如何知道前一条命令是否执行呢? 那就需要用”$?”来查看前一条命令的返回值,如果是0则执行成功,如果是非0就执行错误。

五、小括号和大括号

小括号可以直接把若干命令括起来

大括号需要再{后面加一个空格,}前面加一个分号,大括号必须在结尾加上分号表示终止

小括号和大括号都可以将若干命令括起来(分号隔开),区别是:小括号执行组成命令时需要开启一个子shell来执行,大括号直接在当前(父)shell中执行。

[root@localhost test]# cd 
[root@localhost ~]# (cd /etc;pwd)
/etc
[root@localhost ~]# { cd /etc;pwd;}
/etc
[root@localhost etc]# 
毋庸置疑:大括号执行以后父shell的路径就到了etc
1234567

六、管道符、后台命令符和注释符

1.管道符”|”

用”|”表示,用来连接多条命令,前一条命令的输出是后一条命令的输入。只能处理前一条正确的输出。

[root@localhost ~]# ls /etc |more
分页显示/etc目录下的文件
12

2.后台命令符”&”

当执行一些时间较长无交互的命令或者编译时,可以在命令最后加上”&”。还可以把输出结果重定向带一个文件。

3.注释符”#”

shell脚本以#开头表示单行注释。

在shell脚本中第一行以#!开头后面跟shell的路径,从而调用相应的解释器。例如: #! /bin/bash

二、shell编程

一、变量

1.用户自定义变量

变量名:系统变量用大写字母,自定义变量用小写字母(字母、下划线开头,由字母、数字和下划线组成)

[root@localhost ~]# name=xiaopeng
[root@localhost ~]# echo "$name"
xiaopeng
123

变量赋值用”=”

变量引用:变量名前面加上”$”,

数组:用括号表示数组,数组里面的值用空格分隔、

[root@localhost ~]# arr=(zhangsan lisi wangwi)
数组也可以arr[0]=zhangsan赋值
12

读取数组:格式 “${数组名[下标]}”

[root@localhost ~]# echo "${arr[0]}"
zhangsan
12

2.系统预定义变量

表2-1-1 常用的预定义变量

预定义变量作用
$?上一个命令执行后的返回值(0是执行正确,非0是执行出现错误)
$$当前进程的进程号(pid)
$!上一个后台命令对应的进程号(pid)
$-当前在运行shell程序的选项
$#命令行上参数的个数
$*,$@命令行上实际给出的参数($*是个整体。$@是个迭代器类似数组,可以一个一个拿到)
$nn为数字,$0是命令本身,$$1-9 代 表 第 1 − 9 个 位 置 上 的 参 数 , 10 以 上 的 参 数 需 要 用 9代表第1-9个位置上的参数,10以上的参数需要用9代表第1−9个位置上的参数,10以上的参数需要用${10}

位置参数除了运行时传递参数外,还可以利用set命令赋值

shift命令可以把参数往左移一位,注意不能移走$0(命令本身)。

[root@localhost test]# cat sh0
#! /bin/bash
set agr1 arg2
echo "$1"
shift
echo "$1"
#注意两次都是打印的$1,但是结果会不同,原因是因为shift移动了参数。
[root@localhost test]# ./sh0
agr1
arg2
12345678910

3.环境变量

环境变量是系统变量(永久生效需要写入相应的配置文件),在当前shell和所有子shell中都生效。

使用env或者export可以查看已经定义的所有环境变量

HOME:用户家目录的绝对路径

PATH:shell查找命令的列表。决定了shell将到那些目录中寻找命令或者可执行程序,当用户输入命令或可执行程序时,Linux在这些目录下按顺序依次搜寻。

PS1:shell的主提示符

PWD:当前工作目录的绝对路径

SHELL:当前使用的shell

[root@localhost ~]# echo $HOME
/root
[root@localhost ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/usr/local/python3/bin:/root/bin
[root@localhost ~]# echo $PS1
[\u@\h \W]\$
[root@localhost ~]# echo $PWD
/root
[root@localhost ~]# echo $SHELL
/bin/bash
12345678910

export声明变量可以被子进程继承,用法如下:

[root@localhost ~]# name=xiaopeng
[root@localhost ~]# export name
[root@localhost ~]# bash
[root@localhost ~]# echo "$name"
xiaopeng
12345

变量的删除: unset 变量名

[root@localhost ~]# unset name
[root@localhost ~]# echo "$name"

[root@localhost ~]# 

12345

4.数值运算

1.使用declare声明变量

[root@localhost ~]# declare [选项] 变量名
选项:
-:给变量设定类型属性
+:取消变量的类型属性
-a:将变量声明为数组型
-i:将变量声明为整数型
-r:将变量声明为只读变量 (不能用+r取消,也不能修改变量)
-x:将变量声明为环境变量
-p:显示变量被声明的类型
123456789

2.使用let命令和expr命令

[root@localhost ~]# a=1
[root@localhost ~]# b=1
[root@localhost ~]# let c=$a+$b
[root@localhost ~]# echo $c
2
-----expr----运算符左右必须有空格
[root@localhost ~]# aa=1
[root@localhost ~]# bb=2
[root@localhost ~]# cc=$(expr $aa + $bb)
[root@localhost ~]# echo $cc
3
1234567891011

3.使用”$((算术表达式))” 加上$符号才能返回值

[root@localhost ~]# aaa=1
[root@localhost ~]# bbb=1
[root@localhost ~]# ccc=$(($aaa+$bbb))
[root@localhost ~]# echo $ccc
2
12345

表2-1-2 常用的算术运算符

优先级算术运算符作用
1=、+=、-=、*=、/=、%=、&=、|=、>>=、<<=赋值、运算且赋值
2||逻辑或
3&&逻辑与
4|按位或
5^按位异或
6&按位与
7==、!=等于、不等于
8<=、>=、<、>小于等于、大于等于、小于、大于
9<<、>>按位左移、按位右移
10+、-加、减
11*、/、%乘、除、取模
12!、~逻辑非、按位取反或补码
13-、+单目负、单目正

二、控制结构

1.条件测试:

条件测试有两种形式:一种是用test命令;另一种是将一对方括号(方括号里面头尾加括号)将测试条件括起来。

test condition 等价于 [condition]

表2-2-1 文件测试运算符的形式及功能

参数作用
-r若文件存在且用户可读,测试条件为真
-w若文件存在且用户可写,测试条件为真
-x若文件存在且用户可执行,测试条件为真
-f若文件存在且是普通文件,测试条件为真
-d若文件存在且是目录文件,测试条件为真
-b若文件存在且是块设备文件,测试条件为真
-c若文件存在且是字符设备文件,测试条件为真
-s若文件存在且文件长度大于0,测试条件为真
-e该文件是否存在

表2-2-2 字符串测试运算符的形式及功能

参数作用
-z s1若字符串s1的长度为0,则初始条件为真
-n s1若字符串s1的长度大于0,则测试条件为真
s1 = s2若s1=s2,测试条件为真
s1 != s2若s1不等于s2,测试条件为真

表2-2-3 数值测试运算符的形式及功能

需要记几个常用的英文单词,就很容易了。

equal:平等的 greater than:大于 less then :小于

参数作用
n1 -eq n2若n1等于n2,测试条件为真
n1 -ne n2若n1不等于n2,测试条件为真
n1 -lt n2若n1小于n2,测试条件为真
n1 -le n2若n1小于等于n2,测试条件为真
n1 -gt n2若n1大于n2,测试条件为真
n1 -ge n2若n1大于等于n2,测试条件为真

2.if语句(判断语句)

格式:

if [ 条件判断式1 ]

​ then 命令1

​ elif [ 条件判断式2 ]

​ then 命令2

​ else 命令3

fi

#! /bin/bash
echo -n "请输入一个数字:(1-10):"
read a
if [ $a -lt 0 ] || [ $a -gt 10 ]
    then echo "错误的数字,程序结束!" 
        exit 2  
    elif [ $a -lt 5 ] 
    then echo "$1 小于 5"  
    else echo "$1 is 大于等于  5"  
fi
12345678910

3.case语句(选择语句)

格式:

case $变量名 in

​ “值1”) 命令;; #双分号代表该段程序结束

​ “值2”) 命令;;

​ *) 命令;; #这里的*号表示以上都不执行的时候执行它

esac

#! /bin/bash
echo -n "please input number:"
read a
case $a in
	"1") echo "is one";;
	"2") echo "is two";;
	"3") echo "is three";;
	"4") echo "is four";;
	"5") echo "is five";;
	*) echo "error";;
esac
1234567891011

4.while语句(循环语句)

格式:

while condition #条件成立执行

do

​ 命令

done

eg:输入一个数字来求1-这个数字的和
#! /bin/bash
echo -n "please input number:"
read a
i=1
sum=0
while [ $i -le $a ]
do
	let sum+=i
	let i++
done
echo "the sum is $sum"
123456789101112

5.until语句(循环语句)

格式:

until condition #条件不成立执行

do

​ 命令

done

eg:求1-100的和
#! /bin/bash
sum=0
i=1
until ((i>100))
do
	((sum+=i))
	((i++))
done
echo "$sum"

1234567891011

6.for语句(循环语句)

语法1:

for((exp1;exp2;exp3))

do

​ 命令

done

求1-100的和
#! /bin/bash
sum=0
for ((i=1;i<=100;i++))
do
((sum+=i))
done
echo "$sum"

123456789

7.for…in语句(循环语句)

for 临时变量 in 取值列表

求1-6的和
sum1=0
for i in 1 2 3 4 5 6
do
((sum1+=i))
done
echo "$sum1"
1234567

8.select in语句(循环语句) 适合终端交互场景

select 临时变量 in 取值列表

do

​ 命令

done

通常和case in 一起用
#! /bin/bash
echo "Whit is your favourite OS:"
select name in "windows" "mac os" "linux" "unix" "android"
do
    case $name in
        "windows") 
            echo "windows是微软发明的" 
            break;;     
        "mac os") 
            echo "mac是苹果公司基于unix开发的一个图形化界面操作系统" 
            break;;     
        “linux”) 
            echo "linux是类Unix操作系统,它开源免费" 
            break;;     
        "unix") 
            echo "unix是操作系统的开山鼻祖" 
            break;;     
        "android")
            echo "android是谷歌公司开发的,基于Linux操作系统"
            break;;     
        *)      
            echo "输入错误,请重新输入" 
    esac
done

1234567891011121314151617181920212223242526

9.continue和break

continue 用于跳出本层循环,后面跟数字表示跳出多少层

break 用于跳出整个循环,后面跟数字表示跳出多少个循环

三、shell函数

格式:

funtinue name() {

​ 命令

​ [return 返回值可有可无]

}

调用:shell函数在定义时不能指明参数,但是在调用的时候可以传递参数,并且传递声明参数它就接收什么参数。不限制函数函数定义的位置,可以在前面调用也可以在后面调用。

#! /bin/bash
function test(){
	echo $1
	echo $2
	echo $3
}
test 1 2 3 4
[root@localhost test]# ./function 
1
2
3
1234567891011

脚本实例

模拟Linux登录

#! /bin/bash
read -p "login:" name
read -p "password:" password
if [ "$name" = "zxp" -a "$password" = "123456" ]
    then echo  "welcome to linux"
else
    echo "input is error"
fi

123456789

文件newusers给出了新用户名单,为新用户创建账号密码。登录名为newusers文件里面的名字,先检查是否存在,若存在则提示”xx已经存在”,若不存在则该创建用户

[root@localhost test]# cat newusers 
test1
test2
test1
test3
test5
test6
test7
test2

#! /bin/bash
read -p "please input the user password:" password
for i in `cat newusers`
do
    id $i >/dev/null 2>&1
    if [ $? -eq 0 ] 
        then echo "$i用户已存在!" 
    else
         useradd $i -p $password >/dev/null 2>&1
        if [ $? -eq 0 ] 
            then echo "$i 创建成功"
        else    
            echo "$i 创建失败"
        fi      
    fi  
done

原创文章,作者:Zhu, Yuanyuan,如若转载,请注明出处:https://www.yidc.net/archives/7347