zoukankan      html  css  js  c++  java
  • Shell(1)---变量

    Shell(1)---变量

    初衷:学习shell的目的很简单,自己经常在linux服务器上做各种操作,而且基本上是一些相同的命令操作,所以就想通过shell脚本来启动就行,能够节省一定的开发时间,提高工作效率。

    一、shell变量

    1、定义变量

    Shell 支持以下三种定义变量的方式

    xub$ name=value
    xub$ name='value'
    xub$ name="value"
    # name 是变量名,value 是赋给变量的值。
    

    区别

    如果 value 不包含任何空白符(例如空格、Tab 缩进等),那么可以不使用引号;

    如果 value 包含了空白符,那么就必须使用引号包围起来。

    使用单引号和使用双引号也是有区别的 下面讲。

    注意 赋值号=的两边不能有空格。

    xub$ name="小小"  #赋值
    xub$ echo $name  #输出命令
    xub$ 小小         #输出
    

    2、使用变量

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

    xub$ home="千岛湖"
    xub$ echo $home
    千岛湖
    xub$ echo ${home}
    千岛湖
    

    区别 变量名外面的花括号{ }是可选的,加不加都行,加花括号是为了帮助解释器识别变量的边界,比如下面这种情况:

    xub$ name="xiaoxaio"
    xub$ echo "my name is $namecc "
    my name is  #发现这里并没有输出变量名 因为系统认为$namecc是一个整体了
    

    改成

    xub$ name="xiaoxaio"
    xub$ echo "my name is ${name}cc "
    my name is xiaoxaiocc  #这就是${}的优点
    

    3、单引号和双引号的区别

    上面说了定义变量时,变量的值单引号' ',和双引号" "是有区别的 ,举例如下

    xub$ sex="女"
    xub$ one='小小的性别是:${sex}'
    xub$ two="小小的性别是:${sex}"
    xub$ echo $one
    小小的性别是:${sex} 
    xub$ echo $two
    小小的性别是:女
    

    区别

    • 以单引号' '包围变量的值时,单引号里面是什么就输出什么,即使内容中有变量和命令(命令需要反引起来)也会把它们原样输出。
    • 以双引号" "包围变量的值时,输出时会先解析里面的变量和命令,而不是把双引号中的变量名和命令原样输出。

    建议

    1)如果变量的内容是数字,那么可以不加引号;

    2)如果真的需要原样输出就加单引号;

    3)其他没有特别要求的字符串等最好都加上双引号。

    4、只读变量

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

    xub$ name=zhangsan;readonly name;name=lisi  #这里是三条命令 用;隔开
    -bash: name: readonly variable  #报错
    

    5、删除变量

    使用unset命令可以删除变量。语法:

    xub$ unset variable_name
    

    注意 unset 命令不能删除只读变量。

    6、将命令的输出结果赋值给变量

    Shell 也支持将命令的执行结果赋值给变量,常见的有以下两种方式:

    xub$ name=`return`
    xub$ name=$(return)
    

    第一种方式把命令用反引号(位于 Esc 键的下方)包围起来,反引号和单引号非常相似,容易产生混淆,所以不推荐使用这种方式;第二种方式把命令用$()包围起来,区分更加明显,所以推荐使用这种方式。

    举例1

    xub$ name=$(cat name.text)  #把name.text文件内容赋值给name
    xub$ echo $name  #输出
    大家好 我叫小小
    

    举例2,date 命令用来获得当前的系统时间,使用命令替换可以将它的结果赋值给一个变量。

    xub$ begin_time=`date`    #开始时间,使用``替换
    xub$ sleep 20s            #休眠20秒
    xub$ finish_time=$(date)  #结束时间,使用$()替换
    xub$ echo "Begin time: $begin_time"
    Begin time: 2019年 5月16日 星期四 22时37分46秒 CST
    xub$ echo "Finish time: $finish_time"
    Finish time: 2019年 5月16日 星期四 22时38分06秒 CST
    

    使用 data 命令的%s格式控制符可以得到当前的 UNIX 时间戳,这样就可以直接计算脚本的运行时间了。

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

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

    xub$ ls=`ls -l | grep damo`
    xub$ echo $ls  #不使用双引号包围
    drwxr-xr-x 16 xub staff 544 5 15 14:27 adamo drwxr-xr-x 4 xub staff 136 3 21 17:27 damo
    xub$ echo "$ls"  #使用双引号包围
    drwxr-xr-x   16 xub  staff    544  5 15 14:27 adamo #发现使用双引号才会将变量内容分行
    drwxr-xr-x    4 xub  staff    136  3 21 17:27 damo
    

    总结 原则上讲,上面提到的两种变量替换的形式是等价的,可以随意使用;但是,反引号毕竟看起来像单引号,有时候会对查看代码造成困扰,而使用 $() 就相对清晰,能有效避免这种混乱。而且有些情况必须使用它,因为它支持嵌套,反引号不行。同时也要注意$() 仅在 Bash Shell 中有效,而反引号可在多种 Shell 中使用。


    二、Shell位置参数

    运行 Shell 脚本文件时我们可以给它传递一些参数,这些参数在脚本文件内部可以使用$n的形式来接收,例如,$1 表示第一个参数,$2 表示第二个参数,依次类推。

    这种通过$n的形式来接收的参数,在 Shell 中称为位置参数。

    1、给脚本文件传递位置参数

    请编写下面的代码,并命名为family.sh

    #!/bin/bash
    # $1代表接收第一个传进来的参数,$2代表第二个
    echo "name: $1" 
    echo "sex: $2"
    

    运行family.sh

    xub$ sh family.sh 小小 3岁  #传入两个参数 中间以空格分开
    name: 小小       #输出
    sex: 3岁
    

    2、给函数传递位置参数

    同样创建family.sh脚本

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

    运行family.sh脚本

    xub$ sh family.sh #运行脚本
    name: 小小    #输出
    age: 3岁
    

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


    三、Shell 特殊变量及其含义

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

    下面我们通过两个例子来演示。

    1、给脚本文件传递参数

    编写下面的代码,并保存为family.sh

    #!/bin/bash
    echo "当前shell进程 ID: $$"
    echo "第0个参数名称: $0"
    echo "第一个参数名称: $1"
    echo "第二个参数名称: $2"
    echo "所有参数名称输出方式一: $@"
    echo "所有参数名称输出方式二: $*"
    echo "传递给脚本或函数的参数个数: $#"
    

    运行 family.sh

    xub$ sh family.sh 张三 王老五  #运行脚本
    当前shell进程 ID: 38745
    第0个参数名称: family.sh
    第一个参数名称: 张三
    第二个参数名称: 王老五
    所有参数名称输出方式一: 张三 王老五
    所有参数名称输出方式二: 张三 王老五
    传递给脚本或函数的参数个数: 2
    

    2、给函数传递参数

    编写下面的代码,并保存为 family.sh

    #!/bin/bash
    #定义函数
    function fun(){
    echo "当前shell进程 ID: $$"
    echo "第0个参数名称: $0"
    echo "第一个参数名称: $1"
    echo "第二个参数名称: $2"
    echo "所有参数名称输出方式一: $@"
    echo "所有参数名称输出方式二: $*"
    echo "传递给脚本或函数的参数个数: $#"
    }
    fun 李四 赵六
    

    运行family.sh

    xub$ sh family.sh 
    当前shell进程 ID: 40243
    第0个参数名称: family.sh
    第一个参数名称: 李四
    第二个参数名称: 赵六
    所有参数名称输出方式一: 李四 赵六
    所有参数名称输出方式二: 李四 赵六
    传递给脚本或函数的参数个数: 2
    

    3、Shell $*和$@的区别

    相同点:$* 和 $@ 都表示传递给函数或脚本的所有参数。当 $* 和 $@ 不被双引号" "包围时,它们之间没有任何区别,都是将接收到的每个参数看做一份数据,彼此之间以空格来分隔。

    不同点:但是当它们被双引号" "包含时,就会有区别了:

    • "$*"会将所有的参数从整体上看做一份数据,而不是把每个参数都看做一份数据。
    • "$@"仍然将每个参数都看作一份数据,彼此之间是独立的。

    比如传递了 5 个参数,那么对于"$*"来说,这 5 个参数会合并到一起形成一份数据,它们之间是无法分割的;而对于"$@"来说,这 5 个参数是相互独立的,它们是 5 份数据。

    如果使用 echo 直接输出"$*""$@"做对比,是看不出区别的;但如果使用 for 循环来逐个输出数据,立即就能看出区别来。

    示例

    编写下面的代码,并保存为 test.sh

    #!/bin/bash
    echo "开始遍历参数 from "$*""
    for var in "$*"
    do
        echo "$var"
    done
    echo "开始遍历参数 from "$@""
    for var in "$@"
    do
        echo "$var"
    done
    

    运行 test.sh,并附带参数:

    xub$ sh test.sh 小小 爸爸 妈妈
    开始遍历参数 from "$*"  #很明显$*把我穿入的参数作为一个整体
    小小 爸爸 妈妈
    开始遍历参数 from "$@" # $@传进来的参数是相互独立的
    小小
    爸爸
    妈妈
    

    从运行结果可以发现,对于"$*",只循环了 1 次,因为它只有 1 分数据;对于"$@",循环了 3 次,因为它有 3份数据。

    4、Shell $?

    $? 是一个特殊变量,用来获取上一个命令的退出状态,或者上一个函数的返回值。

    所谓退出状态,就是上一个命令执行后的返回结果。退出状态是一个数字,一般情况下,大部分命令执行成功会返回 0,失败返回 1。不过,也有一些命令返回其他值,表示不同类型的错误。

    1、$? 获取上一个命令的退出状态

    编写下面的代码,并保存为 test.sh:

    #!/bin/bash
    if [ "$1" == 100 ]
    then
       exit 0  #参数正确,退出状态为0
    else
       exit 1  #参数错误,退出状态1
    fi
    

    exit表示退出当前 Shell 进程,我们必须在新进程中运行 test.sh,否则当前 Shell 会话(终端窗口)会被关闭,我们就无法取得它的退出状态了。

    例如,运行 test.sh 时传递参数 100:

    xub$ bash ./test.sh 100  #作为一个新进程运行
    xub$ echo $?
    0
    

    再如,运行 test.sh 时传递参数 89:

    xub$ bash ./test.sh 89  #作为一个新进程运行
    xub$ echo $?
    1
    

    2、 $? 获取函数的返回值

    编写下面的代码,并保存为 test.sh:

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

    运行结果 73

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

    参考

    Shell脚本学习指南



    只要自己变优秀了,其他的事情才会跟着好起来(少将13)
    
  • 相关阅读:
    HTML 特殊符号编码对照表
    C#删除字符串最后一个字符的几种方法
    c# 获取相对路径
    垂直滚动条代码
    Android微信分享功能实例+demo
    android之Itent.ACTION_PICK Intent.ACTION_GET_CONTENT妙用
    Android Camera 使用小结
    onSaveInstanceState和onRestoreInstanceState
    Android中的PopupWindow详解
    Unable to execute dex: java.nio.BufferOverflowException.解决办法
  • 原文地址:https://www.cnblogs.com/qdhxhz/p/10880718.html
Copyright © 2011-2022 走看看