在小学或初中的时候,我们开始接触数学方程式,例如:已知x=1,y=x+1,那么y等于多少?
在上述问题中,等号左边的x和y当时被称为未知数,但在shell编程里它们是变量名,等号右边的1和x+1则是变量内容(变量的
值)。
注意:这里的等号符号被称为赋值,而不是等号。
通过上面的例子可以得出一个变量概念的小结论:简单地说,变量就是用一个固定的字符串(也可能是字符、数字等的组合)代
替更多、更复杂的内容,该内容里可能还会包含变量、路径、字符串等其他的内容。
变量是暂时存储数据的地方及数据标记,所存储的数据在于内存空间中通过正确地调用内存空间中变量的名字就可以取出与变量
对应的数据。使用变量的最大好处就是使程序开发更为方便,当然,在编程中使用变量也是必须的,否则就很难完成相关的程序
开发工作。
[root@kang ~]# blxh="I am blxh" #<==定义变量,名字为blxh,对应的内容为“I am blxh”。
[root@kang ~]# echo $blxh #<==打印变量的值。
I am blxh
[root@kang ~]#
效果:
变量的赋值方式为:先写变量名称,紧接着是“=”这个字符,最后是值,中间无任何空格,通过echo命令加上$blxh即可输出
blxh变量的值,变量的内容一般要加双引号,以防止出错,特别是当值里的内容之间有空格时。
默认情况下,在bash Shell中是不会区分变量类型的,例如:常见的变量类型为整数、字符串、小数等。这和其他强类型语言
(例如:Java/C 语言)是有区别的,当然,如果需要指定Shell变量的类型,也可以使用declare显示定义变量的类型,但在一般
情况下没有这个需求,Shell开发者在开发脚本时需要自行注意Shell脚本中变量的类型,这对新手来说是个重点也是个难点,别
害怕,跟着博文走,一切都不是事。
变量可以分为两类:环境变量(全局变量)和普通变量(局部变量)。
环境变量也可以称为全局变量,可以在创建它们的shell及其派生出来的任意子进程shell中使用,环境变量又可分为自定义环境
变量和bash内置的环境变量。
普通变量也可称为局部变量,只能在创建它们的shell函数或shell脚本中使用。普通变量一般由开发者在开发脚本程序时创建。
环境变量一般是由export内置命令导出的变量,由于定义shell的运行环境,保证shell命令的正确执行。shell通过环境变量来确
定登录用户名、命令路径、终端类型、登录目录等,所有的环境变量都是系统全局变量,可用于所有子进程中,这包括编辑器、
shell脚本和各类应用。
环境变量可以在命令行中设置和创建,但用户退出命令行时这些变量值就会丢失,因此,如果希望永久保存环境变量,可在用户
家目录下的.bash_profile或.bashrc(非用户登录模式特有,例如远程SSH)文件中,或者全局配置/etc/bashrc(非用户登录模式
特有,例如远程SSH)或/etc/profile文件中定义。在将环境变量放入上述的文件中后,每次用户登录时这些变量都将被初始化。
按照系统规范,所有环境变量的名字均采用大写形式。在将环境变量应用于用户进程程序之前,都应该用export命令导出定义,
例如:正确的环境变量定义方法为export BLXH=1。
有一些环境变量,比如:HOME、PATH、SHELL、UID、USER等,在用户登录之前就已经被/bin/login程序设置好了,通常环
境变量被定义并保存在用户家目录下的.bash_profile文件或全局的配置文件/etc/profile中。
具体的环境变量说明参见如下表:
变量名 | 含义 |
---|---|
= _ |
上一条命令的最后一个参数 |
BASH=/bin/bash | 调用bash实例时使用的全路径名 |
BASH_VERSINFO=([0]="3"[1]="2"[2]="25"[3]="1"[4]="release"[5]="x86_64-redhat-linux-gnu") | 使用2.0以上版本时,展开为版本信息 |
BASH_VerSION=‘3.2.25(1)-release’ | 当前bash实例的版本号 |
COLORS=./etc/DIR_CLOLORS | 颜色变量 |
COLUMNS=132 | 设置该变量,就给shell编辑模式和选择的命令定义了编辑窗口的宽度 |
DIRSTACK=() | 代表目录栈的当前内容 |
EUID=0 | 在shell启动时被初始化的当前用户的有效ID |
GROUPS=() | 当前用户所属的组 |
HISTFILE=/root/.bash_history | 历史记录文件的全路径 |
HISTFILESIZE=50 | 历史文件能包含的最大行数 |
HISTSIZE=50 | 记录在命令行历史文件中的命令行数 |
HOME=/root | 当前用户家目录 |
HOSTNAME=blxh | 当前主机名称 |
HOSTTYPE=x86_64 | 当前操作系统类型 |
IFS=$'\t\n' | 内部字段分隔符,一般是空格符、制表符和换行符,用于划分由命令替换、循环结构中的表和所读取的输入产生的词的字段 |
INPUTRC=/etc/inputrc | readline启动文件的文件名,取代默认的~/.inputrc |
JAVA_HOME=/application/jdk1.6.0_10 | JAVA HOME环境变量 |
LANG=zh_CN.UTF-8 | 字符集 |
LOGNAME=root | 登录用户名称 |
MACHTYPE=x86_64-redhat-linux-gnu | 包含一个描述正在运行bash的系统串 |
MAILCHECK=60 | 这个参数定义shell将隔多长时间(以秒为单位)检查一次由参数MAILPATH或MAILFILE指定的文件,看看是否有邮件到达。默认值为600s |
MAIL=/var/spool/mail/root | 邮件全路径 |
OLDPWD=/root | 前一个当前工作目录 |
OPTIND=1 | 下一个由getopts内置命令处理的参数的序号 |
OSTYPE=Linux-gnu | 自动设置成一个串,该串描述正在运行bash的操作系统,默认值由系统来决定 |
PATH=/usr/lib64/qt-3.3/bin:/usr/kerberos/sbin:/usr/kerberos/bin :/usr/local/sbin:/usr/local/bin:/sbin:/bin: /usr/sbin:/usr/bin:/bin: /server/script/shangxian:/root/bin |
全局PATH路径,命令搜索路径。一个由冒号分隔的目录列表,shell用它来搜索命令。默认路径由系统来决定,并且由安装bash的管理员来设置 |
PIDESTATUS=([0]="0"[1]="0") | 一个数组,包含一列最近在管道执行的前台作业的进程退出的状态值 |
PPID=1112 | 父进程的进程ID |
PS1='[\u\@\h\W]\$' | 主提示符串,默认值是$ |
PS2='>' | 次提示符串,默认值是> |
PS4=`+` | 当开启追踪时使用的是调试提示符串,默认值是+,追踪可用set -x 开启 |
PWD=/home | 当前用户家目录 |
RESIN_HOME=/application/resin-3.1.6 | 这是通过export人为设置的环境变量,Java环境会用 |
SHELL=/bin/bash | 登录shell类型 |
SHELLOPTS=braceexpand:emacs:hashall: histexpand:history:interactive-comments:monitor |
包含一列开启的shell选项 |
SHLVL=1 | 每启动一个bash实例就将其加1 |
TERM=vt100 | 终端设置 |
TMOUT=3600 | 退出前等待超时的秒数 |
UID=0 | 当前用户的UID,在shell启动时初始化 |
USER=root | 当前用户的用户名,在shell启动时初始化 |
在查看设置的变量时,有3个命令可以显示变量的值:set、env和declare(替代早期的typeset)。set命令输出所有的变量,包
括全局变量和局部变量;env命令只显示全局变量;declare命令输出所有的变量、函数、整数和已经导出的变量。set -o命令显
示bash shell的所有参数配置信息。
例如:set、env和declare输出
[root@kang ~]# env | tail
SELINUX_LEVEL_REQUESTED=
HISTCONTROL=ignoredups
HOME=/root
SHLVL=2
LOGNAME=root
SSH_CONNECTION=192.168.186.1 64636 192.168.186.128 22
XDG_DATA_DIRS=/root/.local/share/flatpak/exports/share:/var/lib/flatpak/exports/share:/usr/local/share:/usr/share
LESSOPEN=||/usr/bin/lesspipe.sh %s
XDG_RUNTIME_DIR=/run/user/0
_=/usr/bin/env
[root@kang ~]#
效果:
[root@kang ~]# set -o | head
allexport off
braceexpand on
emacs on
errexit off
errtrace off
functrace off
hashall on
histexpand on
history on
ignoreeof off
[root@kang ~]#
效果:
[root@kang ~]# declare | head
ABRT_DEBUG_LOG=/dev/null
BASH=/usr/bin/bash
BASHOPTS=checkwinsize:cmdhist:expand_aliases:extglob:extquote:force_fignore:histappend:interactive_comments:progcomp:promptvars:sourcepath
BASH_ALIASES=()
BASH_ARGC=()
BASH_ARGV=()
BASH_CMDS=()
BASH_COMPLETION_COMPAT_DIR=/etc/bash_completion.d
BASH_LINENO=()
BASH_REMATCH=()
[root@kang ~]#
效果:
如果想要设置环境变量,就要在给变量赋值之后或在设置变量时使用export命令,其实除了export命令,带-x选项的declare内
置命令也可以完成同样的功能(注意:此处不要在变量名前加$)。
export命令和declare命令的格式如下:
export 变量名=value
变量名=value ; export 变量名
declare -x 变量名=value
提示:以上为设置环境变量的3种方法
定义环境变量并赋值的方法
[root@kang ~]# export NAME=blxh #<==export方法
[root@kang ~]# declare -x NAME=blxh #<==declare方法
[root@kang ~]# NAME=blxh ;export NAME #<==export导入方法
[root@kang ~]# echo $NAME
blxh
[root@kang ~]#
以下是自定义全局环境变量的示例:
[root@kang ~]# cat /etc/profile|grep BLX
export BLXH='BLXH' #<===编辑/etc/profile,然后输出此行并保存。
[root@kang ~]# source /etc/profile #<==或 . /etc/profile使其生效
[root@kang ~]# echo $BLXH #<===在变量前加$符号并打印变量值
BLXH
[root@kang ~]# env | grep BLXH #<===查看定义结果
BLXH=BLXH
[root@kang ~]#
效果:
下面来看看让环境永久生效的常用配置文件。
(1.)用户的环境变量配置
[root@kang ~]# ls /root/.bashrc #<===推荐在此文件中优先设置
/root/.bashrc
[root@kang ~]# ls /root/.bash_profile
/root/.bash_profile
[root@kang ~]#
效果:
提示:对于用户的环境变量设置,比较常见的是用户家目录下的.bashrc和.bash_profile。
(2.)全局环境变量的配置
常见的全局环境变量的配置文件如下:
/etc/pfrofile
/etc/bashrc #<==推荐在此文件中优先设置
/etc/profile.d
若要在登录后初始化或显示加载内容,则把脚本文件放在/etc/profile.d/下即可(无须加执行权限)
第一种是在/etc/motd里增加提示的字符串,如下:
[root@kang ~]# cat /etc/motd #<===文件里仅为字符串内容
welcome to blxh linux shell training.
[root@kang ~]#
登录后显示效果如下:
第二种是在/etc/profile.d/下增加如下脚本。
[root@kang ~]# cat /etc/profile.d/blxh.sh #<===这里是脚本的内容
echo " Here is blxh training "
[root@kang ~]#
登录后显示效果如下:
以下是在生产场景下(在Java环境中),自定义环境变量的示例:
export JAVA_HOME=/application/jdk
export CLASSPATH=$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib
export PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$PATH:$HOME/bin
export RESIN_HOME=/application/resin
提示:上述的环境变量设置通常放在/etc/profile全局环境变量里。
如果是写Java的脚本,那么最好是把上述Java环境配置放入脚本内重新定义,特别是作为定时任务执行的脚本。
下面我们先来看看常见的系统环境变量。
通过echo和printf命令打印环境变量。
[root@kang ~]# echo $HOME
/root
[root@kang ~]# echo $UID
0
[root@kang ~]# echo $PWD
/root
[root@kang ~]# echo $SHELL
/bin/bash
[root@kang ~]# echo $USER
root
[root@kang ~]# printf "$HOME\n" #<====printf是一个更复杂的格式化打印内容的工具,一般不需要。
/root
[root@kang ~]#
提示:在写shell脚本时可以直接使用系统默认的环境变量,一般情况下是不需要重新定义的,在使用定时任务等执行shell脚本时建议在脚本中重新定义。
用env(printenv)显示默认环境变量的示例如下:
用set也可以显示环境变量(包括局部变量),如下:
在上面还提到了一个相关的命令declare,大家还记得吗?
用unset取消本地变量和环境变量的示例如下:
[root@kang ~]# echo $USER
root
[root@kang ~]# unset USER
[root@kang ~]# echo $USER
#<===此处为输出的空行
[root@kang ~]#
效果:
根据上图可以看到变量的内容显示为空。
环境变量的知识小结:
在登录Linux系统并启动一个bash shell时,默认情况下bash会在若干个文件中查找环境变量的设置。这些文件可统称为系统环
境文件。bash检查的环境变量文件的情况取决于系统运行shell的方式。系统运行shell的方式一般有3种:
(1.)通过系统用户登录后默认运行的shell
(2.)非登录交互式运行shell
(3.)执行脚本运行非交互式shell
当用户登录Linux系统时,shell会作为登录shell启动。此时的登录shell加载环境变量的顺序如下图所示:
用户登录系统后首先会加载/etc/profile全局环境变量文件,这是Linux系统上默认的shell主环境变量文件。系统上每个用户登录
都会加载这个文件。
当加载完/etc/profile文件后,才会执行/etc/profile.d目录下的脚本文件,这个目录下的脚本文件有很多,例如:系统的字符集设
置(/etc/sysconfig/il8n)等,之后开始运行$HOME/.bash_profile(用户环境变量文件),在这个文件中,又会去找
$HOME/.bashrc文件中又会去找/etc/bashrc(全局环境变量文件),如果有,则执行,如果没有,则不执行。
如果用户的shell不是登录时启动的(比如手动敲下bash时启动或者其他不需要输入密码的登录及远程SSH连接情况),那么这
种非登录shell只会加载$HOME/.bashrc(用户环境变量文件),并会去找/etc/bashrc(全局环境变量文件)。因此如果希望在
非登录shell下也可读到设置的环境变量等内容,就需要将变量设定等写入$HOME/.bashrc或者/etc/bashrc,而不是
$HOME/.bash_profile或/etc/profile。
定义本地变量
本地变量在用户当前shell生存期的脚本中使用。例如:本地变量blxh的取值为bingbing,这个值只在用户当前shell生存期中有
意义。如果在shell中启动另一个进程或退出,那么变量blxh的值将会无效。
1.普通变量定义
为普通变量的定义赋值,一般有以下3种写法:
变量名=value #<==赋值时不加引号
变量名='value' #<==赋值时加单引号
变量名="value" #<==赋值时加双引号
2.在shell中定义变量名及为变量内容赋值的要求
变量名一般是由字母、数字、下划线组成的,可以以字母或下划线开头,例如:
blxh、blxh123、blxh_tarining
变量的内容可以用单引号或双引号括起来,也可以不加引号,但是这三者的含义是不同的。
3.普通变量的定义及输出的示例:
采用不同的方式对普通变量进行定义,并一一打印输出。
[root@kang ~]# a=192.168.1.2
[root@kang ~]# b='192.168.1.2'
[root@kang ~]# c="192.168.1.2"
效果:
提示:$变量名表示输出变量,可以用$c和${c}两种用法。
可见,将连续的普通字符串的内容赋值给变量,不管用不用引号,或者不管用什么引号,它的内容是什么,打印变量时就会输出
什么。
接着上述示例的结果,再在Linux命令行下继续输入如下内容:
[root@kang ~]# a=192.168.1.2-$a
[root@kang ~]# b='192.168.1.2-$a'
[root@kang ~]# c="192.168.1.2-$a"
效果:
4.变量定义的基本技巧总结
根据上述的示例进行一个剖析:
a=192.168.1.2-$a
第一种定义a变量的方式是不加任何引号直接定义变量的内容,当内容为简单连续的数字、字符串、路径名时,可以这样用,例
如:a=1,b=blxh等。不加引号时,值里有变量的会被解析后再输出,上述变量定义中因为$a的值被解析为192.168.1.2(受上述
示例执行的影响),因此新的a值就是192.168.1.2-192.168.1.2。
b='192.168.1.2-$a'
第二种定义b变量的方式是通过单引号定义。这种定义方式的特点是:输出变量内容时单引号里是什么就输出什么,即使内容中
有变量和命令(命令需要反引起来)也会把它们原样输出。这种方式比较适合于定义显示纯字符串的情况,即不希望解析变量、
命令等的场景,因此,对于这里的b的值,定义时看到的是什么就输出什么,即192.168.1.2-$a。
c="192.168.1.2-$a"
第三种定义c变量的方式是通过双引号定义变量。这种定义方式的特点是:输出变量内容时引号里的变量及命令会经过解析后再
输出内容,而不是把双引号中的变量名及命令(命令需要反引起来)原样输出。这种方式比较适合于字符串中附带有变量及命令
且想将其解析后再输出的变量定义。
提示:数字内容的变量定义可以不加引号,其他没有特别要求的字符串等定义最好都加上双引号,如果真的需要原样输出
就加单引号,定义变量加双引号是最常见的使用场景。
5.把一个命令的结果作为变量的内容赋值的方法
对需要获取命令结果的变量内容赋值的常见方法有两种:
变量名=`ls` #<==把命令用反引号引起来,不推荐使用这种方法,因为容易和单引号混淆
变量名=$(ls) #<==把命令用$()括起来,推荐使用这种方法
用两种方法把命令的结果赋值给变量
[root@kang ~]# ls
anaconda-ks.cfg blxh.sh mess.sh ss.sh testsource.sh
[root@kang ~]# CMD=`ls` #<==其中``为键盘上Tab键上面的那个键输出的字符
[root@kang ~]# echo $CMD
anaconda-ks.cfg blxh.sh mess.sh ss.sh testsource.sh
[root@kang ~]# CMD1=$(pwd)
[root@kang ~]# echo $CMD1
/root #<==打印当前用户所在的目录
[root@kang ~]#
提示:生产场景中把命令的结果作为变量的内容进行赋值的方法在脚本开发时很常见。
按天打包网站的站点目录程序,生成不同的文件名。
[root@kang ~]# CMD=$(date +%F) #<==将当前日期(格式为2019-04-07)赋值给CMD变量
[root@kang ~]# echo $CMD #<==输出变量的值
2019-04-07
[root@kang ~]# echo $(date +%F).tar.gz #<==直接输出时间命令的结果
2019-04-07.tar.gz
[root@kang ~]# echo `date +%F`.tar.gz
2019-04-07.tar.gz
[root@kang ~]# tar zcf etc_$(date +%F).tar.gz /etc #<===将时间作为压缩包名打包
tar: 从成员名中删除开头的“/”
[root@kang ~]# ls -l etc_2019-04-07.tar.gz #<==打包结果,包名中包含有当前日期
-rw-r--r--. 1 root root 11130361 4月 7 18:18 etc_2019-04-07.tar.gz
[root@kang ~]# H=$(uname -n) #<==获取主机名并赋值给H变量
[root@kang ~]# echo $H
kang
[root@kang ~]# tar zcf $H.tar.gz /etc/services #<==将主机名作为压缩包名打包文件
tar: 从成员名中删除开头的“/”
[root@kang ~]# ls -l kang.tar.gz #<==打包结果,包名中包含有主机名
-rw-r--r--. 1 root root 136214 4月 7 18:19 kang.tar.gz
[root@kang ~]#
效果:
局部(普通)变量定义及赋值的经验小结
常规普通变量定义:
若变量内容为连续的数字或字符串,赋值时,变量内容两边可以不加引号,例如a=123。
变量的内容很多时,如果有空格且希望解析内容中的变量,就加双引号,例如a="/ect/rc.local $USER",此时输出变量会对内容
中的$USER进行解析然后再输出。
希望原样输出变量中的内容时就用单引号引起内容进行赋值,例如:a='$USER'。
希望变量的内容是命令的解析结果的定义及赋值如下:
要使用反引号将赋值的命令括起来,例如:a=`ls`;或者用$()括起来,例如:a=$(ls)。
变量的输出方法如下:
使用“$变量名”即可输出变量的内容,常用“echo $变量名”的方式,也可用printf代替echo输出更复杂的格式内容。
变量定义的技巧及注意事项:
注意命令变量内前后的字符``(此字符为键盘Tab键上面的那个反引号,不是单引号),例如:"CMD=`ls`"。
在变量名前加$可以取得该变量的值,使用echo或printf命令可以显示变量的值,$A和${A}的写法不同,但效果是一样的。
用echo等命令输出变量的时候,也可用单引号、双引号、反引号,例如:echo $A、echo "$A"、echo '$A',它们的用法和前面
变量内容定义的总结是一致的。
$dbname_tname,当变量后面连接有其他字符的时候,必须给变量加上大括号{},例如:$dbname_tname就要改成
${dbname}_tname。
有关shell变量定义、赋值及变量输出加单引号、双引号、反引号与不加引号的简要说明如下表:
名称 | 解释 |
---|---|
单引号 | 所见即所得,即输出时会将单引号内的所有内容都原样输出,或者描述为单引号里面看到的是什么就会输出什么,这称为强引用。 |
双引号 (默认) |
输出双引号内的所有内容;如果内容中有命令(要反引下)、变量、特殊转义符等,会先把变量、命令、转义字符解析出结果,然后再输出最终内容,推荐使用,这称为弱引用。 |
无引号 | 赋值时,如果变量内容中有空格,则会造成赋值不完整。而在输出内容时,会将含有空格的字符串视为一个整体来输出;如果变量内容中有命令(要反引下)、变量等,则会先把变量、命令解析出结果,然后输出最终内容;如果字符串中带有空格等特殊字符,则有可能无法完整地输出,因此需要改加双引号。一般连续的字符串、数字、路径等可以不加任何引号进行赋值和输出,不过最好是用双引号替代无引号的情况,特别是对变量赋值时。 |
反引号 | ``一般用于引用命令,执行的时候命令会被执行,相当于$(),赋值和输出都要用``将命令引起来。 |
提示:这里仅为Linux shell下的结论,对于awk语言会有点特别。
薄凉小伙的建议:
在脚本中定义普通字符串变量时,应尽量把变量的内容用双引号括起来。
单纯数字的变量内容可以不加引号。
希望变量的内容原样输出时需要加单引号。
希望变量值引用命令并获取命令的结果时就用反引号或$()。
接下来是单引号、双引号与不加引号的实战演示:
对由反引号引起来的`date`命令或$(date)进行测试。
[root@kang ~]# echo 'today is date'
today is date #<==单引号引起内容时,你看到什么就会显示什么
[root@kang ~]# echo 'today is `date`'
today is `date` #<==单引号引起内容时,你看到什么就会显示什么,内容中有命令时即使通过反引号引起来也没用
[root@kang ~]# echo "today is date"
today is date
[root@kang ~]# echo "today is `date`" #<==对输出内容加双引号时,如果里面是变量或用反引号引起来的命令,则会先把变量或命令解析成具体内容再显示。
today is 2019年 04月 07日 星期日 21:38:14 CST
[root@kang ~]# echo "today is $(date)" #<==$()的功能和反引号``相同。
today is 2019年 04月 07日 星期日 21:38:47 CST
[root@kang ~]# echo today is $(date) #<==带空格的内容不加引号,同样可以正确地输出,但不建议这么做。
today is 2019年 04月 07日 星期日 21:39:08 CST
[root@kang ~]# #<==对于连续的字符串等内容输出一般可以不加引号,但加双引号比较保险,所以推荐使用。
效果:
变量定义后,在调用变量输出打印时加引号测试。
[root@kang ~]# BLXH=testchars #<==创建一个不带引号的变量并赋值
[root@kang ~]# echo $BLXH #<==不加引号,显示变量解析后的内容。
testchars
[root@kang ~]# echo '$BLXH' #<==加单引号,显示变量本身。
$BLXH
[root@kang ~]# echo "$BLXH" #<==加双引号,显示变量内容,引号内可以是变量、字符串等。
testchars
[root@kang ~]#
效果:
使用三剑客命令中的grep过滤字符串时给过滤的内容加引号。
[root@kang ~]# cat grep.log #<==待测试的内容
testchars
blxh
[root@kang ~]# grep "$BLXH" grep.log #<==将$BLXH解析为结果后进行过滤
testchars
[root@kang ~]# grep '$BLXH' grep.log #<==将$BLXH本身作为结果进行过滤
[root@kang ~]# grep $BLXH grep.log #<==将$BLXH解析为结果后进行过滤,同双引号的情况,但不建议这样使用,没有特殊需要时应一律加双引号。
testchars
[root@kang ~]#
效果:
使用awk调用shell中的变量,分别针对加引号、不加引号等情况进行测试。
首先在给shell中的变量赋值时不加任何引号,这里使用awk输出测试结果。
[root@kang ~]# ETT=123 #<==定义变量ETT并赋值123,没加引号。
[root@kang ~]# awk 'BEGIN {print "$ETT"}' #<==加双引号引用$ETT,却只输出了本身,这个就不符合前面的结论了。
$ETT
[root@kang ~]# awk 'BEGIN {print $ETT}' #<==不加引号的$ETT,又输出了空的结果,这个就不符合前面的结论了。
[root@kang ~]# awk 'BEGIN {print '$ETT'}' #<==加单引号引用$ETT,又输出了解析后的结果,这个就不符合前面的结论了。
123
[root@kang ~]# awk 'BEGIN {print "'$ETT'"}'
123
[root@kang ~]#
以上的结果正好与前面的结论相反,这是awk调用shell变量的特殊用法。
然后在给shell中的变量赋值时加单引号,同样使用awk输出测试结果。
[root@kang ~]# ETT='oldgirl' #<==定义变量ETT并赋值oldgirl,加单引号。
[root@kang ~]# awk 'BEGIN {print "$ETT"}' #<==加双引号引用$ETT,则输出本身。
$ETT
[root@kang ~]# awk 'BEGIN {print $ETT}' #<==对$ETT不加引号,则输出空的结果。
[root@kang ~]# awk 'BEGIN {print '$ETT'}' #<==加单引号引用$ETT,也是输出空的结果,这个和前面的不加引号定义、赋值的结果又不一样。
[root@kang ~]# awk 'BEGIN {print "'$ETT'"}' #<==在单引号外再加一层双引号引用$ETT,则输出解析后的结果
oldgirl
[root@kang ~]#
以下在给shell中的变量赋值时加双引号,也使用awk输出测试结果。
[root@kang ~]# ETT="tingting" #<==定义变量ETT并赋值tingting,加双引号,这个测试结果同单引号的情况。
[root@kang ~]# awk 'BEGIN {print "$ETT"}' #<==加双引号引用$ETT,会输出本身。
$ETT
[root@kang ~]# awk 'BEGIN {print $ETT}' #<==不加引号的$ETT,会输出空的结果。
[root@kang ~]# awk 'BEGIN {print '$ETT'}' #<==加单引号的$ETT,会输出空的结果。
[root@kang ~]# awk 'BEGIN {print "'$ETT'"}' #<==在单引号外部再加双引号引用$ETT,会输出正确结果。
tingting
[root@kang ~]#
以下在给shell中的变量赋值时加反引号引用命令,同样使用awk输出测试结果。
[root@kang ~]# ETT=`pwd` #<==定义变量ETT并赋值pwd命令,加反引号,这个测试结果更特殊。
[root@kang ~]# echo $ETT
/root
[root@kang ~]# awk 'BEGIN {print "$ETT"}' #<==加双引号引用$ETT,会输出本身。
$ETT
[root@kang ~]# awk 'BEGIN {print $ETT}' #<==不加引号引用$ETT,会输出空的结果。
[root@kang ~]# awk 'BEGIN {print '$ETT'}' #<==单引号引用$ETT,看起来输出了结果,却是报错,和外层单引号冲突了。
awk: cmd. line:1: BEGIN {print /root}
awk: cmd. line:1: ^ unterminated regexp
awk: cmd. line:1: BEGIN {print /root}
awk: cmd. line:1: ^ unexpected newline or end of string
[root@kang ~]# awk 'BEGIN {print "'$ETT'"}' #<==在单引号外部再加双引号引用$ETT,会输出正确结果。
/root
[root@kang ~]#
根据上述示例整理的测试结果如下表:
awk/ETT | ETT=123 | ETT='oldgirl' | ETT="tingting" | ETT=`pwd` |
---|---|---|---|---|
awk加双引号 |
本身 | 本身 | 本身 | 本身 |
awk不加引号 | 空 | 空 | 空 | 空 |
awk加单引号 | 正确输出 | 空 | 空 | 报语法错 |
awk加单引号后再同时加双引号 | 正确输出 | 正确输出 | 正确输出 | 正确输出 |
结论:
不管变量如何定义、赋值,除了加单引号以外,利用awk直接获取变量的输出,结果都是一样的,因此,在awk取用shell变量
时,我们更多地还是喜欢先用echo加符号输出变量,然后通过管道给awk,进而控制变量的输出结果。
举例如下:
[root@kang ~]# ETT="oldgirl" #<==最常规的赋值语法
[root@kang ~]# echo "$ETT" | awk '{print $0}' #<==用双引号引用$ETT
oldgirl
[root@kang ~]# echo '$ETT' | awk '{print $0}' #<==用单引号引用$ETT
$ETT
[root@kang ~]# echo $ETT | awk '{print $0}' #<==不加引号引用$ETT
oldgirl
[root@kang ~]# ETT=`pwd` #<==命令赋值的语法
[root@kang ~]# echo "$ETT" | awk '{print $0}'
/root
[root@kang ~]# echo '$ETT' | awk '{print $0}'
$ETT
[root@kang ~]# echo $ETT | awk '{print $0}'
/root
[root@kang ~]#
这就符合前面给出的普通情况的结论了。
通过sed指定变量关键字过滤。
[root@kang ~]# cat sed.log
testchars
blxh
[root@kang ~]# sed -n /"$BLXH"/p sed.log #<==加双引号测试
testchars
[root@kang ~]# sed -n /$BLXH/p sed.log #<==不加引号测试
testchars
[root@kang ~]# sed -n /'$BLXH'/p sed.log #<==加单引号测试
[root@kang ~]# #<==输出本身,但是文件里没有本身匹配的字符串,因此输出为空。
注意:sed和grep的测试和前面的结论是相符的,唯有awk有些特殊。
关于自定义普通字符串变量的建议
(1.)内容是纯数字、简单的连续字符(内容中不带任何空格)时,定义时可以不加任何引号,例如:
a.BlxhAge=24
b.NETWORKING=yes
(2.)没有特殊情况时,字符串一律用双引号定义赋值,特别是多个字符串中间有空格时,例如:
a.NFSD_MODULE="no load"
b.MyName="Blxh is a handsome boy."
(3.)当变量里的内容需要原样输出时,要用单引号(' '),这样的需求极少,例如:
a.BLXH_NAME='BLXH'
可以多学习和模仿操作系统自带的/etc/init.d/functions函数库脚本的定义思路,多学习Linux系统脚本的定义,有经验的读者最
终应形成一套适合自己的规范和习惯。
(1.)变量名及变量内容定义小结
示例:
BlxhAge=1 #<==每个单词的首字母大写的写法
blxh_age=1 #<==单词之间用"_"的写法
blxhAgeSex=1 #<==驼峰语法:首个单词的首字母小写,其余单词首字母大写
BLXHAGE=1 #<==单词全大写的写法
一般的变量定义、赋值常用双引号;简单连续的字符串可以不加引号;希望原样输出时使用单引号。
希望变量的内容是命令的解析结果时,要用反引号``,或者用$()把命令括起来再赋值。
(2.)Shell定义变量时使用“=”的知识
“a=1”里等号是赋值的意思;比较变量是否相等时也可以用“=”或“==”。
(3.)打印输出及使用变量的知识
打印输出或使用变量时,变量名前要接$符号;变量名后面紧接其他字符的时候,要用大括号将变量部分单独括起来;在unset、export、(())等场景中使用但不打印变量时不加$,这个有些例外。
打印输出或使用变量时,一般加双引号或不加引号;如果是字符串变量,最后加双引号;希望原样输出时使用单引号。
好了今天就先到这里吧,看不懂的可以反复多看几遍,基本都是一些比较基础的知识点,这一篇博文主要是讲解了什么是变量、
变量有什么用、变量的类型有哪些、使用了变量会给运维人员带来哪些方便,再次真心希望对你有所帮助!!!
谢谢关注!!!再见!!!