Shell之可爱的变量

in 互联网技术 with 0 comment  访问: 4,052 次

上节回顾

知止,知道正则什么时候停止。

知止而后能定,定而后能静,静而后能定,安而后能虑,虑而后能得。 --- 语出<<大学>>

正则本身是个贪婪模式,当你发现 .* 会匹配所有的东西,所以应该知道正则在哪停止。

一、bash通配符

Shell常见的通配符

字符 含义 实例
* 匹配0或多个字符 a*b a与b之间可以有任意长度的任意字符,也可以一个也没有,如:aabcb,axyzb,a012b,ab。
? 匹配任意字符 a?b a与b之间必须也只能由一个字符,可以是任意字符,如aab,abb,acb,a0b.
[list] 匹配list中的任意单一字符 a[xyz]b a与b之间必须也只能有一个字符,但只能是x或y或z,如axb,ayb,azb.
[!list] 匹配除list中的任意单一字符 a[!0-9]b a与b之间必须也只能有一个字符,但不能是除阿拉伯数字.
[c1-c2] 匹配c1-c2中的任意单一字符 如:[0-9] a[0-9]b 0-9之间必须也只能有一个字符,如a0b,a1b,a2b…a9b.
{string1,string2,…} 匹配string1或者string2(或者更多)其一字符串 a{abc,xyz,123}b a与b之间只能是abc或xyz或123 这三个字符串之一.

注:此处的 * 和正则中 * 的区别,正则中 * 始终出现在命令的参数部分。

比如 ls * 中的 * 代表的是通配符,而 grep '.*' /etc/passwd 代表正则。

思考:mkdir –pv /tmp/{a,b}/{1,2,3} 一共创建了多少个文件? [:digit:] 在这里任然适用

查看一个文件名为数字文件ls –lh [[:digit:]]

二、设定变量

1、变量名=值
格式的要求:“开头必须是字母或者下划线”, “=两边不能有空格”

2、取消变量
unset 变量名

Example:
15019457621098.jpg
在其他编程语言中需要声明和区分变量类型,在shell中是不区分的,拿以上变量来说都是一个变量。

三、变量的工作范围

设定一个变量在什么样的一个范围会生效,在什么时候继承下去。

Example:
15019461179895.jpg
bash命令是在当前的进程产生一个子进程。
15019461490361.jpg
通过pstree命令可以看出整个过程。最顶端的那个进程为init,init为所有进程的父进程
15019462579246.jpg

通过上面的实例我们可以看出变量只在当前生效,那我们怎么让变量继承下去,让它在所有的子进程中都生效呢,利用export命令可以向下影响所有的子进程,实例如下:
15019469556025.jpg

系统变量和环境变量

set 返回结果包含环境变量和局部变量, env 返回结果包含环境变量。
15019471651354.jpg
15019472018555.jpg
所谓系统变量:自己定义的一个变量就是系统变量
环境变量:通过env返回的结果为环境变量

以下四个变量的执行顺序是这么排列的:

/etc/profile
~/.bash_profile
~/.bashrc
/etc/bashrc

分别定义同一个变量不同的返回值

/etc/ profile 中定义 a=123 
~/.bash_profile 中定义 a=234 
~/.bashrc 中定义 a=345 
/etc/bashrc 中定义 a=456

那么其执行的先后顺序如下:

/etc/profile /root/.bash_profile /root/.bashrc /etc/bashrc

我在root用户下

登陆shell和非登陆shell

登陆shell是指当用户登陆系统时所取得的那个shell,通过查找以上四个不同的启动文件来处理其中的命令,bash处理顺序如下:

/etc/profile(/etc/profile.d等待)-----/$home/.bash_profile------/$home/.bashrc-------/etc/bashrc

非登陆shell
/etc/bashrc 尽管不是通过bash直接调用,但是许多~/.bashrc文件调用/etc/bashrc. 这种设置使得超级用户可以为系统内的非登陆shell建立默认属性。

.bashrc非登陆 shell 执行~/.bashrc 文件中的命令,而登陆 shell 的启动文件(如.bash_profile)通常会运行这个文件。这样,登陆 shell 和非登陆 shell 都可以运行.bashrc 中的命令了。

典型的例子 susu –su – 登陆 shell su 非登陆shell.

四、变量的有意思的用法

15019506890537.jpg
15019507310309.jpg
如上图1、2对比,当a没有值的时候,临时使用hello。当a有值的时候输出a的值。

总结:${var:-word} 如果var没有值,则临时设定值为word

15019519962229.jpg
15019520344359.jpg
如上图3、4对比,当a没有值的时候,会设定为hello,当a有值时输出a的值。

总结:${var:=word}如果var没有值,设定为word,当var有值时输出a的值。

15019525381433.jpg
15019525685618.jpg
如上图5、6对比,当a有值的时候,会临时使用hello,但是本身值不变。

总结:${var:+word} 如果var有值,会临时设定为word,但是var本身的值不改变。

15019528967753.jpg
15019529218413.jpg
如上图7、8对比,如果a没有值报错,如果a有值打印出a的值。

总结: ${var:?word} 如果var没有值,报错,如果var有值打印出var的值。

15019534917926.jpg
15019535392760.jpg

总结: ${var:offset} 从变量offset位置开始,输出到结束。

${var:offset:length} 从变量offset开始,输出length

15023767391963.jpg
如图11 从右向左截取变量a中第一个-后的字符串

如图12 从右先左截取变量a中最后一个-后的字符串

总结: ${varible%string*} 从右向左截取第一个string后的字符串 , ${varible%%string*} 从右向左截取最后一个string后的字符串

15023770542133.jpg
如图13 从左往右截取变量a第一个/后的字符串

如图14 从左往右截取变量a最后一个/后的字符串

总结: ${varible#*string} 从左向右截取第一个string后的字符串, ${varible##*string} 从左向右截取最后一个string后的字符串

15020312493540.jpg
如上图15、16变量之前#是可以用来统计变量中的字符串的长度。

总结: ${#var} 用来计算变量字符串长度

以上部分是作为shell中字符串的截取的介绍,其中 * 是通配符,也可以用 ? 来的。

15020320461719.jpg
如上图17打印出系统中以P开头的变量。

总结: ${!var@} ${!var*} 打印出系统中所有以var开头的变量。两者结果是一样的,唯一不同的,@把整个当字符串处理,*把每个当字符串处理。

五、有用的自带变量

$0,$1,$2...$9 $0代表脚本自身,$1参数的位置。当然你的参数大于10时,变量的写法${10},在10上加上{}.

$# 用来计算参数的个数
$*$@ 用来显示脚本的所有参数

举例说明:

15020346977368.jpg
15020347181404.jpg

$$ 指当前shell的PID
举例
15020357259186.jpg

$_上一条命令的最后一个参数

举例:
15020363171731.jpg
15020365144632.jpg

$- 用来查看shell是否交互(himBH), 其中有i就是交互式。
举例:
15020367053620.jpg

$! 显示最后一个进入后台的作业的pid
举例:
15020368416195.jpg

$? 上一条命令的返回值,0成功,非0不成功。
举例:
15020369929416.jpg

六、有趣的操作符号

&& 前面的命令执行成功,则执行后面的命令执行
|| 前面的命令执行不成功,则后面的命令执行
; 命令的分割符号

举例:
15020376144254.jpg
&& ||这两个符号太长的时候,关键看它之前执行之后返回的结果,; 前面的命令不管成功与否都执行。

& 后台操作符号,其实它可以实现并发的效果。
举例:
15023797676599.jpg

()合并输出,()里面的命令在子shell中执行。
举例:
15023803123793.jpg
(exit;) 退出子shell, {exit;} 推出当前shell, $SHLVL这个变量 可以查到你当前shell跑到了第几层。
举例:

[root@labnode1 ~]# bash
[root@labnode1 ~]# bash
[root@labnode1 ~]# bash
[root@labnode1 ~]# bash
[root@labnode1 ~]# echo $SHLVL
5

好处是在写 shell 脚本时,观察自己的变量在第几层执行。

掌握了shell的内置变量的话和一下特殊的方法,写脚本会很有逼格哦。

| 管道,把前面执行的结果,交给后面的命令处理。
'' 强引用
“” 弱引用

举例:

[root@labnode1 ~]# echo "$a"
test
[root@labnode1 ~]# echo '$a'
$a

\ 转义字符,所谓的转义就是把字符本身的含义转化成另外一个含义,根据不同的环境进行转移。

`` 反引号,键盘数字1左边的那个反引号。实际中shell在执行过程中,先执行``里面的动作,再执行整个语句。

举例:

[root@labnode1 ~]# echo `whoami`
root
[root@labnode1 ~]#

$() 和 反引号执行效果一样,在shell脚本中建议使用$()
举例:

[root@labnode1 ~]# echo $(whoami)
root
[root@labnode1 ~]#

eval 把后面的字符串当命令来使用
举例:

[root@labnode1 ~]# eval $(echo whoami)
root
[root@labnode1 ~]#

type 查看一个变量是否是内置变量
举例:

[root@labnode1 ~]# type /bin/echo
/bin/echo is /bin/echo
[root@labnode1 ~]# type command
command is a shell builtin
[root@labnode1 ~]# type shift
shift is a shell builtin

七、数学运算和数组

复杂的数学运算可以使用bc,下面是简单的数学运算。

[root@labnode1 ~]# a=1
[root@labnode1 ~]# b=2
[root@labnode1 ~]# echo $a+$b
1+2
[root@labnode1 ~]# echo $[a+b]
3
[root@labnode1 ~]# echo $((a+b))
3
[root@labnode1 ~]# c=$a+$b
[root@labnode1 ~]# echo $((c))
3

数组:
定义数组:

Var=(word0 word1 word2 word3)

echo ${var[0]} 查看结果:

[root@labnode1 ~]# zoo=(cat pig dog)
[root@labnode1 ~]# echo ${zoo[0]}
cat
[root@labnode1 ~]# echo ${zoo[1]}
pig
[root@labnode1 ~]# echo ${zoo[2]}
dog
[root@labnode1 ~]# echo ${zoo[*]}
cat pig dog
[root@labnode1 ~]# echo ${#zoo[*]}
3
[root@labnode1 ~]# echo ${#zoo[0]}
3
[root@labnode1 ~]# unset zoo
[root@labnode1 ~]# echo ${#zoo[*]}
0
[root@labnode1 ~]# zoo=(cat pig dog)
[root@labnode1 ~]# echo ${#zoo[*]}
3
[root@labnode1 ~]# echo ${zoo[*]}
cat pig dog
[root@labnode1 ~]# 

改变数组中的元素:

[root@labnode1 ~]# zoo=(fox cat pig)
[root@labnode1 ~]# echo ${zoo[*]}
fox cat pig
[root@labnode1 ~]# zoo[1]=yak
[root@labnode1 ~]# echo ${zoo[*]}
fox yak pig
[root@labnode1 ~]#

举例:数组相当于古代的翻牌子
妃子=(华妃 甄嬛 淑妃)

本文通过Linux天使团可爱的变量文章整理。

WeZan