shell元字符 & 变量介绍

shell基础

元字符

# 1.元字符介绍
[]、[!0-9]、[^a-z]
[]:代表匹配一个字符,该字符属于[]内规定的任意字符
^与!    都是取反,这里不会显示0-9的值,不会显示a-z的值
[root@Centos7 test]# ls /test/a[!-1+]b.txt		#不显示中括号中的三个字符,“-”不要写在1和+的中间
/test/a2b.txt  /test/a3b.txt


# 2.&
进程的运行状态:运行态、就绪态、阻塞态
    并发:看起来是同时运行的(实则cpu在多个进程之间来回切换)
    并行:真正意义上的同时运行,只有多核才有并行的可能性
    
# 3、*任意多个字符
ls *.txt

# 4、()在子shell进程/子进程中运行命令
[root@Centos7 ~]# (x=1)
[root@Centos7 ~]# echo $x    不会有结果输出,因为变量没有在当前环境生效,而是在子shell中
[root@Centos7 ~]# umask
0022
[root@Centos7 ~]# (umask 666;touch {a..c}.txt)		子shell中给予umask为666,不会影响当前shell
[root@Centos7 ~]# touch d.txt
[root@Centos7 ~]# ll 
total 4
-rw-------. 1 root root 1523 Jun 29 23:38 anaconda-ks.cfg
----------  1 root root    0 Aug 25 18:53 a.txt
----------  1 root root    0 Aug 25 18:53 b.txt
----------  1 root root    0 Aug 25 18:53 c.txt
-rw-r--r--  1 root root    0 Aug 25 18:53 d.txt

# 5、_  仅仅创建目录时连接使用
[root@Centos7 ~]# tar czf /bak/`date +%F_%H:%M:%S`_etc.bak.gz /etc
tar: Removing leading `/' from member names
[root@Centos7 ~]# ls /bak/
2020-08-25_18:56:29_etc.bak.gz

# 6、=赋值,==判断是否相等
x=1 变量中的赋值
[ $x == 1 ];echo $?		判断是否相等

# 7、|与xargs
很多命令并不支持管道前的输出作为当前的命令输入,可以配合xargs使用

# 8、\ 转义
[root@Centos7 ~]# echo $RMB			会当成一个变量,此变量没有结果

[root@Centos7 ~]# echo "$RMB"		加了双引号表示将内容不当成字符串,也是会当一个变量

[root@Centos7 ~]# echo "\$RMB"		将原本的$变量名打回原形,这里的$只当成一个字符串
$RMB
[root@Centos7 ~]# echo '$RMB'		单引号里面的内容都为字符串,不具有特殊含义
$RMB

# 9、{}  包含多个条件
touch {1..9}.txt  包含1-9里面的所有值都显示
touch {a..c}{1..3}.txt  包含a1.txt  a2.txt b1.txt.......
[root@Centos7 ~]# echo ${num}RMB    使用{}可区分变量和和他字符串,具有边界感
30RMB

# 10、'',""
单引号:所见即所得
双引号:里面的字符如具有特殊含义则会执行

# 11、:
冒号输出的结果都为true
[root@Centos7 ~]# :
[root@Centos7 ~]# echo $?
0
[root@Centos7 ~]# true
[root@Centos7 ~]# echo $?
0

# 12.;、&&、||
分号:前面的命令和后面的命令执行结果都不受双方影响
&&: 前面的命令执行成功就执行后面命令
||:  前面的命令执行失败就执行后面的命令
注意: && 优先级大于 ||

# 13、?匹配任意一个字符
[root@Centos7 test]# ls
1111.txt  11.txt  1.txt  2.txt  3.txt  aaaaa.txt
[root@Centos7 test]# ls *.txt
1111.txt  11.txt  1.txt  2.txt  3.txt  aaaaa.txt
[root@Centos7 test]# ls ?.txt  
1.txt  2.txt  3.txt
[root@Centos7 test]# ls ??.txt
11.txt
[root@Centos7 test]# ls ???.txt
ls: cannot access ???.txt: No such file or directory
[root@Centos7 test]# ls ????.txt
1111.txt

# 14、/ 根

# 15、> >>
1>    正确输出覆盖
2>    错误输出覆盖
&>/dev/null   正确与错误输出

# 16、~:家目录

# 17、``:取命令的运行结果,这个不支持嵌套
$():支持嵌套
[root@Centos7 test]# res=$(ls $(pwd))
[root@Centos7 test]# echo $res

# 18、!
!历史命令
!$取上一条命令的参数
取反

# 19、#注释
原则:给关键代码加注释
地方:
	1、代码的正上方单独一行
    2、代码正后方
    
# 20、$
取变量的值:
x=111
echo $x
取命令的运行结果
echo $(pwd)

# 21、+、-、*、/、%:取余数,也就是俗称的取模
[root@Centos7 test]# n=10
$[]	
	[root@Centos7 test]# echo $[$n+1]
	[root@Centos7 test]# echo $[$n-1]
	[root@Centos7 test]# echo $[$n/3]
	[root@Centos7 test]# echo $[$n%3]
	[root@Centos7 test]# echo $[$n*3]
$(())     
	[root@Centos7 test]# echo $(($n+1))
	[root@Centos7 test]# echo $(($n-1))
	[root@Centos7 test]# echo $(($n/3))
	[root@Centos7 test]# echo $(($n%3))
expr
	[root@Centos7 test]# expr $n + 1
	[root@Centos7 test]# expr $n / 3
	[root@Centos7 test]# expr $n / 300
	[root@Centos7 test]# expr $n+1  #  一定记得在运算符左右两侧加空格
	10+1
let 重新赋值会比较简单
	[root@Centos7 test]# age=18
	[root@Centos7 test]# age=$[$age+1]
	[root@Centos7 test]# echo $age
	19
	[root@Centos7 test]# let age=age+1	#此方式比较简单
	[root@Centos7 test]# echo $age
	20
	[root@Centos7 test]# let age+=1  # age=age+1
	[root@Centos7 test]# echo $age
	21
	[root@Centos7 test]# let i++    # 自增长运算
	[root@Centos7 test]# echo $i
	1
	[root@Centos7 test]# let ++j	#同样也是自增长
	[root@Centos7 test]# echo $j
	1
	[root@Centos7 test]# let x=m++   #这里先赋值再增长,所以值为0
	[root@Centos7 test]# let y=++n   #这里是先增长再赋值,所以值为1
	[root@Centos7 test]# 
	[root@Centos7 test]# echo $x
	0
	[root@Centos7 test]# echo $y
	1
前面四种都不支持浮点型运算,仅bc支持,但需要yum自行安装
bc
	[root@db01 day02]# echo $(echo "scale=2;3/10"|bc)%	#取出余数,然后自行加上百分号,求出百分比
	.30%
	[root@Centos7 test]# echo $(echo "scale=2;33/100" | bc |cut -d. -f2)% #以点为分隔符取第二位
	33%

shell脚本运行方式

方式一:

  • 绝对路径,需要当前用户对脚本文件有rx权限
[root@Centos7 ~]# /scripts/day02/hello.sh
-bash: /scripts/day02/hello.sh: Permission denied
[root@Centos7 ~]# ll !$
ll /scripts/day02/hello.sh
-rw-r--r-- 1 root root 41 Aug 25 19:43 /scripts/day02/hello.sh
[root@Centos7 ~]# chmod +x !$
chmod +x /scripts/day02/hello.sh
[root@Centos7 ~]# /scripts/day02/hello.sh
hello world

方式二:

  • ./脚本文件.sh,需要当前用户对脚本文件有rx权限
[root@Centos7 day02]# chmod o=x hello.sh 
[root@Centos7 day02]# ll hello.sh 
-rwxr-x--x 1 root root 41 Aug 25 19:43 hello.sh
[root@Centos7 day02]# su - egon
Last login: Tue Aug 25 19:48:57 CST 2020 on pts/0
[egon@Centos7 ~]$ cd /scripts/day02/
[egon@Centos7 day02]$ ./hello.sh 
bash: ./hello.sh: Permission denied

方式三:

  • 指定解释器来解释执行脚本程序,需要当前用户对脚本文件有r权限,
  • 解释:我们执行的是bash命令,所有用户对bash命令都有执行权限,所以我们只需要考虑脚本文件的读权限即可
[root@Centos7 day02]# chmod o=- hello.sh 		#使其他用户对脚本什么权限也没有
[root@Centos7 day02]# su - egon	
[egon@Centos7 ~]$ cd /scripts/day02/
[egon@Centos7 day02]$ ll
-rwxr-x--- 1 root root 26 Aug 25 19:53 hello.sh
[egon@Centos7 day02]$ bash hello.sh 		    
bash: hello.sh: Permission denied
[egon@Centos7 day02]$ exit
logout
[root@Centos7 day02]# chmod o=x hello.sh       #使普通用户对脚本只有执行权限
[root@Centos7 day02]# su - egon
Last login: Tue Aug 25 19:53:31 CST 2020 on pts/0
[egon@Centos7 ~]$ !cd
cd /scripts/day02/
[egon@Centos7 day02]$ bash hello.sh 
bash: hello.sh: Permission denied
[egon@Centos7 day02]$ exit
logout
[root@Centos7 day02]# chmod o=r hello.sh 	  #使脚本让普通用户只有读权限
[root@Centos7 day02]# su - egon
Last login: Tue Aug 25 19:54:07 CST 2020 on pts/0
[egon@Centos7 ~]$ !cd
cd /scripts/day02/
[egon@Centos7 day02]$ bash hello.sh 
hello world

方式四:

  • source在当前bash进程中运行,前三种方式都是在子bash进程中运行,所以变量不对当前bash生效
[root@Centos7 ~]# echo $x
[root@Centos7 ~]# source /scripts/day02/hello.sh
hello world
[root@Centos7 ~]# cat !$
cat /scripts/day02/hello.sh
x=111
echo "hello world"
[root@Centos7 ~]# echo $x
111
[root@Centos7 ~]# unset x
[root@Centos7 ~]# . /scripts/day02/hello.sh
hello world
[root@Centos7 ~]# echo $x
111


# 总结:
source和.的方式执行脚本是在当前bash执行,此方式并不对推荐,污染了当前bash环境

变量

一、变量的介绍

# 1、什么是变量
量:记录事物的状态
变:事物的状态是可以发生变化的

# 2、为何要有变量
书面解释:变量是编程语言为我们提供的一种存取内存的机制
大白话:编程语言里之所有有变量这种语法是为了让计算机能够像人一样去记忆事物的状态

# 3、如何用变量
原则:先定义、后引用
x=1  # 等号左右两侧不要有空格

echo $x

# 注意:没有事先定义变量而取值,会取到空,但是不会报错
[root@Centos7 ~]# echo $x

[root@Centos7 ~]# x=111
[root@Centos7 ~]# echo $x
111
[root@Centos7 ~]# 

# 删除变量
[root@Centos7 ~]# x=111
[root@Centos7 ~]# echo $x
111
[root@Centos7 ~]# unset x
[root@Centos7 ~]# echo $x

二、变量命名规范

# 注意:变量名的命令应该见名知意,同时遵循如下规则
以字母或下划线开头,剩下的部分可以是:字母、数字、下划线,最好遵循下述规范:
    1.以字母开头
    2.使用中划线或者下划线做单词的连接
    3.同类型的用数字区分
    4.对于文件最好加上拓展名
例如: sql_bak.tar.gz,log_bak.tar.bz2  
    5、不要带有空格、?、*等特殊字符
    6、不能使用bash中的关键字,例如if,for,while,do等
    7、不要和系统环境变量冲突
    
# 示例
[root@Centos7 ~]# xxx=18
[root@Centos7 ~]# age=18
[root@Centos7 ~]# salary=18
[root@Centos7 ~]# num=18
[root@Centos7 ~]# gender="male"
[root@Centos7 ~]# ip="1.1.1.1"
[root@Centos7 ~]# age_of_egon=18
[root@Centos7 ~]# AgeOfEgon=18 

三、变量值三种来源

1、直接赋值

[root@Centos7 ~]# age=18
[root@Centos7 ~]# salary=3.1
[root@Centos7 ~]# name="egon"
[root@Centos7 ~]# name="EGON"
[root@Centos7 ~]# echo $name	 #变量读取方式为从上至下读取,所以最下面的会覆盖最上面的
EGON

2、从键盘输入读取值来赋值给变量名

# -p参数:指定提示信息
[root@Centos7 ~]# read -p "请输入你的操作>>>: " cmd
请输入你的操作>>>: start
[root@Centos7 ~]# echo $cmd
start

# -t参数:指定超时时间,超出时间,自动退出
[root@Centos7 ~]# read -t3 -p ">>>: " x
>>>: [root@Centos7 ~]# echo $x

# -n参数:指定读取的字符个数,最多输入字符数,超出自动退出
[root@Centos7 ~]# read -n2 -p ">>>: " x
>>>: 11[root@Centos7 ~]# read -n2 -p ">>>: " x
[root@Centos7 ~]# read -n3 -p ">>>: " x
>>>: 111[root@Centos7 ~]# echo $x
111


# 练习题:
[root@Centos7 day02]# cat login.sh 
#!/bin/bash
db_user="egon"
db_pwd="123"
read -p "请输入您的账号: " username
read -p "请输入您的密码: " password
[ $username == $db_user -a $password == $db_pwd ] && echo "登录成功" || echo "登录失败"

[root@Centos7 day02]# chmod +x login.sh 
[root@Centos7 day02]# ./login.sh 
请输入您的账号: xxx
请输入您的密码: 123
登录失败
[root@Centos7 day02]# ./login.sh 
请输入您的账号: egon
请输入您的密码: 123
登录成功

3.位置参数$n

$0 $1 $2 $3..${10} 
[root@Centos7 day02]# ./server.sh start
./server.sh #表示为$0
start		#表示为$1
${10}		#当有两个字符时需要用花括号

[root@Centos7 day02]# cat server.sh 
#!/bin/bash
echo $0
echo $1
echo $2
echo $3
echo $4
echo $5
echo $6
echo $7
echo $8
echo $9
echo ${10}
echo ${11}

[root@Centos7 day02]# ./server.sh 111 222 333 444 555 666 777 888 999 1000 2000
./server.sh
111
222
333
444
555
666
777
888
999
1000
2000

四、变量的操作

1.求长度

# 面试题
[root@Centos7 day02]# age=111
[root@Centos7 day02]# echo ${age}
111
[root@Centos7 day02]# echo ${#age}
3
[root@Centos7 day02]# echo $age | wc -L
3
[root@Centos7 day02]# echo $age | awk "{print length}"
3

2.切片(了解)

[root@Centos7 day02]# msg="hello world"
[root@Centos7 day02]# echo ${msg}
hello world
[root@Centos7 day02]# echo ${msg:4}	         #前面四位不取
o world
[root@Centos7 day02]# echo ${msg:4:3}        #取第四位字符,并且只取三位
o w
[root@Centos7 day02]# echo ${msg::3}		#取前三位
hel

3、截断

# 1、删除左边的
[root@Centos7 day02]# url="www.sina.com.cn"
[root@Centos7 day02]# echo ${url#www.}		#从左边开始不显示www.
sina.com.cn
[root@Centos7 day02]# echo ${url#*.}		#从左边开始不显示所有内容,直到匹配到.
sina.com.cn
[root@Centos7 day02]# echo ${url##*.}		#贪婪匹配,从左开始匹配到最后一个点为止
cn

# 2、删除右边的
[root@Centos7 day02]# url="www.sina.com.cn"
[root@Centos7 day02]# echo ${url%.cn}		#从右开始,不显示.cn
www.sina.com
[root@Centos7 day02]# echo ${url%.*}		#从右开始,不显示所有内容,直到匹配到*
www.sina.com
[root@Centos7 day02]# echo ${url%%.*}		#从右开始,贪婪匹配,匹配到最左侧一个.为止
www
[root@Centos7 day02]# echo ${url%%w*}		#从右开始,贪婪匹配,直到匹配到最左侧的一个w

[root@Centos7 day02]# echo ${url%w*}		#从右开始,匹配到第一个w结束,然后取出剩下内容显示
ww


# 3、示例
[root@www ~]# hostname
www.oldboy.com
[root@www ~]# echo $HOSTNAME
www.oldboy.com
[root@www ~]# echo ${HOSTNAME%%.*}
www
[root@www ~]# echo ${HOSTNAME#www.}
oldboy.com

4.变量的替换

# 变量值的替换
[root@www ~]# url="www.sina.com.cn"
[root@www ~]# echo ${url/./}		#将.替换为空,类似于删除第一个点
wwwsina.com.cn
[root@www ~]# echo ${url//./}  		# 贪婪匹配所有的点,然后全部替换为空
wwwsinacomcn
[root@www ~]# echo ${url//./|}		# 贪婪匹配所有的.然后替换为|	
www|sina|com|cn

# 应用(使用for循环将_linux删除)
[root@www test]# ls
egon_2020_01_linux.txt  egon_2020_03_linux.txt  egon_2020_05_linux.txt
egon_2020_02_linux.txt  egon_2020_04_linux.txt
[root@www test]# 
[root@www test]# echo `ls /test/`
egon_2020_01_linux.txt egon_2020_02_linux.txt egon_2020_03_linux.txt egon_2020_04_linux.txt egon_2020_05_linux.txt
[root@www test]# for fname in `ls /test/`
> do
>     echo $fname
> done
egon_2020_01_linux.txt
egon_2020_02_linux.txt
egon_2020_03_linux.txt
egon_2020_04_linux.txt
egon_2020_05_linux.txt
[root@www test]# for fname in `ls /test/`; do mv $fname ${fname/_linux/}; done
[root@www test]# ls 
egon_2020_01.txt  egon_2020_02.txt  egon_2020_03.txt  egon_2020_04.txt  egon_2020_05.txt

5.变量的替代(了解)

# 注意:
· 这里的替代仅作为临时使用,并不会改变真实的变量值

#1、${parameter-word}: 当调取变量没有定义过,就返回word字符串信息
[root@www ~]# unset x
[root@www ~]# echo ${x-111}
111
[root@www ~]# x=333
[root@www ~]# echo ${x-111}
333
[root@www ~]# echo ${x-111}


#2、${parameter:-word}: 当调取变量没有定义过或者是定义过变量但是值为空, 就返回word字符串信息
[root@www ~]# unset x
[root@www ~]# echo ${x:-111}   # 变量从未定义过
111
[root@www ~]# x=333
[root@www ~]# echo ${x:-111}  # 变量定义过,并且值为333
333
[root@www ~]# echo ${x:-111}  # 变量定义过,并且值为空
111

#3、{parameter:=word}:当调取变量信息值为空时或未定义,则设置指定字符串为新的变量值
[root@www ~]# unset x
[root@www ~]# echo ${x:=111}
111
[root@www ~]# echo $x
111
[root@www ~]# echo ${x:=111}
111
[root@www ~]# echo $x
111
[root@www ~]# x=333
[root@www ~]# echo ${x:=111}
333
[root@www ~]# echo $x
333

#4、${parameter:?word}:当调取变量信息值为空时或未定义,指定为赋值的错误提示信息
[root@www ~]# unset x
[root@www ~]# echo ${x:?变量不存在傻叉}
-bash: x: 变量不存在傻叉
[root@www ~]# x=
[root@www ~]# echo ${x:?变量不存在傻叉}
-bash: x: 变量不存在傻叉
[root@www ~]# x=123
[root@www ~]# echo ${x:?变量不存在傻叉}
123

#5、${parameter:+word}:当调取变量信息值为空时或未定义,不做任何处理,否则word字符串将替代变量值
[root@www ~]# unset x
[root@www ~]# echo ${x:+111}  #  没有定义x,此时属于没有值的范畴
[root@www ~]# echo $x
[root@www ~]# echo ${x:+111}  # 定义了x但是x的值为空,此时也属于没有值的范畴
[root@www ~]# echo $x

[root@www ~]# x=333
[root@www ~]# echo ${x:+111}  # x有值,有值则替代
111
[root@www ~]# echo $x # 替代不等于赋值
333

6.只读变量(了解)

# 注意:
· 只读变量也就类似于python的常量,无法对变量进行修改

[root@www ~]# age=18
[root@www ~]# readonly age
[root@www ~]# age=19
-bash: age: readonly variable
[root@www ~]# expr $age + 1
19
[root@www ~]# age=`expr $age + 1`
-bash: age: readonly variable
[root@www ~]# 

7.预定义变量

$*:获取命令行传入的所有的位置参数
$@:获取命令行传入的所有的位置参数
# ps:当调用的脚本格式如下形式,必须使用"$@",会将引号中的空格左右两个命令连接使用
[root@www day03]# ./4.sh aaa bbb ccc "ddd eee"  # 注意"ddd eee"
$#:获取命令行传入的所有的位置参数的个数
$$: 获取当前进程的pid  # $PPID  $UID
$?: 获取上一条命令的执行状态,0代表成功,非0代表失败
 
 # 示例1:$*与$@的区别
[root@www day03]# cat 4.sh 
#!/bin/bash
for i in $*
do
    echo $i
done

echo "================"

for i in $@
do
    echo $i
done

 [root@www day03]# ./4.sh aaa bbb ccc "ddd eee"
aaa
bbb
ccc
ddd
eee
================
aaa
bbb
ccc
ddd
eee

 
 # 示例2:$*与$@的区别
[root@www day03]# cat 5.sh 
#!/bin/bash
#for i in "$*"
#do
#    echo $i
#done

echo "================"

for i in "$@"
do
    echo $i
done
[root@www day03]# 

[root@www day03]# ./5.sh aaa bbb ccc "ddd eee"
================
aaa
bbb
ccc
ddd eee

# 示例3:(判断ip地址是否能正常连通)
[root@www day03]# cat ping.sh 
#!/bin/bash
for ip in $*
do
    ping -c1 $ip &>/dev/null
    [ $? == 0 ] && echo "$ip:up" || echo "$ip:down"

done
[root@www day03]# ./ping.sh 127.0.0.1 10.10.0.10 10.10.0.11 172.168.11.12
127.0.0.1:up
10.10.0.10:down
10.10.0.11:down
172.168.11.12:down

# 示例4:(针对操作3的一种优化,更加快速)
[root@www day03]# cat ping2.sh 
#!/bin/bash
for ip in $*
do
    (ping -c1 $ip &>/dev/null ; [ $? == 0 ] && echo "$ip:up" >> ping.log || echo "$ip:down" >> ping.log) &

done
posted @ 2020-08-25 17:38  元气少女郭德纲!!  阅读(414)  评论(0编辑  收藏  举报