zoukankan      html  css  js  c++  java
  • Shell入门教程:Shell变量

    变量

    是一种很“弱”的变量,默认情况下,一个变量保存一个串,Shell不关心这个串是什么含义。所以若要进行数学运算,必须使用一些命令例如 letdeclareexpr、双括号等。

    Shell变量可分为两类:局部变量环境变量。局部变量只在创建它们的Shell中可用。而环境变量则可以在创建它们的Shell及其派生出来的任意子进程中使用。有些变量是用户创建的,其他的则是专用Shell变量。

    变量的命名规则:

    1.可以使用英文字母、数字(0~9)和下划线组成,任何其他的字符都标志着变量名的终止。

    2.第一个字符不能是数字

    3.区分大小写

    变量设定/赋值:

    变量赋值时,等号左右不能有任何空白符。为了给变量赋空值,可以在等号后跟一个换行符。用set命令可以查看所有的变量,unset var命令可以清除变量var,var相当于没有定义过。readonly var可以把var变为只读变量,定义之后不能对var进行任何更改。

    格式:变量名=值

    例如:name=john

    但比较好的习惯是:把字符串用双引号或单引号括起来,如下所示:

    name="john" 或者 name='john'

    在引用变量的时候使用双引号和单引号是有区别的,单引号不会进行变量替换。而在双引号中,如果也想抑制变量替换,则需要使用转义符反斜线

    若等号右边的值含有空白,则要用引号括起来。

    错例:

    name=Black Jack

    正例:

    name="Black Jack"

    引用变量:

    对Shell变量的引用方式很多,用这些方式可以方便的获取Shell变量的值,变量值的长度,变量的一个字串,变量被部分替换后的值等等。Shell变量常见引用方式如下:

    $变量名

    建议这样引用变量:${变量名}

    环境变量:

    使用下面的任意一个方法可以使name变为环境变量

    name="john"
    export name
    export name="john"
    declare -x name="john"

    Shell在初始化的时候会在执行profile等初始化脚本,脚本中定义了一些环境变量,这些变量会在创建子进程时传递给子进程。

    env命令可以查看当前的环境变量。常用的系统环境变量如下:

    _(下划线)   上一条命令的最后一个参数
    BASH   展开为调用bash实例时使用的全路径名
    CDPATH   cd命令的搜索路径。它是以冒号分隔的目录列表,shell通过它来搜索cd命令指定的目标目录。例如.:~:/usr
    EDITOR   内置编辑器emacs、gmacs或vi的路径名
    ENV    每一个新的bash shell(包括脚本)启动时执行的环境文件。通常赋予这个变量的文件名是.bashrc。
    EUID   展开为在shell启动时被初始化的当前用户的有效ID
    GROUPS   当前用户所属的组
    HISTFILE   指定保存命令行历史的文件。默认值是~/.bash_history。如果被复位,交互式shell退出时将不保存命令行历史
    HISTSIZE   记录在命令行历史文件中的命令数。默认是500
    HOME   主目录。未指定目录时,cd命令将转向该目录
    IFS   内部字段分隔符,一般是空格符、制表符和换行符,用于由命令替换,循环结构中的表和读取的输入产生的词的字段划分
    LANG   用来为没有以LC_开头的变量明确选取的种类确定locale类
    OLDPWD   前一个工作目录
    PATH   命令搜索路径。一个由冒号分隔的目录列表,shell用它来搜索命令,一个普通值为 /usr/gnu/bin:/usr/local/bin:/usr/ucb:/usr/bin
    PPID   父进程的进程ID
    PS1   主提示符串,默认值是$
    PS2   次提示符串,默认值是>
    PS3   与select命令一起使用的选择提示符串,默认值是#?
    PS4   当开启追踪时使用的调试提示符串,默认值是+。追踪可以用set –x开启
    PWD   当前工作目录。由cd设置
    RANDOM   每次引用该变量,就产生一个随机整数。随机数序列可以通过给RANDOM赋值来初始化。如果RANDOM被复位,即使随后再设置,它也将失去特定的属性
    REPLY   当没有给read提供参数时设置
    SHELL   当调用shell时,它扫描环境变量以寻找该名字。shell给PATH、PS1、PS2、MAILCHECK和IFS设置默认值。HOME和MAIL由login(1)设置
    SHELLOPTS   包含一列开启的shell选项,比如braceexpand、hashall、monitor等
    UID   展开为当前用户的用户ID,在shell启动时初始化

    数值变量:

    Shell中默认把变量值当作字符串,例如:

    age=22
    age=${age}+1
    echo ${age}

    输出结果为22+1,而不是23,因为Shell将其解释为字符串,而不是数学运算。

    可以用let命令使其进行数学运算,例如:

    let age=${age}+1

    也可以用declare把变量定义为整型。例如:

    declare -i age=22

    这里就用 -i 选项把age定义为整型的了。此后每次运算,都把age的右值识别为算术表达式或数字。

    数组:

    在shell中可以使用数组,例如:

    myArray[0]=0
    myArray[1]=1
    myArray[2]=2

    则myArray就是一个数组,也可以这样给数组初始化:

    myArray=(0 1 2) // 元素之间以空格分隔

    可以通过 ${myArray[$i]}来访问myArray中某个元素,${myArray[*]} 的返回值即数组的所有元素组成的串,${#myArray[*]} 的返回值即数组的元素个数,${myArray[*]:0:2} 返回第一个和第二个元素组成的串。0表示开始的位置,2表示要返回的元素个数,开始位置可以为0-2(0减去2)之类的,表示从倒数第二个元素开始。

    下面写个稍微复杂点的例子:

    #!/bin/bash
    for ((i=0; i<100; i++))
    do
    	array[$i]=$i
    done
    
    for ((i=0; i<100; i++))
    do
    	echo ${array[$i]}
    done

    如果要使用二维数组甚至三维数组该怎么实现呢,那就需要用eval命令来模拟数组的功能了。

    eval命令的作用是扫描命令两次再执行,如果不使用eval,只扫描一次,然后执行。看个例子:

    root@suse:~$ name=Barry
    root@suse:~$ $name=hello
    Barry=hello: command not found

    为什么第二句给Barry变量赋值会出错呢?从报错信息可以发现shell并没有识别这是个赋值语句,而是把Barry=hello当作一个命令来执行,当然会报错。为什么不能识别这是赋值语句呢?第一次扫描时,因为扫描到$符号,所以不能把这句当作赋值语句,赋值语句的左边总是一个变量名,而不应该是$开头的。所以第一次扫描仅仅识别了$name变量,并做了替换,而并没有认识到赋值语句。

    如果使用eval $name=hello呢?

    root@suse:~$ name=Barry
    root@suse:~$ $name=hello
    Barry=hello: command not found
    root@suse:~$ eval $name=hello
    root@suse:~$ echo $Barry
    hello

    可见使用了eval之后,对 $name=hello 第一次扫描替换了$name,没有识别赋值语句,第二次扫描识别是赋值语句,然后执行。现在大约可以想到怎样用eval实现二维数组了。
    下面实现的二维数组每一行代表一个人的信息记录,包括姓名,年龄。

    for ((i=0; i<2; i++))
    do
    	for ((j=0; j<2; j++))
    	do 
    		read man$i$j
    	done
    done
    
    echo "next print:"
    
    for ((i=0; i<2; i++))
    do
    	for ((j=0; j<2; j++))
    	do 
    		eval echo -n "$man$i$j:"
    	done
    
    	printf "
    "
    
    done

    Bash的一些重要的内置变量:

    $0   当前脚本的文件名
    $1 ~ $n?   位置参数,为从1开始的数字,当n超过9后,使用${n},例如${10},$1是第一个参数,$2是第二个参数,${10}是第十个参数
    $#   传入脚本的参数的个数
    $*   所有的位置参数,但视为一个字符串
    $@   所有以空白隔开的位置参数,即代表各位置参数组成的串行(每个都作为独立的字符串,可用  “for 变量 in 串行” 循环输出)。
    $?   当前Shell进程中,上一个命令的返回值,如果上一个命令成功执行则$?的值为0,否则为其他非零值,常用做if语句条件
    $$   当前Shell进程的pid
    $!   后台运行的最后一个进程的pid
    $-   显示Shell使用的当前选项
    $_   之前命令的最后一个参数

  • 相关阅读:
    003_cd pushd popd三个命令的区别
    002_更新Nginx证书
    001_nginx常用参数查询
    001_shell经典案例
    001_chrome工具详解
    002_分布式搜索引擎Elasticsearch的查询与过滤
    004_加速国内docker源下载速度
    dango models and database ---- relation ship
    dango models and database ---- verbose name
    MySQL字符集详解
  • 原文地址:https://www.cnblogs.com/52php/p/5669704.html
Copyright © 2011-2022 走看看