• Home
  • About
    • Road to Coding photo

      Road to Coding

      只要那一抹笑容尚存, 我便心无旁骛

    • Learn More
    • Email
    • Github
  • Posts
    • All Posts
    • All Tags

ShellScript(二)

05 Dec 2017

开始学shell挺有意思的,弱类型的语言再也没有写C的时候,那么多繁文缛节了,真特么爽,不过有爽的地方

就有扣脚的地方…

shell中的变量

首先,shell中的变量分为两类,局部变量和环境变量(全局变量)

局部变量

是每一个shell中可以使用的变量,在不同的shell中,是不能进行使用的

那么,如何界定一个shell呢?

bash shell是根据进程号进行界定的,对于每一个进程号,视为一个shell

环境变量

在学习Bash中提到过,环境变量,就是指在父shell以下的shell中都可以使用的变量

shell的环境变量是传下不传上,即向下的子shell,孙shell都可以继承该环境变量

而向上,父shell的父shell是不能使用的.

来举个实际的例子,Linux操作系统,登录时就是一个shell.

所以在他下面的所有子/孙shell的都可以继承环境变量

预设的环境变量

在shell中还预设了许多环境变量,这些变量可以直接使用,在shell脚本或者console交互界面

想让我给你详解吗,做梦,自己看去,

变量的操作

在shellscript中,变量的赋值,取值与C中还是有与很大的不同的

1. 定义变量

不需要进行类型的声明,弱类型,直接 “变量名=变量值”即可

注意,变量名与值之间仅仅相连,不允许有空格

当变量值中需要空格的时候,使用单/双引号括起来,不然会出现错误

[Crow@EvilCrow ~]$ var=5
[Crow@EvilCrow ~]$ echo $var
5
[Crow@EvilCrow ~]$ var = 6
bash: var: command not found

2. 变量取值

使用变量的值的时候,可以使用 “$变量名”,进行值的获取

严谨一点的写法: ${变量名}

看下面的例子:

[Crow@EvilCrow ~]$ var=Crow
[Crow@EvilCrow ~]$ echo Crow
Crow
[Crow@EvilCrow ~]$ echo $varhello           --bash将varhello视为一个变量

[Crow@EvilCrow ~]$ echo ${var}hello         --bash可以识别var为变量,并非是varhello
Crowhello

同时,如果需要引用其他变量,必须使用部分引用(弱引用)” “ 如果使用**强引用 ‘ ‘ **

则并不会进行变量的引用,会将一切视为普通字符

[Crow@EvilCrow ~]$ var=5
[Crow@EvilCrow ~]$ str="$var"
[Crow@EvilCrow ~]$ echo $str
5
[Crow@EvilCrow ~]$ str='$var'
[Crow@EvilCrow ~]$ echo $str
$var

3.取消变量

变量,可以设置,但是有的时候,我们就是想取消变量,那怎么办呢?

使用unset命令可以取消命令,也可以取消函数

declare var
var=5

func_1()
{
    echo "In func_1"
}

echo "var = $var"
func_1
unset var
unset func_1

echo "After unset"
echo "var = $var"
func_1

4. 特殊变量

常用的特殊变量有以下两类:

位置变量: $0,$1,$2,$3,$#,$@,$* ,之前已经提过,不再赘述

脚本/命令的返回值: $? ,仅能表示上一个命令的返回值,成功为0,反之为非0

数组(Array)

数组,一直是个神奇的东西,很多语言都对其支持,而且合理使用数组,可以方便进行程序设计

在shellscript中数组,虽然没有其他地方强大,不过也差不到哪里去

首先,看看与其他语言数组的不同之处:

1> 区别于C/C++/Java这些编译型语言,sh为弱类型,所以,数组的元素是不会考虑类型的

2> 在大多数语言中,都是支持高维数组的,但是,sh中仅仅支持到一维数组

1.定义数组

定义数组很简单

declare -a array      --即定义了一个数组

array[0]=0            --对数组中元素进行赋值
array[1]=1

数组使用起来还是比较像其他语言的,同时可以使用下标进行访问

同时,声明数组,也可以不使用declare关键字,不过就需要声明的同时进行初始化

declare -a name=("Crow" "Sue")
name=("Crow" "Sue")

sh中进行数组元素的增加是很简单的,声明数组后,进行赋值即可

未定义的下标,可以直接使用进行赋值

sh中数组用空格进行元素得分隔,不是使用逗号

declare -a array=(1 2)

array[2]=3
array[4]=6

echo ${array[*]}

2.数组操作

数组操作,在以往的语言中,都是基于函数,方法来进行操作的,毕竟OOP

但是,在sh中会带给你一种全新的方式进行数组的操作

1> 数组取值操作

数组进行取值时,直接使用下标,*进行索引取值即可,即 ** $ { 数组名 [ 索引 ] } **

同时,@,* 进行整个数组元素的索引方式,还是可以用的,

比如: ${array[@]} ,${array[*]}

不过,使用@,元素时列表的形式,但是,使用*,元素是字符串的形式

2> 求取数组的长度

在C中使用strlen( )函数

在Ruby中使用String.length方法获取字符串长度

在sh中使用 类似于VimScript的方式,进行数组的操作

${#array[@]},${#array[*]},即可获取到数组的长度

使用,(下标为N),${#array[N]},获取字符串的长度

3> 数组截取

数组,还可以截取吗?

答案是肯定的

数组进行截取的时候,遵循这样的操作规范

${array[X]:m:n}:  m表示下标/索引/index

当X = */@ 时,表示,截取到从m个元素开始的n个元素

反之,表示,截取X元素从m开始的n个字符

这里,切不可理解为m~n个字符

var="helloworld"
echo ${#var}
echo ${var:0:2}
echo ${var:5:2}
var=('Crow' 'Sue')
echo ${var[@]:0:2}
echo ${var[@]:0:1}
echo ${var[@]:1:1}
echo ${var[1]:1:1}

4> 连接数组(拼接数组)

在其他语言中,合并数组,需要重新分配内存,使用for循环进行赋值,很是麻烦

在sh中,如下即可

name=("Crow" "Sue")
address=("Xi'an" "Shanghai")
other=(${name[@]} ${address[@]})
echo ${other[@]}    #=> Crow Sue Xi'an Shanghai

所以,很是方便吧?

5> 替换元素

即改变数组中某个元素的值

讲道理,其实,直接进行赋值即可,但是,sh提供的方法,姑且看看吧.

array=(${array[@]/Crow/Evil})

即在数组全局中进行替换,这个特性,我不是很苟同

6> 取消数组/元素

同上理,使用unset可以取消,数组,变量,函数,全部可以取消

只读变量

这一部分也是很简单的

用法:将变量声明为只读属性,变成常量,避免滥用

declare -r a=5       --a,已经具有readonly属性

更简单地理解方式,const变量,,,

变量的作用域

这一部分内容,其实之前也是提到了很多次

作用域,即变量的有效作用范围,可以使用,被声明,被分配内存,可以访问的区域

在sh中,默认是全局变量(环境变量),这个全局指的是,这一个shell

在交互界面,就是这一个终端窗口,在脚本里,就是这一个脚本文件,都是有效范围

而C,是作为auto属性的自动变量,一般是函数中的局部变量,无链接

sh中的环境变量,有好有坏,进行程序设计时,各个函数间传参数很方便,很容易操纵,但同时

也有不小的弊端,,比如一些基本的临时变量,循环变量,这些i,j,k,如果进行模块化的开发

十分危险! ! !

有以下两种方法进行处理:

1.进行变量命名时,谨慎命名,命名为不易重复,含义明确的变量名

2.使用local命令,可以使变量的作用域局限在函数内部

看下面这个例子:

declare var
var=5
func_1()
{
    var=6
    echo "var = $var in func_1"
}
func_2()
{
    var=8
    echo "var = $var in func_2"
}
func_3()
{
    local var=1000
    echo "local var = $var in func_3"
}
func_1 
func_2 
func_3

转义和引用

其实转义和引用两个概念,我们平时已经很习惯的用了.

**转义: ** 因为一些预留的元字符,不能做为普通字符使用,所以进行转义,转义方法,就是使用 “ \ “

**引用: ** 引用是很常用的方法,转义时特殊的引用.

在sh中,引用,时为了防止字符串被解释为其他含义,常用的引用,双引号,单引号,反引号,反斜杠

1.双引号为部分引用

双引号,除了 $,`,\ 这是那种字符以外,都会被解释为普通字符

2.单引号为强引用

单引号,可以将一切解释为普通字符,但是单引号,最大的问题是,单引号,不能嵌套,否则会报错

3.反引号为命令替换

命令替换时十分重要的东西

命令替换,有什么用呢?

命令替换,可以将命令的结果保存至变量中,使用反引号即可,经常使用

同时,还另外一种命令替换 ** “ $ ( ) “ **

区别:反引号不清晰,且不能嵌套,所以建议使用$()的形式

同时,需要注意的一点:

在命令替换后,变量中保存的标准输出是没有换行符的,需要引用才能合理的显示

运算符

作为一门编程语言,怎么能少的了处理数据的内容呢?

sh中运算符,主要用于比较整数.所以这些运算符,也是以处理整数的运算为主

运算符,不多赘述,位运算符同理

sh中算术运算时基于let命令的

而且,一般情况下,运算符,数字是要紧紧相连的

要是不会,就是你特喵的C没学好,自己想办法补

其他的算术运算符

**1. 使用 $ [ ] **

$ [ ] 可以进行简单的算术运算

$ [ 1 + 1 ], $ [ 3 / 2 ]

2. 使用expr

expr时shell命令,可以进行算术运算,但是,运算符,数字不能紧紧相连的

否则会视为,字符串

3. 使用内建命令 declare

很多次看见这个命令了,同时它还可以进行算术运算

declare进行算术运算,其实是显示声明变量为整数, -i参数

还是要,紧紧相连,同时引用的变量不需要$,至直接使用

算术扩展

1. $ ( ( ) )

使用算术扩展符,可以进行变量和运算符的结合运算,不需要使用declare -i 声明

同时,如若其中的变量未初始化,则会将其视为0对待,但是,并不会真的赋值0

2. 使用bc运算

自行查看man文档,,(可以进行浮点运算的呦!)


我是华丽的分割线 ***********

分享在写Markdown时,千万不要

${#array[@]},  ${#array[N]}

这样的东西写在文本里,不然会把你逼疯得

转义,不存在的 !

December 6, 2017 1:06 AM



ShellScript Share Tweet +1