Shell脚本编程(二):shell变量
定义变量
定义变量时,变量名不加美元符号($,PHP语言中变量需要),如:
your_name="runoob.com"
注意,变量名和等号之间不能有空格,这可能和你熟悉的所有编程语言都不一样。同时,变量名的命名须遵循如下规则:
- 命名只能使用英文字母,数字和下划线,首个字符不能以数字开头。
- 中间不能有空格,可以使用下划线(_)。
- 不能使用标点符号。
- 不能使用bash里的关键字(可用help命令查看保留关键字)。
有效的 Shell 变量名示例如下:
DEVICENAME
LD_LIBRARY_PATH
_var
var2
无效的变量命名:
?devicetype=
user name=runoob
status = 0
7isactive=1
除了显式地直接赋值,还可以用语句给变量赋值,如:
for file in `ls /etc`
或
for file in $(ls /etc)
以上语句将 /etc 下目录的文件名循环出来。
使用变量
使用一个定义过的变量,只要在变量名前面加美元符号即可,如:
#!/bin/bash
devicetype='lift'
echo $devicetype
变量名外面的花括号是可选的,加不加都行,加花括号是为了帮助解释器识别变量的边界,比如下面这种情况:
for skill in Ada Coffe Action Java; do
echo "I am good at ${skill}Script"
done
如果不给skill变量加花括号,写成echo "I am good at $skillScript",解释器就会把$skillScript当成一个变量(其值为空),代码执行结果就不是我们期望的样子了。
推荐给所有变量加上花括号,这是个好的编程习惯。
已定义的变量,可以被重新定义,如:
#!/bin/bash
devicetype='lift'
echo $devicetype
devicetype='crane'
echo $devicetype
结果
lift
crane
这样写是合法的,但注意,第二次赋值的时候不能写$your_name="alibaba",使用变量的时候才加美元符($)。
只读变量
使用 readonly 命令可以将变量定义为只读变量,只读变量的值不能被改变。
下面的例子尝试更改只读变量,结果报错:
#!/bin/bash
pdfurl='http://www.xxxx.com/resource/pdfs/181101/6238258284.pdf'
echo $pdfurl
readonly pdfurl
pdfurl='http://www.xxxx.com/resource/pdfs/181111/6238258255.pdf'
echo $pdfurl
运行脚本,可以看到第二次赋值没有成功,并且报错,结果如下:
http://www.xxxx.com/resource/pdfs/181101/6238258284.pdf
http://www.xxxx.com/resource/pdfs/181101/6238258284.pdf
/tmp//main.sh: line : pdfurl: readonly variable
删除变量
使用 unset 命令可以删除变量。语法:
unset variable_name
变量被删除后不能再次使用。unset 命令不能删除只读变量。
实例
#!/bin/bash
# 定义两个变量并打印
pdfurl='http://www.xxxx.com/resource/pdfs/181101/6238258284.pdf'
imgurl='http://www.xxxx.com/resource/imgs/181101/6238258284.jpg'
echo $pdfurl
echo $imgurl
# 将pdfurl置为只读
readonly pdfurl
# 尝试删除这两个变量
unset pdfurl
unset imgurl
# 再次打印
echo $pdfurl
echo $imgurl
执行实例,可以看到第二次只打印了imgurl。
http://www.xxxx.com/resource/pdfs/181101/6238258284.pdf
http://www.xxxx.com/resource/imgs/181101/6238258284.jpg
http://www.xxxx.com/resource/pdfs/181101/6238258284.pdf /tmp//main.sh: line : unset: pdfurl: cannot unset: readonly variable
变量作用域
Shell变量的作用域(Scope),就是 Shell 变量的有效范围(可以使用的范围)。
在不同的作用域中,同名的变量不会相互干涉,就好像 A 班有个叫小明的同学,B 班也有个叫小明的同学,虽然他们都叫小明(对应于变量名),但是由于所在的班级(对应于作用域)不同,所以不会造成混乱。但是如果同一个班级中有两个叫小明的同学,就必须用类似于“大小明”、“小小明”这样的命名来区分他们。
Shell 变量的作用域可以分为三种:
- 有的变量可以在当前 Shell 会话中使用,这叫做全局变量(global variable);
- 有的变量只能在函数内部使用,这叫做局部变量(local variable);
- 而有的变量还可以在其它 Shell 中使用,这叫做环境变量(environment variable)。
1.全局变量
所谓全局变量,就是指变量在当前的整个 Shell 会话中都有效。每个 Shell 会话都有自己的作用域,彼此之间互不影响。在 Shell 中定义的变量,默认就是全局变量。
想要实际演示全局变量在不同 Shell 会话中的互不相关性,可在图形界面下同时打开两个 Shell,或使用两个终端远程连接到服务器(SSH)。
首先打开一个 Shell 窗口,定义一个变量 a 并赋值为 1,然后打印,这时在同一个 Shell 窗口中是可正确打印变量 a 的值的。然后再打开一个新的 Shell 窗口,同样打印变量 a 的值,但结果却为空,如图 所示。
这说明全局变量 a 仅仅在定义它的第一个 Shell 中有效,对其它 Shell 没有影响。这很好理解,就像小王家和小徐家都有一部电视机(变量名相同),但是同一时刻小王家和小徐家的电视中播放的节目可以是不同的(变量值不同)。
需要强调的是,全局变量的作用范围是当前的 Shell 会话,而不是当前的 Shell 脚本文件,它们是不同的概念。打开一个 Shell 窗口就创建了一个 Shell 会话,打开多个 Shell 窗口就创建了多个 Shell 会话,每个 Shell 会话都是独立的进程,拥有不同的进程 ID。在一个 Shell 会话中,可以执行多个 Shell 脚本文件,此时全局变量在这些脚本文件中都有效。
例如,现在有两个 Shell 脚本文件,分别是 a.sh 和 b.sh。a.sh 的代码如下:
#!/bin/bash
echo $a
b=
b.sh 的代码如下:
#!/bin/bash echo $b
打开一个 Shell 窗口,输入以下命令:
$ a=
$ . ./a.sh $ . b.sh $
从输出结果可以发现,在 Shell 会话中以命令行的形式定义的变量 a,在 a.sh 中有效;在 a.sh 中定义的变量 b,在 b.sh 中也有效。
2.局部变量
Shell 也支持自定义函数,但是 Shell 函数和 C/C++、Java 等其他编程语言函数的一个不同点就是:在 Shell 函数中定义的变量默认也是全局变量,它和在函数外部定义变量拥有一样的效果。请看下面的代码:
#!/bin/bash
#定义函数
function func(){
a=
}
#调用函数
func
#输出函数内部的变量
echo $a
输出结果:
a 是在函数内部定义的,但是在函数外部也可以得到它的值,证明它的作用域是全局的,而不是仅限于函数内部。
要想变量的作用域仅限于函数内部,那么可以在定义时加上local
命令,此时该变量就成了局部变量。请看下面的代码:
#!/bin/bash
#定义函数
function func(){
local a=
}
#调用函数
func
#输出函数内部的变量
echo $a
输出结果为空,表明变量 a 在函数外部无效,是一个局部变量。
Shell 变量的这个特性和 JavaScript 中的变量是类似的。在 JavaScript 函数内部定义的变量,默认也是全局变量,只有加上var
关键字,它才会变成局部变量。
3.环境变量
全局变量只在当前 Shell 会话中有效,如果使用export
命令将它导出,那么它就在所有的子 Shell 中也有效了,这称为“环境变量”。
环境变量被创建时所处的 Shell 被称为父 Shell,如果在父 Shell 中再创建一个 Shell,则该 Shell 被称作子 Shell。当子 Shell 产生时,它会继承父 Shell 的环境变量为自己所用,所以说环境变量可从父 Shell 传给子 Shell。不难理解,环境变量还可以传递给孙 Shell。
注意,环境变量只能向下传递而不能向上传递,即“传子不传父”。
在一个 Shell 中创建子 Shell 最简单的方式是运行 bash 命令,如图所示。
通过exit
命令可以一层一层地退出 Shell。
下面演示一下环境变量的使用:
$ a= #定义一个全局变量
$ echo $a #在当前Shell中输出a,成功 $ bash #进入子Shell
$ echo $a #在子Shell中输出a,失败 $ exit #退出子Shell
exit
$ export a #将a导出为环境变量
$ bash #重新进入子Shell
$ echo $a #在子Shell中再次输出a,成功 $ exit #退出子Shell
exit
$ exit #退出父Shell,结束整个Shell会话
可以发现,默认情况下,a 在子 Shell 中是无效的;使用 export 将 a 导出为环境变量后,在子 Shell 中就可以使用了。export a
这种形式是在定义变量 a 以后再将它导出为环境变量,如果想在定义的同时导出为环境变量,可以写作export a=22
。
注意,本节我们一直强调的是环境变量在子 Shell 中有效,并没有说它在所有的 Shell 种有效;如果你通过终端创建一个新的 Shell,那么它就不是当前 Shell 的子 Shell,环境变量对这个 Shell 就是无效的。
此外,通过export
命令导出的环境变量是临时的,关闭 Shell 会话后它就销毁了。所以,这种环境变量也只是在局部范围内起作用,并不影响所有 Shell。
如果想让环境变量在所有 Shell 中都有效,并且能够永久保存,在关闭 Shell 后也不丢失,那么就需要把环境变量写入启动文件。至于如何写入文件,请大家自行百度,这里就不再赘述了。
Shell字符串
字符串是shell编程中最常用最有用的数据类型(除了数字和字符串,也没啥其它类型好用了),字符串可以用单引号,也可以用双引号,也可以不用引号。单双引号的区别跟PHP类似。
单引号
str='this is a string'
单引号字符串的限制:
- 单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的;
- 单引号字串中不能出现单独一个的单引号(对单引号使用转义符后也不行),但可成对出现,作为字符串拼接使用。
双引号
#!/bin/bash
ordernum=''
# 双引号里既可以有变量又可以有转义
orderdetail="this is the order $ordernum detail info, find it by \\"
echo $ordernum
echo $orderdetail
输出结果为:
this is the order detail info, find it by \
双引号的优点:
- 双引号里可以有变量
- 双引号里可以出现转义字符
拼接字符串
#!/bin/bash
datestr='2018-01-01'
timestr='11:11:11'
# 双引号拼接
echo '双引号拼接字符串'
currentdatetime_1="now time is "$datestr" "$timestr" !"
currentdatetime_2="now time is ${datestr}+${timestr} 。"
echo $currentdatetime_1 $currentdatetime_2
# 单引号拼接
echo '单引号拼接字符串'
currentdatetime_11='now time is '$datestr' '$timestr' !'
currentdatetime_22='now time is ${datestr}+${timestr} 。'
echo $currentdatetime_11 $currentdatetime_22
输出结果为:
双引号拼接字符串
now time is -- :: ! now time is --+:: 。
单引号拼接字符串
now time is -- :: ! now time is ${datestr}+${timestr} 。
获取字符串长度
#!/bin/bash
datestr='2018-01-01'
echo $datestr 的长度为: ${#datestr}
结果
-- 的长度为:
提取子字符串(截取)
以下实例从字符串第 1 个字符开始截取 4 个字符:
#!/bin/bash
datestr='2018-01-02'
echo 日期【 $datestr 】的年为: ${datestr::}
结果
日期【 -- 】的年为:
查找子字符串
查找字符 - 或 : 的位置(哪个先出现就计算哪个):
#!/bin/bash
datestr='2018-01-02 11:11:11'
echo `expr index "$datestr" -:`
结果:
5
注意: 以上脚本中 ` 是反引号,而不是单引号 ',不要看错了哦。
Shell 数组
bash支持一维数组(不支持多维数组),并且没有限定数组的大小。
类似于 C 语言,数组元素的下标由 0 开始编号。获取数组中的元素要利用下标,下标可以是整数或算术表达式,其值应大于或等于 0。
定义数组
在 Shell 中,用括号来表示数组,数组元素用"空格"符号分割开。定义数组的一般形式为:
数组名=(值1 值2 ... 值n)
例如:
array_name=(value0 value1 value2 value3)
或者
array_name=(
value0
value1
value2
value3
)
还可以单独定义数组的各个分量:
array_name[]=value0
array_name[]=value1
array_name[n]=valuen
可以不使用连续的下标,而且下标的范围没有限制。
读取数组
读取数组元素值的一般格式是:
${数组名[下标]}
例如:
valuen=${array_name[n]}
使用 @ 符号可以获取数组中的所有元素,例如:
echo ${array_name[@]}
获取数组的长度
获取数组长度的方法与获取字符串长度的方法相同,例如:
# 取得数组元素的个数
length=${#array_name[@]}
# 或者
length=${#array_name[*]}
# 取得数组单个元素的长度
lengthn=${#array_name[n]}
Shell 注释
以 # 开头的行就是注释,会被解释器忽略。
通过每一行加一个 # 号设置多行注释,像这样:
#--------------------------------------------
# 这是一个注释
# author:菜鸟教程
# site:www.runoob.com
# slogan:学的不仅是技术,更是梦想!
#--------------------------------------------
##### 用户配置区 开始 #####
#
#
# 这里可以添加脚本描述信息
#
#
##### 用户配置区 结束 #####
如果在开发过程中,遇到大段的代码需要临时注释起来,过一会儿又取消注释,怎么办呢?
每一行加个#符号太费力了,可以把这一段要注释的代码用一对花括号括起来,定义成一个函数,没有地方调用这个函数,这块代码就不会执行,达到了和注释一样的效果。
多行注释
多行注释还可以使用以下格式:
:<<EOF
注释内容...
注释内容...
注释内容...
EOF
EOF 也可以使用其他符号:
:<<'
注释内容...
注释内容...
注释内容...
' :<<!
注释内容...
注释内容...
注释内容...
!
Shell脚本编程(二):shell变量的更多相关文章
- Linux shell脚本编程(二)
Linux shell脚本编程(二) 练习:求100以内所有偶数之和; 使用至少三种方法实现; 示例1: #!/bin/bash # declare -i sum=0 #声明一个变量求和,初始值为0 ...
- shell 脚本编程之特殊变量
$0 当前脚本的文件名$n 传递给脚本或函数的参数.n 是一个数字,表示第几个参数.例如,第一个参数是$1,第二个参数是$2.$# 传递给脚本或函数的参数个数.$* 传递给脚本或函数的所有参数.$@ ...
- linux中的shell脚本编程---初识shell
Shell是用户与Linux或Unix内核通信的工具,shell编程指的并不是编写这个工具,而是指利用现有的shell工具进行编程,写出来的程序是轻量级的脚本,我们叫做shell脚本. Shell的语 ...
- Shell脚本 (二) 变量与运算符
个人博客网:https://wushaopei.github.io/ (你想要这里多有) 四.Shell 中的变量 1.系统变量 1.1 常用系统变量 $HOME. $PWD. $SHELL . ...
- Shell脚本编程具体解释
第12章 Shell脚本编程 l Shell命令行的执行 l 编写.改动权限和运行Shell程序的步骤 l 在Shell程序中使用參数和变量 l 表达式比較.循环结构语句和条件结构语句 l ...
- shell脚本(二)
shell脚本(二)——变量 一.定义:用来存放各种数据,编程语言组成部分 变量的命名规则: 变量名由数字 字母下划线组成 必须以字母或者下划线开头 不能使用shell里面的关键词 ...
- shell脚本编程(一) 变量、条件判断、循环
目录 1. shell脚本编程 2. 运行 Shell 脚本有两种方法 3. 变量 4. 本地变量 5. 环境变量 6. 参数变量 7. 多行注释 8. if条件判断 ...
- Shell脚本编程总结及速查手册
Shell是一种编程语言, 它像其它编程语言如: C, Java, Python等一样也有变量/函数/运算符/if语句/循环控制/… 但在开始之前, 我想先理清Shell语言与Shell之间的关系. ...
- shell脚本编程基础
最近学习了shell脚本编程,感觉自己的脚本写的不太好,所以想把shell脚本相关的知识系统的整理一下,便于以后的学习和使用. 一.shell脚本基础 shell脚本是利用shell的功能 ...
- SHELL脚本编程的常识和VI常用技巧
来源:http://mprc.pku.edu.cn/mentors/training/TrainingCourses/material/ShellProgramming.HTM#_Toc3751808 ...
随机推荐
- java中与和或的注意点
1.&&和&的区别 &:无论左边是true是false.右边都运算. &&:当左边为false时,右边不运算. 2.|与||的区别 |:两边都参与运算. ...
- js数据结构之hash散列的详细实现方法
hash散列中需要确定key和value的唯一确定关系. hash散列便于快速的插入删除和修改,不便于查找最大值等其他操作 以下为字符和数字的hash散列: function HashTable () ...
- Android应用开发-网络编程(二)
Apache HttpClient框架 GET方式请求提交数据 1. 创建一个HttpClient HttpClient hc = new DefaultHttpClient(); 2. 创建一个Ht ...
- java 利用Future做超时任务处理
Callable<String> task = new Callable<String>() { @Override public String call() throws E ...
- AGC027 E - ABBreviate
目录 题目链接 题解 代码 题目链接 AGC027 E - ABBreviate 题解 神仙啊 建议查看https://img.atcoder.jp/agc027/editorial.pdf 定义a ...
- 3451: Tyvj1953 Normal 点分治 FFT
国际惯例的题面:代价理解为重心和每个点这个点对的代价.根据期望的线性性,我们枚举每个点,计算会产生的ij点对的代价即可.那么,i到j的链上,i必须是第一个被选择的点.对于i来说,就是1/dis(i,j ...
- IDA Pro Disassembler 6.8.15.413 (Windows, Linux, Mac)
IDA: What's new in 6.8 Highlights This is mainly a maintenance release, so our focus was on fixing b ...
- 如何正确地使用android中的progressdialog
网上有很多关于progressdialog的用法的介绍,下面这个是最具代表性的: http://sd8089730.iteye.com/blog/1441610 其核心代码: Handler hand ...
- Windows DIB文件操作具体解释-4.使用DIB Section
前面讲了为了提高DIB的显示性能和效率,我们将DIB转换成DDB.可是这又遇到一个问题.假设我想操作DIB的数据的话,显然是不能使用DDB:一是由于DIB转DDB时发生了颜色转换.再就是DDB无法直接 ...
- 在Objective-C 中使用字符生成NSArray、NSDictionary、NSNumber
@符号不仅可以生成字符串,还可以生成其他数据类型如NSArray.NSDictionary和NSNumber,是一种简洁快速的用法. // NSArray array = [NSArray array ...