首页 > 代码库 > Bash Shell脚本编程-变量知识

Bash Shell脚本编程-变量知识

Shell:GUI  CLI

提供交互式接口:提高效率

命令行展开:~ {}

命令别名:alias

命令历史:history

Globbing*,?,[][^]

命令补全:$PATH指定的目录下

路径补全:TAB

管道:|

输入输出重定向:>    >> 

 

提供编程环境:

bash自动运行脚本机制

面向过程(以指令为中心组织数据)的编程模型

脚本编程

输入指令解决问题

程序是语句和表达式组成的

运行时根据一定流程来执行:

顺序执行

选择执行

循环执行

 

 

程序是指令+数据的

 

面向对象(以数据为中心来组织指令)

框架组织程序中的各个指令

 

程序运行模型:

编译运行:

源程序——>预处理——>编译——>汇编——>链接——>运行

# file /bin/cat
/bin/cat: ELF 64-bit LSB executable, x86-64, version 1 (SYSV),
dynamically linked (uses shared libs), for GNU/Linux 2.6.18, stripped

# ldd /bin/cat         链接到的库

 

linux-vdso.so.1 =>  (0x00007fff5c3ff000)
libc.so.6 => /lib64/libc.so.6 (0x00000035d0e00000)
/lib64/ld-linux-x86-64.so.2 (0x00000035d0600000)

 

 

解释运行:

向内核提出运行要求时是解释器运行成进程

源程序——>无需编译——>解释器——>内核根据文件的格式来判定可执行(脚本的第一行要写入shebang,如#!/bin/bash)——>bash程序来执行

 

 

变量:命名的内存空间

变量名:存放在内存中,由解释器和内存自行维护

变量值:存放在内存中,由用户来维护

 

数据类型:12701111111    7bit存储空间

127127,是字串,要24位来存储

ASCII码:0-9a-zA-Zpunction

0-127 128种变化,要7位就能存储

0000   0000 - 0111 1111

1.定义了数据存储格式

2.定义了数据表示范围

3.定义数据可以参与的运算类型

强类型编程语言:严格区分类型

弱类型编程语言:不严格区分类型

bash:把所有值都默认当作字符存储

类型:

数值型:

精确数值型:整数

近似数值型:float(单精度浮点),double(双精度浮点)

计算机里面有专门的浮点单元来进行

浮点数的存储格式?

 

 

字符型:

单个字符,字符串string

 

布尔型:

truefalse

 

逻辑运算:

与:1&&1=1

    1&&0=0

    0&&1=0

    0&&0=0

或:

1 || 1 =1

1 || 0 =1

0 || 1 =1

0 || 0 =0

非:

1 =0

0 =1

异或:

1 异或 1 =0

1 异或 0 =1

 

 

bash的变量类型:

本地变量:只对当前shell进程有效,对当前之外的其他shellshell都无效。

环境变量:对当前shell进程及其子shell进程有效,对其他shell无效。

局部变量:仅对当前shell进程中的某段代码空间内有效,通常用于函数本地程序。

位置变量:$1  $2   ,。。。

特殊变量:$?,$0 $$ $# $* $@

$# 传递到脚本的参数个数

 

$* 传递到脚本的参数,与位置变量不同,此选项参数可超过9

 

$$ 脚本运行时当前进程的ID号,常用作临时变量的后缀,如 haison.$$

 

$! 后台运行的(&)最后一个进程的ID

 

$@ $#相同,使用时加引号,并在引号中返回参数个数

 

$- 上一个命令的最后一个参数

 

$? 最后命令的退出状态,0表示没有错误,其他任何值表明有错误

 

 

 

本地变量:只是在用户当前shell生存期的脚本中使用

 

无需事先声明可直接使用

变量赋值:# VAR_NAME=

变量引用:#echo "${VAR_NAME}"

[root@localhostretry]# a=1
[root@localhostretry]# echo "a=$a"
a=1
[root@localhostretry]# b=‘2‘
[root@localhostretry]# echo "b=$b"
b=2
[root@localhostretry]# c="3"
[root@localhostretry]# echo "c=${c}"
c=3
[root@localhostretry]# a=1-$a
[root@localhostretry]# echo "a=$a"
a=1-1
[root@localhostretry]# b=‘2-$a‘
[root@localhostretry]# echo "b=$b"
b=2-$a
[root@localhostretry]# c="3-$a"
[root@localhostretry]# echo "c=${c}"
c=3-1-1


wKiom1SBuN2A8ctEAAHSdKz5v2Y422.jpg

#echo $username
 
#username=jerry
#echo $username
jerry
# echo ‘$username‘         强引用,其中变量会被替换,所见所得
$username
# echo "$username"        弱引用,其中变量不会被替换
jerry
#set                                   显示本地变量
#unset VAR_NAME        撤销变量
#username=slackware
#useradd $username
#echo $username |passwd --stdin $username
Changingpassword for user slackware.
passwd:all authentication tokens updated successfully.


 

注意习惯:

1.数字不加引号,其他默认加双引号

2.把命令作为变量:反引号

CMD=`ls`

3.${WEEK}day  若变量和其他字符组成新的变量就必须给变量加上大括号。

4.养成将所有字符串变量用双引号括起来的使用习惯,将会减少很多编程中遇到的错误。如 "$A" "${A}"

 

 

 

特殊例子:awk调用shell变量引号例子

[root@localhostretry]# NUM=123
[root@localhostretry]# awk ‘BEGIN {print ‘$NUM‘}‘
123
[root@localhostretry]# awk ‘BEGIN {print "$NUM"}‘
$NUM


 

 

环境变量

环境变量用于定义shell的运行环境,保证shell命令的正确执行,shell通过环境变量确定登录用户名,命令路径,终端类型,登录目录等,所有的环境变量都是系统全局变量,可用于所有子进程。

无需事先声明

$USER

$HOME

$UID

$SHELL

$PATH

变量赋值:

 #export VAR_NAME=VALUE

 #declare -x  VAR_NAME=VALUE

变量引用:${VAR_NAME}

 

注意:bash内建了许多环境变量

显示环境变量                  

#export

#printenv

#env

#export username        导出为环境变量

#unset VAR_NAME        撤销变量临时生效

 

变量只读:

readonly  VAR_NAME

declare -r VAR_NAME

退出当前shell进程可撤销

 

变量命名规则:

1.不能使用程序中的关键字

2.只能使用数字,字母或者下划线,而且不能以数字开头

3.见名知意:usernameuserName_

 

自定义环境变量生成环境JAVA环境配置实例:tomcatresincsvn,hadoop

export JAVA_HOME=/application/jdk
export CLASSPATH=$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib
export PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$PATH:$HOME/bin
export RESIN_HOME=/application/resin

常见放在: /etc/profile   或者 /etc/

 

 

 

位置变量:

#scirpt1.sharg1 arg2…

$0,$1…${10}

 

算术运算:

letVAR=expression

$[epression]

$((epression))

‘expr arg1 arg2 arg3‘

 

计算整数之和

        #vi test.sh    
        #!/bin/bash
        #author:test
        declare -i sum=0
        sum=$[$1+$2]
        echo "the sum of $1 and $2:$[$1+$2]
        echo "the minus of $1 and $2:$[$1-$2]


 

参数变量的轮替

shift [n]

        #vi test2.sh    
        #!/bin/bash
        #author:test
        #echo $1
        shift
        #echo $1
        shift
        #echo $1
        shift


 

 

特殊变量:

$0:获取当前执行的shell脚本的文件名,包括路径

        #cat 14.sh    
        dirname $0
        basename $0
        #sh /root/14.sh
        /root
        14.sh


 

$n获取当前执行的shell脚本的第n个参数值,n=1..9,当n为0时表示脚本的文件名,如果n大于9后,用大括号括起来${10}

        #seq 7 |sed ‘s#[0-9]#$&#g‘    
        #cat 13.sh
        #!/bin/bash
        echo$1 $2 $3 $4 $5 $6 $7 $8 $9 $10
        #sh 13.sh 1 2 3
        12 3 10


 

$#:获取当前shell命令行参数的总个数

        #cat 13.sh    
        #!/bin/bash
        echo$1 $2 $3 $4 $5 $6 $7 $8 $9 $10
        echo$#
        #sh 13.sh 1 2 3 4 5
        12 3 4 5 10
        5
         
        #sh 13.sh "1 2 3 45"
        12 3 4 5 1 2 3 4 50
        1


 

 

$@:这个程序的所有参数"$1" "$2"  "$3"  … ,这是将参数传递给其他程序的最佳方式,因为它会保留所有内嵌在每个参数里面的任何空白

 

 

$*:获取当前shell的所有参数,将所有的命令行参数视为单个字符串,相当于"$!$2$3"…

 

        echo ‘total $#‘    
        echo -e ‘$@\n‘
        echo -e ‘$*\n‘


 

进程状态变量

$$:获取当前shell的进程号PID

        #!/bin/bash    
        echo$$ >/root/pid.log
        whiletrue ; do
                uptime &>/dev/null
                sleep 2
        done
        #sh 15.sh &
        [1]3158
        #cat pid.log
        3158


 

$!:获取上一个指令的PID

 

$?:获取执行的上一个指令的状态码(0为成功,非0失败)

例如:编译安装程序时,make后查询成功与否

make

echo $?

打包时也可以使用

$?返回值参考:

0:表示运行成功

2:权限拒绝

1-125:表示运行识别,脚本命令,系统命令错误或参数传递错误

126:找到命令,但无法执行

127:未找到要运行的命令

>128:命令被系统强制结束

 

 

$_ :在此之前执行的命令或脚本的最后一个参数

 wKioL1SBui7yCAiTAAMrURu96M4344.jpg


 

    练习:写一个脚本,能接受一个参数,此参数用于用户名

    1.创建此用户

    2.给用户添加密码,密码同用户名

    #!/bin/bash    
    #author:test
    useradd$1 
    echo$1 |passwd --stdin $1


 

    练习:写一个脚本,能接受一个参数,此参数为系统上某文本文件路径

    1.显示此文件的总行数

    2.统计此文件中的空白行数

    #!/bin/bash    
    wc-l $1 |cut -d‘ ‘ -f1
    grep‘^[[:space:]]$‘ $1 |wc -l

 

 

$*$@的区别:

$*:将所有命令行所有参数视为单个字符,等同于"$1$2$3"

$@:将命令行每个参数视为单独的字符串,等同于"$!" "$2"  $3" ,这是将参数传递给其他程序的最佳方式,因为它会保留所有内嵌在每个参数里的任何空白。

                            

    [root@localhost ~]# set -- "how old " are you.      传入3个参数    
    [root@localhost ~]# echo $#                         现在有三个参数
    3
    [root@localhost ~]# for i in $* ; do echo $i ; done循环打印参数,用$*,
    how
    old
    are
    you.
    [root@localhost ~]# for i in $@ ; do echo $i ; done没有双引号情况
    how
    old
    are
    you.
    [root@localhost ~]# for i; do echo $i ; done      去掉in变量列表,相当于in"$@"
    howold
    are
    you.
    [root@localhost ~]# for i in "$@" ; doecho $i ; done  在有双引号的情况下,参数里引号内容当作一个参数输出,这才真正符合我们传入的参数需求。
    howold
    are
    you.
    .

 

获取系统运行级别:

    # runlevel=$(set -- $(runlevel);eval "echo \$$#" )    
    # echo $runlevel
    3

 

1. eval command-line

其中command-line是在终端上键入的一条普通命令行。然而当在它前面放上eval时,其结果是shell在执行命令行之前扫描它两次。如:

pipe="|"

evalls $pipe wc -l

shell第1次扫描命令行时,它替换出pipe的值|,接着eval使它再次扫描命令行,这时shell把|作为管道符号了。

如果变量中包含任何需要shell直接在命令行中看到的字符(不是替换的结果),就可以使用eval。命令行结束符(;| &),I/o重定向符(< >)和引号就属于对shell具有特殊意义的符号,必须直接出现在命令行中。

2. eval echo \$$# 取得最后一个参数

如:cat last

evalecho \$$#

./lastone two three four

four

第一遍扫描后,shell把反斜杠去掉了。当shell再次扫描该行时,它替换了$4的值,并执行echo命令

3.以下示意如何用eval命令创建指向变量的“指针”:

x=100

ptrx=x

eval echo \$$ptrx 指向ptrx,用这里的方法可以理解b中的例子

100 打印100

eval $ptrx=50 将50存到ptrx指向的变量中。

echo$x

50 打印50


本文出自 “龙之守护” 博客,请务必保留此出处http://sohudrgon.blog.51cto.com/3088108/1586794

Bash Shell脚本编程-变量知识