写完shell脚本要用chmod命令加上x(执行)权限
文件名的扩展成为通配,通配定义了一套使用特殊字符的规则。当输入文件名作为参数的命令时,可以使用特定的通配符去匹配多个文件
表1-1-1 常用的通配符
符号 | 含义 |
---|---|
* | 匹配任意字符的0次或多次出现 |
? | 匹配任意零个或单个字符 |
[ ] | 匹配字符串中所限定的任何一个字符 |
[^ ]或[! ] | 表示反向选择,匹配不在该字符串的任意字符 |
{string1,string2,…} | 匹配其中一个指定的字符串 |
eg:匹配所有以".png"结尾的,星号可放在任意位置,匹配任意一段字符。
ls *.png
?匹配任意单个字符
?*y匹配以任意单个字符开头以*y结尾的文件名
总而言之:?与*号不同,?只能匹配一个字符
[ .]中无论有多少个字符,都只代表某一个字符。例如:[hfchg]匹配以*[ ]中**任意一个字符开头,以任意内容结尾的。
"-"可以指定范围例如:[a-z]匹配a-z之间任意一个字符。
表示反向选择 例如:[^Aa]* 表示匹配不以A或者a开头的任意文件名。
匹配其中一个指定的字符串,
例如:{string1,string2} 表示依次以string1、string2与单个文件名进行完整匹配。
被单引号括起来的所有内容都是普通字符,就算特殊字符也不再有特殊含义。
由双引号括起来的字符(除$、倒引号和转义字符""以外)均是普通字符。
“$”:代表引用变量的值
“`”:倒引号代表引用命令
[root@localhost ~]# name=xiaopeng
[root@localhost ~]# echo '$name'
$name
[root@localhost ~]# echo "$name"
xiaopeng
表1-3-1 常用的输入、输出重定向
类型 | 符号 | 作用 |
---|---|---|
标准输入重定向 | command 将文件作为命令的输入 |
|
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当成系统的垃圾箱,任何放入垃圾箱的数据都会被丢弃,无法恢复。
使用";"连接多条命令,这些命令会依次执行,个命令之间没有任何逻辑关系,就算有一条命令报错后面也会继续执行。它与写成多行命令是等价的
如果使用"&&“连接多条命令,那么这些命令之间就有了逻辑关系,只有第一条命令正确执行了,”&&"连接的第二条命令才会执行。
使用"||"连接多条命令,则只有前一条命令执行错误,后一条命令才会执行。
系统如何知道前一条命令是否执行呢? 那就需要用"$?"来查看前一条命令的返回值,如果是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
用"|"表示,用来连接多条命令,前一条命令的输出是后一条命令的输入。只能处理前一条正确的输出。
[root@localhost ~]# ls /etc |more
分页显示/etc目录下的文件
当执行一些时间较长无交互的命令或者编译时,可以在命令最后加上"&"。还可以把输出结果重定向带一个文件。
shell脚本以#开头表示单行注释。
在shell脚本中第一行以#!开头后面跟shell的路径,从而调用相应的解释器。例如: #! /bin/bash
变量名:系统变量用大写字母,自定义变量用小写字母(字母、下划线开头,由字母、数字和下划线组成)
[root@localhost ~]# name=xiaopeng
[root@localhost ~]# echo "$name"
xiaopeng
变量赋值用"="
变量引用:变量名前面加上"$",
数组:用括号表示数组,数组里面的值用空格分隔、
[root@localhost ~]# arr=(zhangsan lisi wangwi)
数组也可以arr[0]=zhangsan赋值
读取数组:格式 “${数组名[下标]}”
[root@localhost ~]# echo "${arr[0]}"
zhangsan
表2-1-1 常用的预定义变量
预定义变量 | 作用 |
---|---|
$? | 上一个命令执行后的返回值(0是执行正确,非0是执行出现错误) |
$$ | 当前进程的进程号(pid) |
$! | 上一个后台命令对应的进程号(pid) |
$- | 当前在运行shell程序的选项 |
$# | 命令行上参数的个数 |
$*,$@ | 命令行上实际给出的参数($*是个整体。$@是个迭代器类似数组,可以一个一个拿到) |
$n | n为数字,$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
环境变量是系统变量(永久生效需要写入相应的配置文件),在当前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
export声明变量可以被子进程继承,用法如下:
[root@localhost ~]# name=xiaopeng
[root@localhost ~]# export name
[root@localhost ~]# bash
[root@localhost ~]# echo "$name"
xiaopeng
变量的删除: unset 变量名
[root@localhost ~]# unset name
[root@localhost ~]# echo "$name"
[root@localhost ~]#
1.使用declare声明变量
[root@localhost ~]# declare [选项] 变量名
选项:
-:给变量设定类型属性
+:取消变量的类型属性
-a:将变量声明为数组型
-i:将变量声明为整数型
-r:将变量声明为只读变量 (不能用+r取消,也不能修改变量)
-x:将变量声明为环境变量
-p:显示变量被声明的类型
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
3.使用"$((算术表达式))" 加上$符号才能返回值
[root@localhost ~]# aaa=1
[root@localhost ~]# bbb=1
[root@localhost ~]# ccc=$(($aaa+$bbb))
[root@localhost ~]# echo $ccc
2
表2-1-2 常用的算术运算符
优先级 | 算术运算符 | 作用 |
---|---|---|
1 | =、+=、-=、*=、/=、%=、&=、|=、>>=、<<= | 赋值、运算且赋值 |
2 | || | 逻辑或 |
3 | && | 逻辑与 |
4 | | | 按位或 |
5 | ^ | 按位异或 |
6 | & | 按位与 |
7 | ==、!= | 等于、不等于 |
8 | <=、>=、<、> | 小于等于、大于等于、小于、大于 |
9 | <<、>> | 按位左移、按位右移 |
10 | +、- | 加、减 |
11 | *、/、% | 乘、除、取模 |
12 | !、~ | 逻辑非、按位取反或补码 |
13 | -、+ | 单目负、单目正 |
条件测试有两种形式:一种是用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,测试条件为真 |
格式:
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
格式:
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
格式:
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"
格式:
until condition #条件不成立执行
do
命令
done
eg:求1-100的和
#! /bin/bash
sum=0
i=1
until ((i>100))
do
((sum+=i))
((i++))
done
echo "$sum"
语法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"
for 临时变量 in 取值列表
求1-6的和
sum1=0
for i in 1 2 3 4 5 6
do
((sum1+=i))
done
echo "$sum1"
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
continue 用于跳出本层循环,后面跟数字表示跳出多少层
break 用于跳出整个循环,后面跟数字表示跳出多少个循环
格式:
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
模拟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
文件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