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)

Shell(1)---变量的更多相关文章

  1. shell与变量的声明的操作

    1.给命令起别名:alias 执行下面命令后,可以使用dir代替ls –l 命令,显示目录中的文件详细信息: 还可以用一个别名表示几个命令 的结合: 2.ps:显示当前登录会话的所有活动进程: 3.更 ...

  2. shell之变量与read

    环境变量 set 环境变量可供shell以外的程序使用 shell变量 env shell变量仅供shell内部使用 set:显示(设置)shell变量 包括的私有变量以及用户变量,不同类的shell ...

  3. 【Linux】之shell特殊变量整理

    目录 1. 特殊变量列表 2. 特殊说明 在shell中变量名只能包含数字.字母和下划线,因为某些包含其他字符的变量有特殊含义,这样的变量被称为特殊变量. 例如,$ 表示当前Shell进程的ID,即p ...

  4. (转载)shell变量基础—shell自定义变量

    (转载)http://see.xidian.edu.cn/cpp/html/1494.html 一.Shell定义变量需要遵循的规则 Shell编程中,使用变量无需事先声明,同时变量名的命名须遵循如下 ...

  5. shell基础——变量定义

    快速参考: 变量定义格式: 变量名=值 str1="hello world" # define a string var str2=hello # define a string ...

  6. shell的变量处理

    shell的变量处理 一.删除 删除(删除某一段) # 从前向后删除 % 从后向前删除 删除(删除某一部分) $(var:nu1:nu2) nu1表示开始位置 nu2表示删除长度 示例如下 file= ...

  7. shell 环境变量的相关配置文件和配置方法

    shell 环境变量的相关配置文件和配置方法: bash 的配置文件: 全局配置: /etc/profile, /etc/profile.d/*.sh, /etc/bashrc 个人配置 ~/.bas ...

  8. Linux编程 12 (默认shell环境变量, PATH变量重要讲解)

    一 .概述 默认情况下, bash shell会用一些特定的环境变量来定义系统的环境.这些默认环境变量可以理解是上篇所讲的系统全局环境变量. 1.1 bash  shell支持的Bourne变量 Bo ...

  9. shell模板变量替换

    我们经常使用一些模板语言来处理一些变量替换.比如jsp,php,velocity,freemarker,thymeleaf等.那对于shell来说,应该怎样替换变量呢.有一种很简单的办法可以做到. 先 ...

  10. centos shell编程5 LANMP一键安装脚本 lamp sed lnmp 变量和字符串比较不能用-eq cat > /usr/local/apache2/htdocs/index.php <<EOF重定向 shell的变量和函数命名不能有横杠 平台可以用arch命令,获取是i686还是x86_64 curl 下载 第三十九节课

    centos shell编程5  LANMP一键安装脚本 lamp  sed  lnmp  变量和字符串比较不能用-eq  cat > /usr/local/apache2/htdocs/ind ...

随机推荐

  1. vue.js 的 vue-element-admin 实践开发

    官方网址: https://panjiachen.github.io/vue-element-admin-site/zh/ 一:面包屑导航,根目录文字修改: 定位到文件 vue-element-sup ...

  2. ej3-0开端

    开始 编码多年,总有一些最佳实践,Java也是,比如设计模式,比如Effective Java 3 (ej3) . 设计模式先后看过<大话设计模式>,<HeadFirst 设计模式& ...

  3. SpringBoot:CORS处理跨域请求的三种方式

    一.跨域背景 1.1 何为跨域? Url的一般格式: 协议 + 域名(子域名 + 主域名) + 端口号 + 资源地址 示例: https://www.dustyblog.cn:8080/say/Hel ...

  4. kafka速度快的原因

    我们都知道Kafka非常快,比绝大多数的市场上其他消息中间件都要快.这里来研究下那么为什么Kafka那么快(当然不会是因为它用了Scala). Kafka的消息是保存或缓存在磁盘上的,一般认为在磁盘上 ...

  5. RK3399安装Qt

    更新软件源.升级软件 sudo apt-get update sudo apt-get upgrade 安装Qt sudo apt-get install qt5-default sudo apt-g ...

  6. GROUP BY中的WITH CUBE、WITH ROLLUP原理测试及GROUPING应用

    前几天,看到一个群友用WITH ROLLUP运算符.由于自个儿没用过,看到概念及结果都云里雾里的,所以突然来了兴趣对生成结果测了一番. 一.概念: WITH CUBE:生成的结果集显示了所选列中值的所 ...

  7. python爬虫公众号所有信息,并批量下载公众号视频

    前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者: 数据分析实战 PS:如有需要Python学习资料的小伙伴可以加点击 ...

  8. 理解并运用TP5.1-Facade

    1.内容介绍 深入解析tp5.1与laravel 中Facade底层原理实现 1. 什么是Facade 2. 为什么需要有什么好处 3.  Facade实现原理 4. 功能实现. 5. 容器注入 2. ...

  9. .netcore2.1 使用IdentityServer4 生成Token验证

    每个新技术权限验证都有一套机制,之前项目WebApi接口权限验证用的是Owin做为权限验证,而.netcore权限限制使用的是IdentityServer4,采用JWT的方法验证token. 首先使用 ...

  10. echarts背景颜色渐变的三种类型

    // 线性渐变,多用于折线柱形图,前四个参数分别是 x0, y0, x2, y2, 范围从 0 - 1,相当于在图形包围盒中的百分比,如果 globalCoord 为 `true`,则该四个值是绝对的 ...