什么是变量?
让某一个特定字符串代表不固定的内容
- 变量的可变性与方便性
![程序、变量与不同用户的关系 程序、变量与不同用户的关系](http://vbird.dic.ksu.edu.tw/linux_basic/0320bash_files/var_01.gif)
图 2.1.1、程序、变量与不同用户的关系
如上图所示,由于系统已经帮我们规划好 MAIL 这个变量,所以用户只要知道 mail 这个命令如何使用即可, mail 会主动的取用 MAIL 这个变量,就能够如上图所示的取得自己的邮件信箱了!(注意大小写,小写的 mail 是命令, 大写的 MAIL 则是变量名称!)
- 影响 bash 环境操作的变量
环境变量通常以大写字符来表示!
- 脚本程序设计 (shell script) 的好帮手
![变量应用于 shell script 的示意图 变量应用于 shell script 的示意图](http://vbird.dic.ksu.edu.tw/linux_basic/0320bash_files/var_02.gif)
图 2.1.2、变量应用于 shell script 的示意图
变量就是以一组文字或符号等,来取代一些配置或者是一串保留的数据!
- 变量的取用: echo
[root@www ~]# echo $variable [root@www ~]# echo $PATH /usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin [root@www ~]# echo ${PATH} |
例题:
请在屏幕上面显示出您的环境变量 HOME 与 MAIL:
答:
echo $HOME 或者是 echo ${HOME} echo $MAIL 或者是 echo ${MAIL} |
[root@www ~]# echo $myname <==这里并没有任何数据~因为这个变量尚未被配置!是空的! [root@www ~]# myname=VBird [root@www ~]# echo $myname VBird <==出现了!因为这个变量已经被配置了! |
在 bash 当中,当一个变量名称尚未被配置时,默认的内容是『空』的。
- 变量的配置守则
- 变量与变量内容以一个等号『=』来连结,如下所示:
『myname=VBird』
- 等号两边不能直接接空格符,如下所示为错误:
『myname = VBird』或『myname=VBird Tsai』
- 变量名称只能是英文字母与数字,但是开头字符不能是数字,如下为错误:
『2myname=VBird』
- 变量内容若有空格符可使用双引号『"』或单引号『'』将变量内容结合起来,但
- 双引号内的特殊字符如 $ 等,可以保有原本的特性,如下所示:
『var="lang is $LANG"』则『echo $var』可得『lang is en_US』 - 单引号内的特殊字符则仅为一般字符 (纯文本),如下所示:
『var='lang is $LANG'』则『echo $var』可得『lang is $LANG』
- 双引号内的特殊字符如 $ 等,可以保有原本的特性,如下所示:
- 可用跳脱字符『 \ 』将特殊符号(如 [Enter], $, \, 空格符, '等)变成一般字符;
- 在一串命令中,还需要藉由其他的命令提供的信息,可以使用反单引号『`命令`』或 『$(命令)』。特别注意,那个 ` 是键盘上方的数字键 1 左边那个按键,而不是单引号! 例如想要取得核心版本的配置:
『version=$(uname -r)』再『echo $version』可得『2.6.18-128.el5』
- 若该变量为扩增变量内容时,则可用 "$变量名称" 或 ${变量} 累加内容,如下所示:
『PATH="$PATH":/home/bin』
- 若该变量需要在其他子程序运行,则需要以 export 来使变量变成环境变量:
『export PATH』
- 通常大写字符为系统默认变量,自行配置变量可以使用小写字符,方便判断 (纯粹依照使用者兴趣与嗜好) ;
- 取消变量的方法为使用 unset :『unset 变量名称』例如取消 myname 的配置:
『unset myname』
范例一:配置一变量 name ,且内容为 VBird [root@www ~]# 12name=VBird -bash: 12name=VBird: command not found <==屏幕会显示错误!因为不能以数字开头! [root@www ~]# name = VBird <==还是错误!因为有空白! [root@www ~]# name=VBird <==OK! 范例二:承上题,若变量内容为 VBird's name ,就是变量内容含有特殊符号时: [root@www ~]# name=VBird's name # 单引号与双引号必须要成对,在上面的配置中仅有一个单引号,因此当你按下 enter 后, # 你还可以继续输入变量内容。这与我们所需要的功能不同,失败! # 记得,失败后要复原请按下 [ctrl]-c 结束! [root@www ~]# name="VBird's name" <==OK! # 命令是由左边向右找→,先遇到的引号先有用,因此如上所示,单引号会失效! [root@www ~]# name='VBird's name' <==失败! # 因为前两个单引号已成对,后面就多了一个不成对的单引号了!因此也就失败了! [root@www ~]# name=VBird\'s\ name <==OK 的啦! # 利用反斜杠 (\) 跳脱特殊字符,例如单引号与空格键,这也是 OK 的啦! 范例三:我要在 PATH 这个变量当中『累加』:/home/dmtsai/bin 这个目录 [root@www ~]# PATH=$PATH:/home/dmtsai/bin [root@www ~]# PATH="$PATH":/home/dmtsai/bin [root@www ~]# PATH=${PATH}:/home/dmtsai/bin # 上面这三种格式在 PATH 里头的配置都是 OK 的!但是底下的例子就不见得! 范例四:承范例三,我要将 name 的内容多出 "yes" 呢? [root@www ~]# name=$nameyes # 知道了吧?如果没有双引号,那么变量成了啥?name 的内容是 $nameyes 这个变量! # 我们可没有配置过 nameyes 这个变量!所以,应该是底下这样才对! [root@www ~]# name="$name"yes [root@www ~]# name=${name}yes <==以此例较佳! 范例五:如何让我刚刚配置的 name=VBird 可以用在下个 shell 的程序? [root@www ~]# name=VBird [root@www ~]# bash <==进入到所谓的子程序 [root@www ~]# echo $name <==子程序:再次的 echo 一下; <==并没有刚刚配置的内容! [root@www ~]# exit <==子程序:离开这个子程序 [root@www ~]# export name [root@www ~]# bash <==进入到所谓的子程序 [root@www ~]# echo $name <==子程序:在此运行! VBird <==出现配置值了! [root@www ~]# exit <==子程序:离开这个子程序 |
范例六:如何进入到您目前核心的模块目录? [root@www ~]# cd /lib/modules/`uname -r`/kernel [root@www ~]# cd /lib/modules/$(uname -r)/kernel |
- 先进行反单引号内的动作『uname -r』并得到核心版本为 2.6.18-128.el5
- 将上述的结果带入原命令,故得命令为:『cd /lib/modules/2.6.18-128.el5/kernel/』
范例七:取消刚刚配置的 name 这个变量内容 [root@www ~]# unset name |
例题:
在变量的配置当中,单引号与双引号的用途有何不同?
答:
单引号与双引号的最大不同在于
双引号仍然可以保有变量的内容,但单引号内仅能是一般字符 ,而不会有特殊符号。我们以底下的例子做说明:假设您定义了一个变量, name=VBird ,现在想以 name 这个变量的内容定义出 myname 显示 VBird its me 这个内容,要如何订定呢?
[root@www ~]# name=VBird |
例题:
在命令下达的过程中,反单引号( ` )这个符号代表的意义为何?
答:
在一串命令中,在 ` 之内的命令将会被先运行,而其运行出来的结果将做为外部的输入信息!例如 uname -r 会显示出目前的核心版本,而我们的核心版本在 /lib/modules 里面,因此,你可以先运行 uname -r 找出核心版本,然后再以『 cd 目录』到该目录下。
另外再举个例子,我们也知道, locate 命令可以列出所有的相关文件档名,但是,如果我想要知道各个文件的权限呢?举例来说,我想要知道每个 crontab 相关档名的权限: [root@www ~]# ls -l `locate crontab`如此一来,先以 locate 将文件名数据都列出来,再以 ls 命令来处理的意思啦!瞭了吗? ^_^ |
例题:
若你有一个常去的工作目录名称为:『/cluster/server/work/taiwan_2005/003/』,如何进行该目录的简化?
答:
在一般的情况下,如果你想要进入上述的目录得要『cd /cluster/server/work/taiwan_2005/003/』, 以鸟哥自己的案例来说,鸟哥跑数值模式常常会配置很长的目录名称(避免忘记),但如此一来变换目录就很麻烦。 此时,鸟哥习惯利用底下的方式来降低命令下达错误的问题:
[root@www ~]# work="/cluster/server/work/taiwan_2005/003/"未来我想要使用其他目录作为我的模式工作目录时,只要变更 work 这个变量即可!而这个变量又可以在 bash 的配置文件中直接指定,那我每次登陆只要运行『 cd $work 』就能够去到数值模式仿真的工作目录了! |
Tips: 老实说,使用『 version=$(uname -r) 』来取代『 version=`uname -r` 』比较好,因为反单引号大家老是容易打错或看错! |
环境变量的功能
- 用 env 观察环境变量与常见环境变量说明
范例一:列出目前的 shell 环境下的所有环境变量与其内容。 [root@www ~]# env HOSTNAME=www.vbird.tsai <== 这部主机的主机名 TERM=xterm <== 这个终端机使用的环境是什么类型 SHELL=/bin/bash <== 目前这个环境下,使用的 Shell 是哪一个程序? HISTSIZE=1000 <== 『记录命令的笔数』在 CentOS 默认可记录 1000 笔 USER=root <== 使用者的名称啊! LS_COLORS=no=00:fi=00:di=00;34:ln=00;36:pi=40;33:so=00;35:bd=40;33;01:cd=40;33;01: or=01;05;37;41:mi=01;05;37;41:ex=00;32:*.cmd=00;32:*.exe=00;32:*.com=00;32:*.btm=0 0;32:*.bat=00;32:*.sh=00;32:*.csh=00;32:*.tar=00;31:*.tgz=00;31:*.arj=00;31:*.taz= 00;31:*.lzh=00;31:*.zip=00;31:*.z=00;31:*.Z=00;31:*.gz=00;31:*.bz2=00;31:*.bz=00;3 1:*.tz=00;31:*.rpm=00;31:*.cpio=00;31:*.jpg=00;35:*.gif=00;35:*.bmp=00;35:*.xbm=00 ;35:*.xpm=00;35:*.png=00;35:*.tif=00;35: <== 一些颜色显示 MAIL=/var/spool/mail/root <== 这个用户所取用的 mailbox 位置 PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/X11R6/bin:/usr/local/bin:/usr/local/sbin: /root/bin <== 是运行文件命令搜寻路径 INPUTRC=/etc/inputrc <== 与键盘按键功能有关。可以配置特殊按键! PWD=/root <== 目前用户所在的工作目录 (利用 pwd 取出!) LANG=en_US HOME=/root <== 这个用户的家目录! _=/bin/env <== 上一次使用的命令的最后一个参数(或命令本身) |
env 是 environment (环境) 的简写
- HOME
代表用户的家目录。
- SHELL
- HISTSIZE
- MAIL
当我们使用 mail 这个命令在收信时,系统会去读取的邮件信箱文件 (mailbox)。
- PATH
就是运行文件搜寻的路径
- LANG
- RANDOM
『随机数』的变量!目前大多数的 distributions 都会有随机数生成器,那就是 /dev/random 这个文件。 我们可以透过这个随机数文件相关的变量 ($RANDOM) 来随机取得随机数值。在 BASH 的环境下,这个 RANDOM 变量的内容,介于 0~32767 之间,所以,你只要 echo $RANDOM 时,系统就会主动的随机取出一个介于 0~32767 的数值。
[root@www ~]# declare -i number=$RANDOM*10/32768 ; echo $number 8 <== 此时会随机取出 0~9 之间的数值喔!
- 用 set 观察所有变量 (含环境变量与自定义变量)
bash 可不只有环境变量喔,还有一些与 bash 操作接口有关的变量,以及用户自己定义的变量存在的。 那么这些变量如何观察?这个时候就得要使用 set 这个命令了。 set 除了环境变量之外, 还会将其他在 bash 内的变量通通显示出来!
[root@www ~]# set BASH=/bin/bash <== bash 的主程序放置路径 BASH_VERSINFO=([0]="3" [1]="2" [2]="25" [3]="1" [4]="release" [5]="i686-redhat-linux-gnu") <== bash 的版本! BASH_VERSION='3.2.25(1)-release' <== 也是 bash 的版本! COLORS=/etc/DIR_COLORS.xterm <== 使用的颜色纪录文件 COLUMNS=115 <== 在目前的终端机环境下,使用的字段有几个字符长度 HISTFILE=/root/.bash_history <== 历史命令记录的放置文件,隐藏档 HISTFILESIZE=1000 <== 存起来(与上个变量有关)的文件之命令的最大纪录笔数。 HISTSIZE=1000 <== 目前环境下,可记录的历史命令最大笔数。 HOSTTYPE=i686 <== 主机安装的软件主要类型。我们用的是 i686 兼容机器软件 IFS=$' \t\n' <== 默认的分隔符 LINES=35 <== 目前的终端机下的最大行数 MACHTYPE=i686-redhat-linux-gnu <== 安装的机器类型 MAILCHECK=60 <== 与邮件有关。每 60 秒去扫瞄一次信箱有无新信! OLDPWD=/home <== 上个工作目录。我们可以用 cd - 来取用这个变量。 OSTYPE=linux-gnu <== 操作系统的类型! PPID=20025 <== 父程序的 PID PS1='[\u@\h \W]\$ ' <== PS1 就厉害了。这个是命令提示字符,也就是我们常见的 [root@www ~]# 或 [dmtsai ~]$ 的配置值!可以更动的! PS2='> ' <== 如果你使用跳脱符号 (\) 第二行以后的提示字符也 name=VBird <== 刚刚配置的自定义变量也可以被列出来! $ <== 目前这个 shell 所使用的 PID ? <== 刚刚运行完命令的回传值。 |
『基本上,在 Linux 默认的情况中,使用{大写的字母}来配置的变量一般为系统内定需要的变量』。
- PS1:(提示字符的配置)
- \d :可显示出『星期 月 日』的日期格式,如:"Mon Feb 2"
- \H :完整的主机名。举例来说,鸟哥的练习机为『www.vbird.tsai』
- \h :仅取主机名在第一个小数点之前的名字,如鸟哥主机则为『www』后面省略
- \t :显示时间,为 24 小时格式的『HH:MM:SS』
- \T :显示时间,为 12 小时格式的『HH:MM:SS』
- \A :显示时间,为 24 小时格式的『HH:MM』
- \@ :显示时间,为 12 小时格式的『am/pm』样式
- \u :目前使用者的账号名称,如『root』;
- \v :BASH 的版本信息,如鸟哥的测试主板本为 3.2.25(1),仅取『3.2』显示
- \w :完整的工作目录名称,由根目录写起的目录名称。但家目录会以 ~ 取代;
- \W :利用 basename 函数取得工作目录名称,所以仅会列出最后一个目录名。
- \# :下达的第几个命令。
- \$ :提示字符,如果是 root 时,提示字符为 # ,否则就是 $ 啰~
CentOS 默认的 PS1 内容:『[\u@\h \W]\$ 』, 要注意!那个反斜杠后的数据为 PS1 的特殊功能,与 bash 的变量配置没关系![root@www /home/dmtsai 16:50 #12]#
那个 # 代表第 12 次下达的命令。那么应该如何配置 PS1 呢?可以这样啊:
[root@www ~ ]# cd /home [root@www home]# PS1='[\u@\h \w \A #\#]\$ ' [root@www /home 17:02 #85]# # 看到了吗?提示字符变了!变的很有趣吧!其中,那个 #85 比较有趣, # 如果您再随便输入几次 ls 后,该数字就会添加喔!为啥?上面有说明滴!
- $:(关于本 shell 的 PID)
这个咚咚代表的是『目前这个 Shell 的线程代号』,亦即是所谓的 PID (Process ID)。 shell 的 PID ,就可以用:『 echo $$ 』即可!出现的数字就是你的 PID 号码。
- ?:(关于上个运行命令的回传值)
[root@www ~]# echo $SHELL /bin/bash <==可顺利显示!没有错误! [root@www ~]# echo $? 0 <==因为没问题,所以回传值为 0 [root@www ~]# 12name=VBird -bash: 12name=VBird: command not found <==发生错误了!bash回报有问题 [root@www ~]# echo $? 127 <==因为有问题,回传错误代码(非为0) # 错误代码回传值依据软件而有不同,我们可以利用这个代码来搜寻错误的原因! [root@www ~]# echo $? 0 # 咦!怎么又变成正确了?这是因为 "?" 只与『上一个运行命令』有关, # 所以,我们上一个命令是运行『 echo $? 』,当然没有错误,所以是 0 没错!
- OSTYPE, HOSTTYPE, MACHTYPE:(主机硬件与核心的等级)
目前个人计算机的 CPU 主要分为 32/64 位,其中 32 位又可分为 i386, i586, i686,而 64 位则称为 x86_64。 由于不同等级的 CPU 命令集不太相同,因此你的软件可能会针对某些 CPU 进行优化,以求取较佳的软件性能。 所以软件就有 i386, i686 及 x86_64 之分。以目前 (2009) 的主流硬件来说,几乎都是 x86_64 的天下! 可以在 x86_64 的硬件上安装 i386 的 Linux 操作系统,但是你无法在 i686 的硬件上安装 x86_64 的 Linux 操作系统!这点得要牢记在心!
- export: 自定义变量转成环境变量
该变量是否会被子程序所继续引用
当你登陆 Linux 并取得一个 bash 之后,你的 bash 就是一个独立的程序。 接下来你在这个 bash 底下所下达的任何命令都是由这个 bash 所衍生出来的,那些被下达的命令就被称为子程序了。 我们可以用底下的图示来简单的说明一下父程序与子程序的概念:
![程序相关性示意图 程序相关性示意图](http://vbird.dic.ksu.edu.tw/linux_basic/0320bash_files/ppid.gif)
图 2.3.1、程序相关性示意图
如上所示,我们在原本的 bash 底下运行另一个 bash ,结果操作的环境接口会跑到第二个 bash 去(就是子程序), 那原本的 bash 就会在暂停的情况 。
因为子程序仅会继承父程序的环境变量, 子程序不会继承父程序的自定义变量!所以你在原本 bash 的自定义变量在进入了子程序后就会消失不见, 一直到你离开子程序并回到原本的父程序后,这个变量才会又出现!
如果我能将自定义变量变成环境变量的话,那不就可以让该变量值继续存在于子程序了? 没错!如你想要让该变量内容继续的在子程序中使用,那么就请运行:
[root@www ~]# export 变量名称
|
[root@www ~]# export declare -x HISTSIZE="1000" declare -x HOME="/root" declare -x HOSTNAME="www.vbird.tsai" declare -x INPUTRC="/etc/inputrc" declare -x LANG="en_US" declare -x LOGNAME="root" # 后面的鸟哥就都直接省略了! |
影响显示结果的语系变量 (locale)
[root@www ~]# locale -a ....(前面省略).... zh_TW zh_TW.big5 <==大五码的中文编码 zh_TW.euctw zh_TW.utf8 <==万国码的中文编码 zu_ZA zu_ZA.iso88591 zu_ZA.utf8 |
[root@www ~]# locale <==后面不加任何选项与参数即可! LANG=en_US <==主语言的环境 LC_CTYPE="en_US" <==字符(文字)辨识的编码 LC_NUMERIC="en_US" <==数字系统的显示信息 LC_TIME="en_US" <==时间系统的显示数据 LC_COLLATE="en_US" <==字符串的比较与排序等 LC_MONETARY="en_US" <==币值格式的显示等 LC_MESSAGES="en_US" <==信息显示的内容,如菜单、错误信息等 LC_ALL= <==整体语系的环境 ....(后面省略).... |
基本上,你可以逐一配置每个与语系有关的变量数据,但事实上,如果其他的语系变量都未配置, 且你有配置 LANG 或者是 LC_ALL 时,则其他的语系变量就会被这两个变量所取代! 这也是为什么我们在 Linux 当中,通常说明仅配置 LANG 这个变量而已,因为他是最主要的配置变量! 好了,那么你应该要觉得奇怪的是,为什么在 Linux 主机的终端机接口 (tty1 ~ tty6) 的环境下,如果『 LANG=zh_TW.big5 』这个配置值生效后,使用 man 或者其他信息输出时, 都会有一堆乱码,尤其是使用 ls -l 这个参数时?
因为在 Linux 主机的终端机接口环境下是无法显示像中文这么复杂的编码文字, 所以就会产生乱码了。也就是如此,我们才会必须要在 tty1 ~ tty6 的环境下, 加装一些中文化接口的软件,才能够看到中文啊!不过,如果你是在 MS Windows 主机以远程联机服务器的软件联机到主机的话,那么,嘿嘿!其实文字接口确实是可以看到中文的。 此时反而你得要在 LANG 配置中文编码才好呢!
Tips: 无论如何,如果发生一些乱码的问题,那么配置系统里面保有的语系编码, 例如: en_US 或 en_US.utf8 等等 语系文件都放置在: /usr/lib/locale/ 这个目录中。 |
整体系统默认的语系定义在哪里呢? 其实就是在 /etc/sysconfig/i18n 啰!这个文件在 CentOS 5.x 的内容有点像这样:
[root@www ~]# cat /etc/sysconfig/i18n
LANG="zh_TW.UTF-8"
|
变量的有效范围
在跑程序的时候,有父程序与子程序的不同程序关系时, 则『变量』可否被引用与 export 有关。被 export 后的变量,我们可以称他为『环境变量』! 环境变量可以被子程序所引用,但是其他的自定义变量内容就不会存在于子程序中。
Tips: 在某些不同的书籍会谈到『全局变量, global variable』与『局部变量, local variable』。 基本上你可以这样看待: 环境变量=全局变量 自定义变量=局部变量 |
为什么环境变量的数据可以被子程序所引用呢?这是因为内存配置的关系!理论上是这样的:
- 当启动一个 shell,操作系统会分配一记忆区块给 shell 使用,此内存内之变量可让子程序取用
- 若在父程序利用 export 功能,可以让自定义变量的内容写到上述的记忆区块当中(环境变量);
- 当加载另一个 shell 时 (亦即启动子程序,而离开原本的父程序了),子 shell 可以将父 shell 的环境变量所在的记忆区块导入自己的环境变量区块当中。
透过这样的关系,我们就可以让某些变量在相关的程序之间存在,以帮助自己更方便的操作环境! 不过要提醒的是,这个『环境变量』与『bash 的操作环境』意思不太一样,举例来说, PS1 并不是环境变量, 但是这个 PS1 会影响到 bash 的接口 (提示字符)!
变量键盘读取、数组与宣告: read, array, declare
- read
[root@www ~]# read [-pt] variable 选项与参数: -p :后面可以接提示字符! -t :后面可以接等待的『秒数!』! 范例一:让用户由键盘输入一内容,将该内容变成名为 atest 的变量 [root@www ~]# read atest This is a test <==此时光标会等待你输入!请输入左侧文字看看 [root@www ~]# echo $atest This is a test <==你刚刚输入的数据已经变成一个变量内容! 范例二:提示使用者 30 秒内输入自己的大名,将该输入字符串作为名为 named 的变量内容 [root@www ~]# read -p "Please keyin your name: " -t 30 named Please keyin your name: VBird Tsai <==注意看,会有提示字符! [root@www ~]# echo $named VBird Tsai <==输入的数据又变成一个变量的内容了! |
- declare / typeset
『宣告变量的类型』。如果使用 declare 后面并没有接任何参数,那么 bash 就会主动的将所有的变量名称与内容通通叫出来,就好像使用 set 一样!
[root@www ~]# declare [-aixr] variable 选项与参数: -a :将后面名为 variable 的变量定义成为数组 (array) 类型 -i :将后面名为 variable 的变量定义成为整数数字 (integer) 类型 -x :用法与 export 一样,就是将后面的 variable 变成环境变量; -r :将变量配置成为 readonly 类型,该变量不可被更改内容,也不能 unset 范例一:让变量 sum 进行 100+300+50 的加总结果 [root@www ~]# sum=100+300+50 [root@www ~]# echo $sum 100+300+50 <==因为这是文字型态的变量属性! [root@www ~]# declare -i sum=100+300+50 [root@www ~]# echo $sum 450 |
由于在默认的情况底下, bash 对于变量有几个基本的定义:
- 变量类型默认为『字符串』,所以若不指定变量类型,则 1+2 为一个『字符串』而不是『计算式』。
- bash 环境中的数值运算,默认最多仅能到达整数形态,所以 1/3 结果是 0;
如果需要非字符串类型的变量,那就得要进行变量的宣告!
范例二:将 sum 变成环境变量 [root@www ~]# declare -x sum [root@www ~]# export | grep sum declare -ix sum="450" <==果然出现了!包括有 i 与 x 的宣告! 范例三:让 sum 变成只读属性,不可更动! [root@www ~]# declare -r sum [root@www ~]# sum=tesgting -bash: sum: readonly variable <==老天爷~不能改这个变量了! 范例四:让 sum 变成非环境变量的自定义变量! [root@www ~]# declare +x sum <== 将 - 变成 + 可以进行『取消』动作 [root@www ~]# declare -p sum <== -p 可以单独列出变量的类型 declare -ir sum="450" <== 只剩下 i, r 的类型,不具有 x啰! |
如果你不小心将变量配置为『只读』,通常得要注销再登陆才能复原该变量的类型了!
- 数组 (array) 变量类型
var[index]=content
范例:配置上面提到的 var[1] ~ var[3] 的变量。 [root@www ~]# var[1]="small min" [root@www ~]# var[2]="big min" [root@www ~]# var[3]="nice min" [root@www ~]# echo "${var[1]}, ${var[2]}, ${var[3]}" small min, big min, nice min |
与文件系统及程序的限制关系: ulimit
bash 是可以『限制用户的某些系统资源』的,包括可以开启的文件数量, 可以使用的 CPU 时间,可以使用的内存总量等等。
[root@www ~]# ulimit [-SHacdfltu] [配额] 选项与参数: -H :hard limit ,严格的配置,必定不能超过这个配置的数值; -S :soft limit ,警告的配置,可以超过这个配置值,但是若超过则有警告信息。 在配置上,通常 soft 会比 hard 小,举例来说,soft 可配置为 80 而 hard 配置为 100,那么你可以使用到 90 (因为没有超过 100),但介于 80~100 之间时, 系统会有警告信息通知你! -a :后面不接任何选项与参数,可列出所有的限制额度; -c :当某些程序发生错误时,系统可能会将该程序在内存中的信息写成文件(除错用), 这种文件就被称为核心文件(core file)。此为限制每个核心文件的最大容量。 -f :此 shell 可以创建的最大文件容量(一般可能配置为 2GB)单位为 Kbytes -d :程序可使用的最大断裂内存(segment)容量; -l :可用于锁定 (lock) 的内存量 -t :可使用的最大 CPU 时间 (单位为秒) -u :单一用户可以使用的最大程序(process)数量。 范例一:列出你目前身份(假设为root)的所有限制数据数值 [root@www ~]# ulimit -a core file size (blocks, -c) 0 <==只要是 0 就代表没限制 data seg size (kbytes, -d) unlimited scheduling priority (-e) 0 file size (blocks, -f) unlimited <==可创建的单一文件的大小 pending signals (-i) 11774 max locked memory (kbytes, -l) 32 max memory size (kbytes, -m) unlimited open files (-n) 1024 <==同时可开启的文件数量 pipe size (512 bytes, -p) 8 POSIX message queues (bytes, -q) 819200 real-time priority (-r) 0 stack size (kbytes, -s) 10240 cpu time (seconds, -t) unlimited max user processes (-u) 11774 virtual memory (kbytes, -v) unlimited file locks (-x) unlimited 范例二:限制用户仅能创建 10MBytes 以下的容量的文件 [root@www ~]# ulimit -f 10240 [root@www ~]# ulimit -a file size (blocks, -f) 10240 <==最大量为10240Kbyes,相当10Mbytes [root@www ~]# dd if=/dev/zero of=123 bs=1M count=20 File size limit exceeded <==尝试创建 20MB 的文件,结果失败了! |
单一 filesystem 能够支持的单一文件大小与 block 的大小有关。例如 block size 为 1024 byte 时,单一文件可达 16GB 的容量。但是,我们可以用 ulimit 来限制使用者可以创建的文件大小! 利用 ulimit -f 就可以来配置了!
Tips: 想要复原 ulimit 的配置最简单的方法就是注销再登陆,否则就是得要重新以 ulimit 配置才行! 不过,要注意的是,一般身份使用者如果以 ulimit 配置了 -f 的文件大小, 那么他『只能继续减小文件容量,不能添加文件容量喔!』 |
变量内容的删除、取代与替换
- 变量内容的删除与取代
范例一: [root@www ~]# path=${PATH} [root@www ~]# echo $path /usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin: /usr/sbin:/usr/bin:/root/bin <==这两行其实是同一行! 范例二:假设我不喜欢 kerberos,所以要将前两个目录删除掉 [root@www ~]# echo ${path#/*kerberos/bin:} /usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin |
${variable#/*kerberos/bin:} 代表要被删除的部分,由于 # 代表由前面开始删除,所以这里便由开始的 / 写起。 需要注意的是,我们还可以透过通配符 * 来取代 0 到无穷多个任意字符 以上面范例二的结果来看, path 这个变量被删除的内容如下所示: /usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin: /usr/sbin:/usr/bin:/root/bin <==这两行其实是同一行! |
范例三:我想要删除前面所有的目录,仅保留最后一个目录 [root@www ~]# echo ${path#/*:} /usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin: /root/bin <==这两行其实是同一行! # 由于一个 # 仅删除掉最短的那个,因此他删除的情况可以用底下的删除线来看: # /usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin: # /usr/sbin:/usr/bin:/root/bin <==这两行其实是同一行! [root@www ~]# echo ${path##/*:} /root/bin # 多加了一个 # 变成 ## 之后,他变成『删除掉最长的那个数据』!亦即是: # /usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin: # /usr/sbin:/usr/bin:/root/bin <==这两行其实是同一行! |
- # :符合取代文字的『最短的』那一个;
- ##:符合取代文字的『最长的』那一个
范例四:我想要删除最后面那个目录,亦即从 : 到 bin 为止的字符串 [root@www ~]# echo ${path%:*bin} /usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin: /usr/sbin:/usr/bin <==最后面一个目录不见去! # 这个 % 符号代表由最后面开始向前删除!所以上面得到的结果其实是来自如下: # /usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin: # /usr/sbin:/usr/bin:/root/bin <==这两行其实是同一行! 范例五:那如果我只想要保留第一个目录呢? [root@www ~]# echo ${path%%:*bin} /usr/kerberos/sbin # 同样的, %% 代表的则是最长的符合字符串,所以结果其实是来自如下: # /usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin: # /usr/sbin:/usr/bin:/root/bin <==这两行其实是同一行! |
例题:
假设你是 root ,那你的 MAIL 变量应该是 /var/spool/mail/root 。假设你只想要保留最后面那个档名 (root), 前面的目录名称都不要了,如何利用 $MAIL 变量来达成?
答:
题意其实是这样『
/var/spool/mail/root』,亦即删除掉两条斜线间的所有数据(最长符合)。 这个时候你就可以这样做即可:
|
范例六:将 path 的变量内容内的 sbin 取代成大写 SBIN: [root@www ~]# echo ${path/sbin/SBIN} /usr/kerberos/SBIN:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin: /usr/sbin:/usr/bin:/root/bin # 关键词在于那两个斜线,两斜线中间的是旧字符串 # 后面的是新字符串 [root@www ~]# echo ${path//sbin/SBIN} /usr/kerberos/SBIN:/usr/kerberos/bin:/usr/local/SBIN:/usr/local/bin:/SBIN:/bin: /usr/SBIN:/usr/bin:/root/bin # 如果是两条斜线,那么就变成所有符合的内容都会被取代! |
变量配置方式 | 说明 |
${变量#关键词} ${变量##关键词} |
若变量内容从头开始的数据符合『关键词』,则将符合的最短数据删除 若变量内容从头开始的数据符合『关键词』,则将符合的最长数据删除 |
${变量%关键词} ${变量%%关键词} |
若变量内容从尾向前的数据符合『关键词』,则将符合的最短数据删除 若变量内容从尾向前的数据符合『关键词』,则将符合的最长数据删除 |
${变量/旧字符串/新字符串} ${变量//旧字符串/新字符串} |
若变量内容符合『旧字符串』则『第一个旧字符串会被新字符串取代』 若变量内容符合『旧字符串』则『全部的旧字符串会被新字符串取代』 |
- 变量的测试与内容替换
范例一:测试一下是否存在 username 这个变量,若不存在则给予 username 内容为 root [root@www ~]# echo $username <==由于出现空白,所以 username 可能不存在,也可能是空字符串 [root@www ~]# username=${username-root} [root@www ~]# echo $username root <==因为 username 没有配置,所以主动给予名为 root 的内容。 [root@www ~]# username="vbird tsai" <==主动配置 username 的内容 [root@www ~]# username=${username-root} [root@www ~]# echo $username vbird tsai <==因为 username 已经配置了,所以使用旧有的配置而不以 root 取代 |
new_var=${old_var-content} 变量的『内容』,在本范例中,这个部分是在『给予未配置变量的内容』 |
范例二:若 username 未配置或为空字符串,则将 username 内容配置为 root [root@www ~]# username="" [root@www ~]# username=${username-root} [root@www ~]# echo $username <==因为 username 被配置为空字符串了!所以当然还是保留为空字符串! [root@www ~]# username=${username:-root} [root@www ~]# echo $username root <==加上『 : 』后若变量内容为空或者是未配置,都能够以后面的内容替换! |
变量配置方式 | str 没有配置 | str 为空字符串 | str 已配置非为空字符串 |
var=${str-expr} | var=expr | var= | var=$str |
var=${str:-expr} | var=expr | var=expr | var=$str |
var=${str+expr} | var= | var=expr | var=expr |
var=${str:+expr} | var= | var= | var=expr |
var=${str=expr} | str=expr var=expr |
str 不变 var= |
str 不变 var=$str |
var=${str:=expr} | str=expr var=expr |
str=expr var=expr |
str 不变 var=$str |
var=${str?expr} | expr 输出至 stderr | var= | var=$str |
var=${str:?expr} | expr 输出至 stderr | expr 输出至 stderr | var=$str |
:
测试:先假设 str 不存在 (用 unset) ,然后测试一下减号 (-) 的用法: [root@www ~]# unset str; var=${str-newvar} [root@www ~]# echo var="$var", str="$str" var=newvar, str= <==因为 str 不存在,所以 var 为 newvar 测试:若 str 已存在,测试一下 var 会变怎样?: [root@www ~]# str="oldvar"; var=${str-newvar} [root@www ~]# echo var="$var", str="$str" var=oldvar, str=oldvar <==因为 str 存在,所以 var 等于 str 的内容 |
测试:先假设 str 不存在 (用 unset) ,然后测试一下等号 (=) 的用法: [root@www ~]# unset str; var=${str=newvar} [root@www ~]# echo var="$var", str="$str" var=newvar, str=newvar <==因为 str 不存在,所以 var/str 均为 newvar 测试:如果 str 已存在了,测试一下 var 会变怎样? [root@www ~]# str="oldvar"; var=${str=newvar} [root@www ~]# echo var="$var", str="$str" var=oldvar, str=oldvar <==因为 str 存在,所以 var 等于 str 的内容 |
测试:若 str 不存在时,则 var 的测试结果直接显示 "无此变量" [root@www ~]# unset str; var=${str?无此变量} -bash: str: 无此变量 <==因为 str 不存在,所以输出错误信息 测试:若 str 存在时,则 var 的内容会与 str 相同! [root@www ~]# str="oldvar"; var=${str?novar} [root@www ~]# echo var="$var", str="$str" var=oldvar, str=oldvar <==因为 str 存在,所以 var 等于 str 的内容 |