Shell变量及其相关操作

Shell变量及其相关操作

变量基础

在 Bash shell 中,每一个变量的值都是字符串,变量赋值时,值都会以字符串的形式存储。也就是说,Bash shell 在默认情况下不会区分变量类型,即使你将整数和小数赋值给变量,它们也会被视为字符串 。

命名规则

  • 命名只能使用英文字母,数字和下划线,首个字符不能以数字开头。
  • 中间不能有空格,可以使用下划线(_)。
  • 不能使用标点符号。
  • 不能使用bash里的关键字(可用help命令查看保留关键字)。

除了显式地直接赋值,还可以用语句给变量赋值

for file in `ls /etc`
for file in $(ls /etc)

使用变量

使用一个定义过的变量,只要在变量名前面加美元符号$即可

url="www.baidu.com"
echo $url
echo ${url}

推荐给所有变量加上花括号{ },这是个良好的编程习惯。

修改变量值

第二次对变量赋值时不能在变量名前加$,只有在使用变量时才能加$

url="www.baidu.com"
url="http://www.baidu.com"
echo $url

单引号和双引号的区别

定义变量时,变量的值可以由单引号' '包围,也可以由双引号" "包围

url="http://www.baidu.com"
website1='baidu:$url'
website2="baidu:$url"
echo $website1
echo $website2

输出结果

baidu:$url
baidu:http://www.baidu.com
  • 以单引号' '包围变量的值时,单引号里面是什么就输出什么,即使内容中有变量和命令(命令需要反引起来)也会把它们原样输出。这种方式比较适合定义显示纯字符串的情况,即不希望解析变量、命令等的场景。
  • 以双引号" "包围变量的值时,输出时会先解析里面的变量和命令,而不是把双引号中的变量名和命令原样输出。这种方式比较适合字符串中附带有变量和命令并且想将其解析后再输出的变量定义。

只读变量

使用 readonly 命令可以将变量定义为只读变量,只读变量的值不能被改变。

#将命令值结果赋给变量
myUrl=$url
readonly myUrl
echo $myUrl
myUrl="www.baidu.com"

输出结果

http://www.baidu.com
./test.sh: 行 15: myUrl: 只读变量

删除变量

使用 unset 命令可以删除变量

unset url
echo $url

输出结果

输出为空,没有结果输出

变量作用域Scope

Shell变量的作用域(Scope),就是 Shell 变量的有效范围(可以使用的范围)。

Shell 变量的作用域可以分为三种:

  • 有的变量只能在函数内部使用,这叫做局部变量(local variable);
  • 有的变量可以在当前 Shell 进程中使用,这叫做全局变量(global variable);
  • 而有的变量还可以在子进程中使用,这叫做环境变量(environment variable)。

局部变量

在 Shell 函数中定义的变量默认也是全局变量,它和在函数外部定义变量拥有一样的效果。

#!/bin/bash
#定义函数
function func(){
    a=99
}
#调用函数
func
#输出函数内部的变量
echo $a

输出结果为:99 参数a是在函数内部调用的,但在函数外部仍可以得到值

若要变量作用域仅限于函数内部,可以在定义时加上local命令,如下:

#!/bin/bash
#定义函数
function func(){
    local a=99
}
#调用函数
func
#输出函数内部的变量
echo $a

输出结果为空,变量a此时在函数外无效,是局部变量

全局变量

所谓全局变量,就是指变量在当前的整个 Shell 进程中都有效。每个 Shell 进程都有自己的作用域,彼此之间互不影响。在 Shell 中定义的变量,默认就是全局变量。

全局变量的作用范围是当前的Shell 进程,而不是当前的 Shell 脚本文件,它们是不同的概念。打开一个 Shell 窗口就创建了一个 Shell 进程,打开多个 Shell 窗口就创建了多个 Shell 进程,每个 Shell 进程都是独立的,拥有不同的进程 ID。在一个 Shell 进程中可以使用 source 命令执行多个 Shell 脚本文件,此时全局变量在这些脚本文件中都有效。

Shell变量及其相关操作_第1张图片

环境变量

全局变量只在当前 Shell 进程中有效,对其它 Shell 进程和子进程都无效。如果使用export命令将全局变量导出,那么它就在所有的子进程中也有效了,这称为“环境变量”。

环境变量被创建时所处的 Shell 进程称为父进程,如果在父进程中再创建一个新的进程来执行 Shell 命令,那么这个新的进程被称作 Shell 子进程。两个没有父子关系的 Shell 进程是不能传递环境变量的,并且环境变量只能向下传递而不能向上传递,即“传子不传父”。

#环境变量
#定义一个全局变量
a=20
#在当前Shell中输出a,成功
echo "父进程:$a"
#进入Shell子进程
bash
#子进程中输出为空,失败
echo "子进程:$a"
#退出Shell子进程,返回上一级Shell
exit
#将a到处环境变量
export a
#重新进入Shell子进程
bash
#输出a=20,成功
echo "子进程:$a"
#退出Shell子进程
exit

export a这种形式是在定义变量 a 以后再将它导出为环境变量,如果想在定义的同时导出为环境变量,可以写作export a=20

环境变量也是临时的

创建一个新的Shell窗口时,在次访问该环境变量依旧访问不到。

通过 export 导出的环境变量只对当前 Shell 进程以及所有的子进程有效,如果最顶层的父进程被关闭了,那么环境变量也就随之消失了,其它的进程也就无法使用了,所以说环境变量也是临时的。

命令替换

Shell命令替换是指将命令的输出结果赋值给某个变量。比如,在某个目录中输入 ls 命令可查看当前目录中所有的文件,但如何将输出内容存入某个变量中呢?这就需要使用命令替换了,这也是 Shell 编程中使用非常频繁的功能。

替换方式

Shell 中有两种方式可以完成命令替换,一种是反引号` `,一种是$()

variable=`commands`
variable=$(commands)

commands 可以只有一个命令,也可以有多个命令,多个命令之间以分号;分隔

示例

#!/bin/bash
begin_time=`date`    #开始时间,使用``替换
sleep 20s            #休眠20秒
finish_time=$(date)  #结束时间,使用$()替换
echo "Begin time: $begin_time"
echo "Finish time: $finish_time"

date命令用来获取当前系统时间,通过命令替换将其结果赋值给变量

Begin time: 2019年 05月 28日 星期二 14:12:05 CST
Finish time: 2019年 05月 28日 星期二 14:12:25 CST

data的%s格式可以获得当前UNIX时间戳,UNIX时间戳是从1970年1月1日00:00:00到目前为止的秒数

#!/bin/bash
begin_time=`date +%s`    #开始时间,使用``替换
sleep 20s                #休眠20秒
finish_time=$(date +%s)  #结束时间,使用$()替换
run_time=$((finish_time - begin_time))  #时间差
echo "begin time: $begin_time"
echo "finish time: $finish_time"
echo "run time: ${run_time}s"

(())是shell数学计算命令,后边会详细介绍

begin time: 1559024547
finish time: 1559024567
run time: 20s

特殊情况

如果被替换的命令的输出内容包括多行(也即有换行符),或者含有多个连续的空白符,那么在输出变量时应该将变量用双引号包围,否则系统会使用默认的空白符来填充,这会导致换行无效,以及连续的空白符被压缩成一个。

#!/bin/bash
LL=`ls -l`
echo $LL  #不使用双引号包围
echo "--------------------------"  #输出分隔符
echo "$LL"  #使用引号包围
总用量 12 -rwxrwxrwx 1 root root 215 5月 28 14:11 getCurrentTime.sh -rwxrwxrwx 1 root root 308 5月 28 14:22 getRunTime.sh -rwxrwxrwx 1 root root 143 5月 28 14:35 multiLineReplace.sh
--------------------------
总用量 12
-rwxrwxrwx 1 root root 215 5月  28 14:11 getCurrentTime.sh
-rwxrwxrwx 1 root root 308 5月  28 14:22 getRunTime.sh
-rwxrwxrwx 1 root root 143 5月  28 14:35 multiLineReplace.sh

为了防止格式混乱,在输出变量时加上双引号

比较两种方式

反引号 $()
是否容易混淆 容易与单引号混淆
是否支持嵌套
支持格式 多种shell中 bash

位置参数

定义

Shell 函数参数的传递和其它编程语言不同,没有所谓的形参和实参,在定义函数时也不用指明参数的名字和数目。定义 Shell 函数时不能带参数,但是在调用函数时却可以传递参数,这些传递进来的参数,在函数内部就也使用$n的形式接收。$1 表示第一个参数, 2 表 示 第 二 个 参 数 , 依 次 类 推 。 这 种 通 过 ‘ 2 表示第二个参数,依次类推。这种通过` 2n`的形式来接收的参数,在 Shell 中称为位置参数。

命名特殊

在讲解变量的命名时,我们提到:变量的名字必须以字母或者下划线开头,不能以数字开头;但是位置参数却偏偏是数字,这和变量的命名规则是相悖的,所以我们将它们视为“特殊变量”。

给脚本文件传递参数

#!/bin/bash
echo "number1: $1"
echo "number2: $2"
if [ $1 == $2 ]
then
    echo "等于"
elif [ $1 -gt $2 ]
then
    echo "大于"
else
    echo "小于"
fi

执行及返回

./compassVar 7 20
number1: 7
number2: 20
小于

给函数传递参数

#!/bin/bash
#定义函数
function func(){
    echo "name: $1"
    echo "password: $2"
}
#调用函数
func root root

执行及返回

name: root
password: root

注意

如果参数个数太多,达到或者超过了 10 个,那么就得用${n}的形式来接收了,例如 10 、 {10}、 10{23}。{ }的作用是为了帮助解释器识别参数的边界,这跟使用变量时加{ }是一样的效果。

特殊变量

变量 含义
$0 当前脚本的文件名
$n 传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第一个参数是$1,第二个参数是$2
$# 传递给脚本或函数的参数个数
$* 传递给脚本或函数的所有参数
$@ 传递给脚本或函数的所有参数。被双引号" "包含时,与 $* 稍有不同
$? 上个命令的退出状态,或函数的返回值
$$ 当前Shell进程ID。对于 Shell 脚本,就是这些脚本所在的进程ID

给脚本文件传参

#!/bin/bash
echo -n "文件名:"
echo $0
echo -n "参数传递个数:"
echo "$#"
echo -n "所有向脚本传递的参数:"
for var in "$*"
do
    echo "$var"
done
echo -n "当前进程ID号:"
echo "$$"
echo -n "后台运行最后一个进程ID号:"
echo "$!"
echo "引号中返回每个参数:"
for var1 in "$@"
do
    echo "$var1"
done
echo -n "Shell使用的当前选项:"
echo "$-"
echo -n "最后命令的退出状态:"
echo "$?"

执行及返回

bash `pwd`/compassVar.sh 1 5
文件名:/demo/var/compassVar/compassVar.sh
参数传递个数:2
所有向脚本传递的参数:1 5
当前进程ID号:72353
后台运行最后一个进程ID号:
引号中返回每个参数:
1
5
Shell使用的当前选项:hB
最后命令的退出状态:0

$0介绍

$0:获取当前执行的shell脚本的文件名(执行时给定的是完整路径则获取到的也是完整路径)

两个命令与$0的组合测试:获取一个带路径的文件的路径名与文件名两部分

#获取目录名部分
dirname $0
#获取文件名部分
basename $0

Shell变量及其相关操作_第2张图片

$n介绍

$n:获取当前执行的shell脚本的第n个参数,如果n=0则获取的是脚本的文件名。如果n>9则需要用大括号括起来,eg:${21}

Shell变量及其相关操作_第3张图片

&表示[0-9]本身,$是想要增加的字符
#生成1~10数字
seq -s “ ” 10      

$*$@的区别与联系

  • 当不被双引号""包围时,没有任何区别,都是将接受到的每个参数看做一份数据,然后以空格隔开输出
  • 当被双引号包围时$*会将所有的参数从整体上看成一份数据,而不是把每个参数看成一份数据,$@仍然会将每个参数当做一份数据,彼此间是独立的

$?介绍

用来获取上一个命令的退出状态,或者上一个函数的返回值。退出状态,就是上一个命令执行后的返回结果。退出状态是一个数字,一般情况下,大部分命令执行成功会返回 0,失败返回 1。

  • 获取上一个命令退出状态

    #!/bin/bash
    if [ "$1" == 100 ]
    then
        exit 0
    else
        exit 1
    fi
    
    #然后执行 
    ./getExitStatus.sh 50
    echo "$?"
    1
    ./getExitStatus.sh 100
    echo "$?"
    0
    
  • 获取函数返回值

    #!/bin/bash
    #得到两个数相加的和
    function add(){
        return `expr $1 + $2`
    }
    add 23 50  #调用函数
    echo $?  #获取函数返回值
    

    执行返回73

严格来说,Shell 函数中的 return 关键字用来表示函数的退出状态,而不是函数的返回值;Shell 不像其它编程语言,没有专门处理返回值的关键字。

你可能感兴趣的:(linux,shell,shell脚本)