变量
Shell变量:Shell变量的定义、删除变量、只读变量、变量类型
变量是任何一种编程语言都必不可少的组成部分,变量用来存放各种数据。脚本语言在定义变量时通常不需要指明类型,直接赋值就可以,Shell 变量也遵循这个规则。
在 Bash shell 中,每一个变量的值都是字符串,无论你给变量赋值时有没有使用引号,值都会以字符串的形式存储。
这意味着,Bash shell 在默认情况下不会区分变量类型,即使你将整数和小数赋值给变量,它们也会被视为字符串,这一点和大部分的编程语言不同。
例如在 C/C++ 中,变量分为整型、浮点型、字符串、布尔等多种类型。
当然,如果有必要,你也可以使用 declare 关键字显式定义变量的类型,但在一般情况下没有这个需求,Shell 开发者在编写代码时自行注意值的类型即可。
#为什么要有变量
书面解释:变量是编程语言为我们提供的一种'存取内存'的机制
大白话:编程语言里之所有有变量这种语法是为了让计算机能够像人一样去'记忆事物的状态'
文件是操作系统为我们提供的一种'读写硬盘'的机制
定义变量
Shell 支持以下三种定义变量的方式:
#直接赋值
variable=value
variable='value'
variable="value"
variable 是变量名,value 是赋给变量的值。如果 value 不包含任何空白符(例如空格、Tab缩进等),那么可以不使用引号;如果 value 包含了空白符,那么就必须使用引号包围起来。使用单引号和使用双引号也是有区别的,稍后我们会详细说明。
注意,赋值号的周围不能有空格,这可能和你熟悉的大部分编程语言都不一样。
Shell 变量的命名规范和大部分编程语言都一样:
- 变量名由数字、字母、下划线组成;
- 必须以字母或者下划线开头;
- 不能使用 Shell 里的关键字(通过 help 命令可以查看保留关键字)。
变量定义举例:
url=http://c.biancheng.net
echo $url
name='C语言中文网'
echo $name
author="严长生"
echo $author
使用变量
使用一个定义过的变量,只要在变量名前面加美元符号$
即可,如:
author="严长生"
echo $author
echo ${author}
变量名外面的花括号{ }
是可选的,加不加都行,加花括号是为了帮助解释器识别变量的边界,比如下面这种情况:
skill="Java"
echo "I am good at ${skill}Script"
如果不给 skill 变量加花括号,写成echo "I am good at $skillScript"
,解释器就会把 $skillScript 当成一个变量(其值为空),代码执行结果就不是我们期望的样子了。
推荐给所有变量加上花括号{ }
,这是个良好的编程习惯。
修改变量的值
已定义的变量,可以被重新赋值,如:
url="http://c.biancheng.net"
echo ${url}
url="http://c.biancheng.net/cpp/shell/"
echo ${url}
第二次对变量赋值时不能在变量名前加$
,只有在使用变量时才能加$
。
单引号和双引号的区别
前面我们还留下一个疑问,定义变量时,变量的值可以由单引号' '包围,也可以由双引号" "包围,它们到底有什么区别呢?不妨以下面的代码为例来说明:
#!/bin/bash
url="http://c.biancheng.net"
website1='C语言中文网:${url}'
website2="C语言中文网:${url}"
echo $website1echo $website2
运行结果:
C语言中文网:${url}
C语言中文网:http://c.biancheng.net
#单引号强引,缩减即所得
#双引号弱引,解释器会解析里面的变量、命令等
以单引号' '
包围变量的值时,单引号里面是什么就输出什么,即使内容中有变量和命令(命令需要反引起来)也会把它们原样输出。这种方式比较适合定义显示纯字符串的情况,即不希望解析变量、命令等的场景。
以双引号" "包围变量的值时,输出时会先解析里面的变量和命令,而不是把双引号中的变量名和命令原样输出。这种方式比较适合字符串中附带有变量和命令并且想将其解析后再输出的变量定义。
建议:如果变量的内容是数字,那么可以不加引号;如果真的需要原样输出就加单引号;其他没有特别要求的字符串等最好都加上双引号,定义变量时加双引号是最常见的使用场景。
将命令的结果赋值给变量
Shell 也支持将命令的执行结果赋值给变量,常见的有以下两种方式:
#传参
variable=`command`
variable=$(command)
#``不支持嵌套,$()可以进行多级嵌套
第一种方式把命令用反引号包围起来,反引号和单引号非常相似,容易产生混淆,所以不推荐使用这种方式;第二种方式把命令用$()
包围起来,区分更加明显,所以推荐使用这种方式。
例如,我在 code 目录中创建了一个名为 log.txt 的文本文件,用来记录我的日常工作。下面的代码中,使用 cat 命令将 log.txt 的内容读取出来,并赋值给一个变量,然后使用 echo 命令输出。
[mozhiyan@localhost ~]$ cd code
[mozhiyan@localhost code]$ log=$(cat log.txt)
[mozhiyan@localhost code]$ echo $log
[2017-09-10 06:53:22] 编写Shell教程
[mozhiyan@localhost code]$ log=`cat log.txt`
[mozhiyan@localhost code]$ echo $log
[2017-09-10 06:53:22] 编写Shell教程
只读变量
使用 readonly 命令可以将变量定义为只读变量,只读变量的值不能被改变。
下面的例子尝试更改只读变量,结果报错:
#!/bin/bash
myUrl="http://see.xidian.edu.cn/cpp/shell/"
readonly myUrlmyUrl="http://see.xidian.edu.cn/cpp/danpianji/"
运行脚本,结果如下:
/bin/sh: NAME: This variable is read only.
#重启终端,只读状态消失
删除变量
使用 unset 命令可以删除当前终端定义的变量。语法:
unset variable_name
#不能删除只读状态的变量
举个例子:
#!/bin/sh
myUrl="http://see.xidian.edu.cn/cpp/u/xitong/"
unset myUrl
echo $myUrl
上面的脚本没有任何输出。
变量类型
运行shell时,会同时存在三种变量:
1) 局部变量
局部变量在脚本或命令中定义,仅在当前shell实例中有效,其他shell启动的程序不能访问局部变量。
2) 环境变量(全局变量)
所有的程序,包括shell启动的程序,都能访问环境变量,有些程序需要环境变量来保证其正常运行。必要的时候shell脚本也可以自定义环境变量。
3) shell变量
shell变量是由shell程序设置的特殊变量。shell变量中有一部分是环境变量,有一部分是局部变量,这些变量保证了shell的正常运行
查看所有定义的变量
set
[root@hass-11 ~]# abcd=123
[root@hass-11 ~]# set|grep abcd
env
[root@hass-11 ~]# export a=1234
[root@hass-11 ~]# env|grep a
变量的替换
#变量没值就没值,变量有值就覆盖,注意覆盖不是赋值
[root@hass-11 script]# unset x
[root@hass-11 script]# echo ${x:+333}
[root@hass-11 script]# echo $x
[root@hass-11 script]# x=111
[root@hass-11 script]# echo ${x:+333}
333
[root@hass-11 script]# echo $x
111
#变量没值就覆盖,变量有值就直接打印,注意覆盖不是赋值
[root@hass-11 script]# unset x
[root@hass-11 script]# echo ${x:-333}
333
[root@hass-11 script]# echo $x
[root@hass-11 script]# echo $x
[root@hass-11 script]# x=111
[root@hass-11 script]# echo ${x:-333}
111
[root@hass-11 script]# echo $x
111
#变量没值就赋值,变量有值就直接打印,注意是赋值
[root@hass-11 script]# unset x
[root@hass-11 script]# echo ${x:=333}
333
[root@hass-11 script]# echo $x
333
[root@hass-11 script]# x=111
[root@hass-11 script]# echo ${x:=333}
111
[root@hass-11 script]# echo $x
111
#变量没值就打印注释,变量有值就直接打印,注意不是赋值
[root@hass-11 script]# unset x
[root@hass-11 script]# echo ${x:?333}
-bash: x: 333
[root@hass-11 script]# echo $x
[root@hass-11 script]# x=111
[root@hass-11 script]# echo ${x:?333}
111
[root@hass-11 script]# echo $x
111
#设置变量只读
[root@hass-11 test]# readonly x
[root@hass-11 test]# x=1
-bash: x: readonly variable
#重启终端,只读变量消失
#使用该命令可以快速检测
unset x;echo ${x:+333};echo $x;x=111;echo ${x:+333};echo $x
#不加':',除了以下情况,其他和加冒号结果一样
unset x;echo ${x?333};echo $x;x=111;echo ${x?333};echo $x
-bash: x: 333
企业实用
在apache1服务启动脚本/etc/init.d/httpd中
1 #!/bin/bash
2 #
3 # httpd Startup script for the Apache HTTP Server
4 #
5 # chkconfig: - 85 15
6 # description: The Apache HTTP Server is an efficient and extensible \
7 # server implementing the current HTTP standards.
8 # processname: httpd
9 # config: /etc/httpd/conf/httpd.conf
10 # config: /etc/sysconfig/httpd
11 # pidfile: /var/run/httpd/httpd.pid
12 #
13 ### BEGIN INIT INFO
14 # Provides: httpd
15 # Required-Start: $local_fs $remote_fs $network $named
16 # Required-Stop: $local_fs $remote_fs $network
17 # Should-Start: distcache
18 # Short-Description: start and stop Apache HTTP Server
19 # Description: The Apache HTTP Server is an extensible server
20 # implementing the current HTTP standards.
21 ### END INIT INFO
22
23 # Source function library.
24 . /etc/rc.d/init.d/functions
25
26 if [ -f /etc/sysconfig/httpd ]; then
27 . /etc/sysconfig/httpd
28 fi
29
30 # Start httpd in the C locale by default.
31 HTTPD_LANG=${HTTPD_LANG-"C"} #若HTTPD_LANG变量没有赋值(没有定义),则将HTTPD_LANG值变,此处为":"省略的情况
33 # This will prevent initlog from swallowing up a pass-phrase prompt if
34 # mod_ssl needs a pass-phrase from the user.
35 INITLOG_ARGS=""
36
37 # Set HTTPD=/usr/sbin/httpd.worker in /etc/sysconfig/httpd to use a server
38 # with the thread-based "worker" MPM; BE WARNED that some modules may not
39 # work correctly with a thread-based MPM; notably PHP will refuse to start.
40
41 # Path to the apachectl script, server binary, and short-form for messages.
42 apachectl=/usr/sbin/apachectl
43 httpd=${HTTPD-/usr/sbin/httpd} #若HTTPD没有赋值(没有定义):则将httpd赋值为"/usr/sbin/httpd"
44 prog=httpd
注:
1.在企业中,针对目录路径情况等的处理就可以采用上述变量不存在的方式,防止因目录不存在而导致的异常
删除7天前的过期数据备份
[centos@mycentos shell]$ cat 1.sh
#!/bin/bash
sudo find ${path-/tmp} -name "*.tar.gz" -type f -mtime +7 |xargs rm -f
1.如果忘记了定义path路径变量,又不希望其为空,就可以定义/tmp代替path空值返回值.
2.若忘记了定义path路径变量,还没有做特殊变量定义,此条命令会出现异常
补充:http脚本变量的定义方式:
httpd=${HTTPD-/usr/sbin/httpd}
prog=httpd
pidfile=${PIDFILE-/var/run/httpd/httpd.pid}
lockfile=${LOCKFILE-/var/lock/subsys/httpd}
#此定义方式可以防止出现空值