欢迎各位兄弟 发布技术文章

这里的技术是共享的

You are here

马哥 05_02 _bash脚本编程之一 变量、变量类型等 有大用

http://mageedu.blog.51cto.com/


grep egrep  grep检索的时候会浪费大量的cpu时钟周期,是相当消耗时间的,速度比较慢

fgrep : fast grep 不支持正则表达式 太简单 不举例了 (用法与  grep 一样 )


shell 编程:

编译器,解释器

编程语言: 机器语言,汇编语言,高级语言


静态语言:编译型语言

    强类型(变量)

    关键字

    事先转换成可执行格式

    C,C++,JAVA,C#

    (不需要任何解释器,自我独立运行)


动态语言:解释型语言 on the fly

    弱类型(变量) (一般是弱类型,也可以为强类型)

    关键字

    边解释边执行

    ASP,ASP.NET,PHP,SHELL,python,perl

    (需要解释器)

所有的脚本都需要解释器解释执行(解释器本身都常是静态语言开发的)


bash:(本身是个解释器)

     Lua 也是一种语言(应该是解释型语言)

    

面向过程(适合开发小型的) shell,c

    linux 内核是面向过程的 C 语言开发的


面向对象(适合开发大型的) java,c++,python,perl(既面向过程,又面向对象),C++(肯定是面向对象,好像也有面向过程)

    C++是面向对象的


变量: 内存空间,命名的内存空间 


内存是编址的存储单元


进程:  程序运行起来,它就是进程

1+100:

1+1000000:

1


变量类型: 存储格式 事先确定好数据的存储格式和长度

    字符

    数值

        整型

        浮点型:带小数 11.23  1.123*10^1,0.1112*10^2

        2013/10/10 (数值 1970/01/01到这一天的天数,把天数存下来就可以了 假设 99999:24bit,3个字节足够了)

                            (字符串,8个字节,64位(不考虑斜线))

      日期,时间(转化成字符型或数值型)

      布尔型 真假型 逻辑型  true false (字符型) 1 0 (数值型)

            逻辑: 1+1>2

            与 或 非 异或

1:真

0:假

与:

1 & 0   结果 0

0 & 1    结果 0

0 & 0    结果 0

1 & 1    结果 1

或:


非: 单目运算,只需要一个操作数

! 真 = 假

! 假 = 真 


异或

两个操作数 相同就是 0

两个操作数 不相同就是 1


编译型语言必须要定义变量的类型(没有解释器,必须靠程序自身来保证每一个变量是正确的)

整形: 8bit: 256 

0-255   1溢出了, 后面全是0,第一会计算结果错误,第二,就是溢出到其它进程(比如系统进程,就会使系统有问题)  有种攻击叫缓冲区溢出   防止攻击溢出的方法(比如有个变量,能保存就保存,超过了不能保存就拒绝)


(有解释器的语言,变量由解释器在另一个层次的予以避免)

(编译型语言,用户事先定义变量类型,编译器转换的过程中,只能检查事先预防的错误,后续由用户填进来的数据,编译器检查不了)

变量:

1,10000


10: 字符 16bit

10:数字 1010 4位, 8bit (因为最小存储空间是8位)



shell 是弱类型 编程语言

强:变量在使用前,必须先声明,甚至可能需要初始化

        (系统默认一般字符串为 NULL 数值为0)

弱:变量可以拿来直接用,甚至不区分类型 (如果不区别类型,一般默认为字符串)


11+c (许多语言转换成 ascii数值进行相加) (隐式转换)  (还有一种叫显式转换)


变量赋值:  (变量是指向存储空间的引用,这个空间是存储数据的)

         VAR_NAME=VALUE




bash: 对于变量本身的作用范围,变量本身的表示形式来讲

        变量类型:            

            (本地)变量(有一个更小的概念,局部变量) (局部变量本身未必是本地变量,它是一个子概念)

            环境变量

            位置变量 (类似于 grep 中的 \1 \2 但使用是$1 $2 )

            特殊变量(bash内置的,用来保存某些特殊数据的变量)(有人称特殊变量是系统变量)


变量与进程相关的,一旦这个bash进程没了,这个进程里面的变量也就没了

所以变量一定是进程的变量


本地变量:

    VARNAME=VALUE      这是声明本地变量 作用域为整个脚本bash进程

局部变量:   

     local VARNAME=VALUE      这是声明局部变量 ,变量是局部的 只对当前这一段代码有效 作用域为当前代码段 

环境变量:作用域为当前shell进程及其子进程(与本地变量相比其它没有什么不同)

    export VARNAME=VALUE  定义环境变量

    (也可以先定义,再导出

        VARNAME=VALUE

         export VARNAME

    )

        "导出"


位置变量  是用来执行脚本参数的,用的时候再讲解

$1 $2 ......


特殊变量:是用来保存某些特殊数据的

$? : 美元符号问号 上一个命令(上一个进程)执行状态返回值

        程序执行,可能有两类返回值:

            程序执行结果

            程序状态返回代码 (0-255)

                0:正确执行

                1-255:错误执行  1,2,127:是系统预留的,其它的可以自己定义的


输出重定向:

>

>>

2>

2>>

$>


/dev/null: 软件设备 (软件模拟的设备)(这个设备不存在) bit bucket 位桶(全部吞下去)(数据黑洞)


撤消变量: (变量用完后撤消变量) (回收变量)

unset VARNAME  (无论撤消本地变量,还是环境变量,还有其它什么变量,都是用 unset)



其实 定义变量的时候是  (set VARNAME=value ,只是set 省略了)

撤消变量就是 unset VARNAME  (此时变量名前面不能加美元符$,因为它是撤消一个变量的,不是撤消变量中的值,但凡操作变量本身,而是不操变量里面的值,就不要加美元符$,否则才需要加$)



查看当前shell中变量:

set :  (不带任何选项或参数)

(结果中包含环境变量和本地变量)

查看当前shell中的环境变量:

printenv

env

export 

这三个命令都行


脚本: 是程序的源代码,里面是一大堆你想写的程序,

        命令的堆砌,按实际需要,结合命令流程控制机制实现的源程序


shebang: 指定程序的魔数 magic number  (#!/bin/bash就是shebang)      image.png

#!/bin/bash      (第一行必须这么写) (井号叹号开头后面跟上解释器路径(可执行程序的路径)) (如果是perl #!/usr/bin/perl,如果python,#!/usr/bin/python) (linux 根据这里提供的解释器路径,如果是 /bin/bash,就启动bash进程,让bash执行下面的各种命令)


# 之后任何一个井号开头的行都是无意义的,不执行的,是注释行

除此之外的每一行都被当作脚本的有效组成部分



练习: 写一个脚本,完成以下任务

1,添加5个用户, user1,........user5

2,每个用户的密码同用户名,而且要求,添加密码完成后不显示passwd命令的执行结果信息 

3,每个用户添加完成后,都要显示用户某某已经成功添加


练习:写一个脚本,完成以下任务

1,使用一个变量保存一个用户名:

2,删除此变量中的用户,且一并删除其家目录

3,显示"用户删除完成"类的信息





特殊变量和位置变量都无法查看


(对于shell来讲,默认所有的变量的值都是字符串,所以默认不能作算术运算)











脚本在执行时会启动一个子shell进程:(当前shell的子shell进程)

    命令行中启动的脚本会继承当前shell环境变量

    系统自动执行的脚本((跟shell没关系,跟命令行没关系)非命令行启动)就需要自我定义需要各种环境变量

    (比如 自动备份什么的脚本,在当前命令行有效,但是系统自动执行就无效)







    bash:

引用变量: ${VARNAME}     花括号(大括号)在大多数情况下(有时)可以省略 

    echo "There are some ${ANIMAL}s."  在这种情况下 花括号不能省略 




            




与运算

image.png


或运算

image.png


非运算

image.png


image.png

image.png

短路逻辑

image.png


[root@ebs-22618 ~]# NAME=Jerry  声时一个变量为 NAME,这个变量引用所指向的地址上存的值是 Jerry

image.png

[root@ebs-22618 ~]# echo $NAME

image.png

[root@ebs-22618 ~]# bash  原来的shell 执行下 bash ,打开了一个子shell

[root@ebs-22618 ~]# echo $NAME  (因为两个shell,两个不同的shell 进程,子shell得不到父shell中声明的本地变量,因为本地变量只与进程相关)

image.png

[root@ebs-22618 ~]# exit 退出当前的shell

image.png


[root@ebs-22618 ~]# ANIMAL=pig

[root@ebs-22618 ~]# echo "There are some $ANIMALs."  双引号是弱引用,内部的变量会变替换

[root@ebs-22618 ~]# echo "There are some ${ANIMAL}s."  在这种情况下 花括号不能省略 (这种易混淆的必须要加花括号)

image.png


[root@ebs-22618 ~]# echo 'There are some ${ANIMAL}s.'   单引号是强引用 不作变量替换的

image.png


[root@ebs-22618 ~]# pstree   以树状图的方式展现进程之间的派生关系,显示效果比较直观。

(没有发现有什么子shell)

image.png

[root@ebs-22618 ~]# NAME=Jerry

[root@ebs-22618 ~]# export NAME

[root@ebs-22618 ~]# echo $NAME

image.png

[root@ebs-22618 ~]# bash  打开子shell 

[root@ebs-22618 ~]# echo $NAME 输出$NAME

image.png

[root@ebs-22618 ~]# bash   再打开子shell 

[root@ebs-22618 ~]# echo $NAME   再输出$NAME

image.png


重新登录一个shell (是不同的shell 也不是子shell)

[root@ebs-22618 ~]# echo $NAME  此时环境变量没有值了

image.png


[root@ebs-22618 ~]# ls /var

image.png

[root@ebs-22618 ~]# ls /varr

image.png

[root@ebs-22618 ~]# echo $?  //某命令执行后 ,再执行本命令 返回上一次命令执行状态返回代码

image.png



[root@ebs-22618 ~]# ls /var

image.png

[root@ebs-22618 ~]# echo $?  (美元符问号是状态码)

image.png


[root@ebs-22618 ~]# lss /var

image.png

[root@ebs-22618 ~]# echo $?

image.png


[root@ebs-22618 ~]# id student   看有没有这个用户

image.png

[root@ebs-22618 ~]# echo $?

image.png


[root@ebs-22618 ~]# id student &> /dev/null

image.png

[root@ebs-22618 ~]# echo $?

image.png


[root@ebs-22618 ~]# exit 退出子shell

image.png

[root@ebs-22618 ~]# exit  再退出子shell

image.png

[root@ebs-22618 ~]# echo $NAME

image.png

[root@ebs-22618 ~]# unset NAME

[root@ebs-22618 ~]# echo $NAME

image.png


[root@ebs-22618 ~]# set

image.png



[root@ebs-22618 ~]# ANIMALS=pig

[root@ebs-22618 ~]# ANIMALS=$ANIMALS:"goat"  //可以用单引号,也可以把引号去掉 (字符串相加相连)

[root@ebs-22618 ~]# echo $ANIMALS

image.png

[root@ebs-22618 ~]# ANIMALS=$ANIMALS:sheep  冒号是不会作为变量名,所以前面不需要用花括号

image.png


[root@ebs-22618 ~]# echo $PATH

image.png

[root@ebs-22618 ~]# export PATH=$PATH:/usr/local/apache/bin

[root@ebs-22618 ~]# echo $PATH

image.png


[root@ebs-22618 ~]# export PATH=/usr/local/mysql/bin:$PATH (不过export 应该也可以,因为PATH本身是环境变量,此前已export过,环境变量与本地变量的区别仅仅在作用域上,不在于有没有export这个变量 .  如果此前已export,此时不加export也没有关系)

[root@ebs-22618 ~]# echo $PATH

image.png


[root@ebs-22618 ~]# A=2

[root@ebs-22618 ~]# B=3

[root@ebs-22618 ~]# C=$A+$B

[root@ebs-22618 ~]# echo $C

image.png


[root@ebs-22618 ~]# cat /etc/fstab

image.png

[root@ebs-22618 ~]# ls /var

image.png


[root@ebs-22618 ~]# nano first.sh

image.png


[root@ebs-22618 ~]# file /bin/ls

image.png

ELF 是可执行的 可链接的文件格式 ,linux 内核只能识别这种格式,才能让它执行


[root@ebs-22618 ~]# file first.sh

image.png

它是一个纯ASCII码格式,linux内核理解不了它,程序没法执行(程序就会报错)

此时需要告诉内核,一旦发现它不是可执行的格式的时候,告诉内核,它是一个脚本,让内核去启动一个脚本解释器去执行它


[root@ebs-22618 ~]# nano first.sh

image.png


[root@ebs-22618 ~]# ls -lt

image.png


[root@ebs-22618 ~]# chmod +x first.sh

[root@ebs-22618 ~]# ls -lt

image.png


[root@ebs-22618 ~]# first.sh   (当命令没有路径的时候到环境变量中找)

image.png

[root@ebs-22618 ~]# echo $PATH

image.png

[root@ebs-22618 ~]# pwd

image.png


两种方法 让它执行 

1) 把 /root 放到 环境变量中

2) 明确指定路径 ./

[root@ebs-22618 ~]# ./first.sh

image.png


[root@ebs-22618 ~]# nano first.sh

image.png



[root@ebs-22618 ~]# chmod -x first.sh

[root@ebs-22618 ~]# bash first.sh    (first.sh没有执行权限的时候,使用解释器执行first.sh)

image.png



编程能力

    脚本编程




普通分类: