变量用于保存有用信息,如路径名、文件名、数字等,Linux用户使用变量定制其工作环境,使系统获知用户相关的配置。变量本质上是存储数据的一个或多个计算机内存地址。
变量可分为三类:
本地变量是仅可以在用户当前Shell(就是现在正在使用的这个端口)生命期的脚本中使用的变量,类似于C、C++、Java等编程语言中局部变量
环境变量则适用于所有由登录进程所产生的子进程,环境变量在用户登录后到注销之前的所有编辑器、脚本、程序和应用中都有效
位置参数也属于变量,用户用于向Shell脚本传递参数,是只读的
变量替换和赋值
1 变量是某个值的名称,引用变量值就称为变量替换
$符号是变量替换符号,如variable是变量名,那么$variable就表示变量的值
变量赋值有两种格式:
variable=value
${ variable=value }
等号的两边可以有空格,这不影响赋值操作;
如果值(value)中包含空格,则必须用双引号括起来;
变量名只能包括大小写字母(a-z和A-Z)、数字(0-9)、下划杠(_)等符号,并且变量名不能以数字开头,否则视为无效变量名
eg
variable1=33
variable2=”hello world”
variable3=hello world 这个是错误的 一定要加引号!
2 利用unset命令可以清除变量的值,命令格式为:
unset 变量名
eg
unset variable2
3 readonly可将变量设置为只读,变量一旦设置为只读,任何用户不能对此变量进行重新赋值
variable=value #先对一个变量进行赋值
readonly variable #将variable变量设置为只读
eg
color=green
readonly color
color=blur
结果;bash: color: 只读变量
无类型的Shell脚本变量
Shell脚本变量是无类型的,这与awk变量是一样的
bash Shell不支持浮点型,只支持整型和字符型,默认情况下,Shell脚本变量是字符型的,同时,字符型的变量还具有一个整型值,为0;但是,bash Shell并不要求在定义一个变量时声明其类型
Shell会根据上下文判断出数值型的变量,并进行变量的算术运算和比较等数值操作。判断标准是变量中是否只是包含数字,如果变量只包含数字,则Shell认定该变量是数值型的,反之,Shell认定该变量是字符串
eg
脚本:
#!/bin/bash
a=2009
let "a+=1"
echo "a=$a"
b=xx09
echo "b=$b"
declare -i b 将B声明为整数
echo "b=$b"
let "b+=1" 此处的结果运算过程: 上面强制声明为整数。而字符串的默认整数是0 所以+1后结果为1
echo "b=$b"
exit 0
结果
a=2010
b=xx09
b=xx09
b=1
eg2
脚本
#!/bin/bash
c=""
echo "c=$c"
let "c+=1"
echo "c=$c"
echo "e=$e"
let "e+=1"
echo "e=$e"
exit 0
结果:
c=
c=1
e=
e=1
结论:
shell变量有两种类型, 字符,数字(整数!)
字符默认是 空 “”
数字 默认是 0
有型变量
Shell变量一般是无类型的,但是bash Shell提供了declare和typeset两个命令用于指定变量的类型,两个命令是完全等价的
declare [选项] 变量名
-r 将变量设置为只读属性
-i 将变量定义为整型数
-a 将变量定义为数组
-f 显示此脚本前定义过的所有函数名及其内容
-F 仅显示此脚本前定义过的所有函数名
-x 将变量声明为环境变量
eg
#!/bin/bash
var1=2012
var2=$var1+1 什么也没有声明则是字符串
echo "var2=$var2"
let "var3=$var1+1" 纯是let的作用
echo "var3=$var3"
declare -i var4 声明为整数!
var4=$var1+1
echo "var4=$var4"
ming@ming-F83VF:~/shellpractice/chapter9$./vartype.sh
var2=2012+1
var3=2013
var4=2013
双小括号方法,即((…))格式,也可以用于算术运算
双小括号方法也可以使bash Shell实现C语言风格的变量操作
#!/bin/bash
var1=9
var2=10
var3=$((var1*var2)) 可以直接吧$提到最外面
echo $var3
declare命令的-x选项将变量声明为环境变量,相当于export命令,但是,declare -x允许在声明变量为环境变量的同时给变量赋值,而export命令不支持此功能
declare -x variable-name=value
环境变量
1 定义环境变量的方法
ENVIRON-VARIABLE=value #环境变量赋值
export ENVIRON-VARIABLE #声明环境变量
清除环境变量同样是unset命令
2 env命令可以列出已经定义的环境变量
环境变量:对于这个shell以及子shell都可以使用, 一般大写!!!
3 PWD和OLDPWD
PWD记录当前的目录路径,当利用cd命令改变当前目录时,系统自动更新PWD的值
OLDPWD记录旧的工作目录,即用户所处的前一个目录
4 PATH就记录了一系列的目录列表,Shell为每个输入命令搜索PATH中的目录列表
小总结:
对于刚才执行的./null-undeclear.sh 可以在刚才的目录这样执行,但是切换到它的上一级的目录就不能执行,若想执行的话,就要:
./variable/./null-undeclear.sh 其中variable是null-undeclear.sh文件所在的目录
而ls cat find等这样的命令可以任何的目录中执行,这是为什么?
因为PATH
linux执行命令的时候会先去PATH中寻找命令所在的目录的
如果想执行的画,就将 null-undeclear.sh目录加入到PATH中!
5 HOME记录当前用户的根目录
6 SHELL变量保存缺省Shell,缺省的值为/bin/bash
7 USER和UID是保存用户信息的环境变量,USR表示已登录用户的名字,UID则表示已登录用户的ID
8 PPID是创建当前进程的进程号,即当前进程的父进程号
9 PS1和PS2 (linux中有PS1 PS2 PS3 PS4)
提示符变量,用于设置提示符格式
PS1是用于设置一级Shell提示符的环境变量,也称为主提示符字符串,即改变: [root @jselab ~]#
eg:
PS1变量是[\u@\h \W]\$,\u、\h、\W和\$表示了特定含义,\u表示当前用户名,\h表示表示主机名,\W表示当前目录名,如果是root用户,\$表示#号,其他用户,\$则表示$号
PS2是用于设置二级Shell提示符的环境变量,
eg
echo $PS2 结果: >
提示符变量中特殊符号及其意义:
模式 意义
\d 以“周 月日”格式显示的日期 日期信息
\H 主机名和域名 host
\h 主机名 host
\s Shell的类型名称 shell
\T 以12小时制显示时间,格式为:HH:MM:SS time
\t 以24小时制显示时间,格式为:HH:MM:SS time
\@ 以12小时制显示时间,格式为:am/pm 12小时制显示时间
\u 当前的用户名 user
\v bash Shell的版本号 version
\V bash Shell的版本号和补丁号
\w 当前工作目录的完整路径 way
\W 当前工作目录名字
\# 当前命令的序列号 #sequence
\$ 如果UID为0,打印#;否则,打印$
几个重要的配置文件“
1
$HOME/.bash_profile是最重要的配置文件,当某Linux用户登录时,Shell会自动执行.bash_profile文件,如果.bash_profile文件不存在,则自动执行系统默认的配置文件/etc/profile
/etc/profile 全局用户 文件 如果修改了此文件中的设置,修改的设置只会影响单个用户
~/.bash_profile 用户个人配置文件, 如果修改了此文件中的设置,只会影响单个用户
/etc/bashrc 全局变量配置文件,此文件中中定义了所有用户的环境变量
~/.bashrc 个人环境变量配置文件,此文件中定义了 用户的环境变量
eg
cat /etc/profile
结果
# /etc/profile: system-wide .profilefile for the Bourne shell (sh(1))
# and Bourne compatible shells(bash(1), ksh(1), ash(1), ...).
if [ "$PS1" ]; then
if [ "$BASH" ] && [ "$BASH" !="/bin/sh" ]; then
# The file bash.bashrc already sets the default PS1.
# PS1='\h:\w\$ '
if [ -f /etc/bash.bashrc ]; then
. /etc/bash.bashrc
fi
else
if [ "`id -u`" -eq 0 ]; then
PS1='# '
else
PS1='$ '
fi
fi
fi
# The default umask is now handledby pam_umask.
# See pam_umask(8) and/etc/login.defs.
if [ -d /etc/profile.d ]; then
for i in /etc/profile.d/*.sh; do
if [ -r $i ]; then
. $i
fi
done
unset i
fi
exportJAVA_HOME=/usr/lib/jvm/jdk1.7.0_04
export JRE_HOME=${JAVA_HOME}/jre
exportCLASSPATH=$CLASSPATH:.:$JAVA_HOME/lib:$JAVA_HOME/jre/lib
exportCATALINA_HOME=/home/ming/prosoft/tomcat7
exportANT_HOME=/home/ming/prosoft/apache-ant-1.8.4
exportPATH=$PATH:/home/ming/prosoft/apache-ant-1.8.4/bin
如果要使新加入的行立即生效,需要利用source命令执行.bash_profile文。
source命令也称为“点命令”,即句点符号“.”和source命令是等价的,source命令通常用于重新执行刚修改的初始化文件,使之立即生效,而不必注销并重新登录
eg
. .bash_profile #注意:句点符号后面用空格与文件名相分隔
source bash_profile
bash Shell的.bash_login文件来源于C Shell的.login文件,bash Shell的.profile文件来源于Bourne Shell和Korn Shell的.profile文件
当用户登录时,首先查找是否存在.bash_profile文件,若它不存在,则查找是否存在.bash_login文件,若它也不存在,则查找是否存在. profile文件
eg:
脚本:father.sh
#!/bin/bash
echo "Father Process ID is$$"
localvar="Define a localvariable."
echo "localvar=$localvar"
ENVVAR="Define a environmentvariable."
export ENVVAR
echo "ENVVAR=$ENVVAR"
$PWD/child.sh
echo "Return to father process:$$"
echo "localvar=$localvar"
echo "ENVVAR=$ENVVAR"
脚本 child.sh
#!/bin/bash
echo "Child Process ID is$$"
echo "My Father Process ID is$PPID"
echo "localvar=$localvar"
echo "ENVVAR=$ENVVAR"
localvar="Redefine this localvariable."
ENVVAR="Redefine thisenvironment variable."
echo "localvar=$localvar"
echo "ENVVAR=$ENVVAR"
执行:
./father.sh
结果:
Father Process ID is 5065
localvar=Define a local variable.
ENVVAR=Define a environmentvariable.
Child Process ID is 5066
My Father Process ID is 5065
localvar=
ENVVAR=Define a environmentvariable.
localvar=Redefine this localvariable.
ENVVAR=Redefine this environment variable.
Return to father process: 5065
localvar=Define a local variable.
ENVVAR=Define a environmentvariable.
由此可以知道:
子进程对变量的修改不影响父进程,而父进程修改变量会影响子进程!!!!
位置参数(positional parameters)是一种特殊的Shell变量,用于从命令行向Shell脚本传递参数
$1表示第1个参数、$2表示第2个参数等等,$0脚本的名字,从${10}开始,参数号需要用大括号括起来,如${10}、${11}、${100}……
$*和$@一样,表示从$1开始的全部参数
$#
命令行或者是位置参数的个数
$*
所有的位置参数,被作为一个单词.
注意:"$*"必须被""引用.
$@
与$* 同义,但是每个参数都是一个独立的""引用字串,这就意味着参数被完整地传递,
并没有被解释和扩展.这也意味着,每个参数列表中的每个参数都被当成一个独立的单词.
注意:"$@"必须被""引用.
其他的特殊参数
$-
传递给脚本的falg(使用set 命令).
注意:这起初是 ksh 的特征,后来被引进到Bash 中,但不幸的是,在Bash 中它看上去也不
能可靠的工作.使用它的一个可能的方法就是让这个脚本进行自我测试(查看是否是交
互的).
$!
在后台运行的最后的工作的PID(进程ID).
$_
保存之前执行的命令的最后一个参数.
$?
命令,函数或者脚本本身的退出状态(见Example 23-7)
用于检查上一个命令,函数或者脚本执行是否正确。(在Linux中,命令退出状态为0表示该命令正确执行,任何非0值表示命令出错。)
$$
脚本自身的进程ID.这个变量经常用来构造一个"unique"的临时文件名.
这通常比调用mktemp 来得简单.
注意事项:
[1] 当前运行的脚本的PID 为$$.
eg
脚本 position.sh
#!/bin/sh
echo "The script name is:$0"
echo "Parameter #1:$1"
echo "Parameter #2:$2"
echo "Parameter #3:$3"
echo "Parameter #4:$4"
echo "Parameter #5:$5"
echo "Parameter #6:$6"
echo "Parameter #7:$7"
echo "Parameter #8:$8"
echo "Parameter #9:$9"
echo "Parameter#10:${10}"
echo"-------------------------"
echo "All the command lineparameters are: $*"
运行:
./position.sh a b c d e f g h I j
结果:
The script name is: ./position.sh
Parameter #1:a
Parameter #2:b
Parameter #3:c
Parameter #4:d
Parameter #5:e
Parameter #6:f
Parameter #7:g
Parameter #8:h
Parameter #9:i
Parameter #10:j
-------------------------
All the command line parameters are:a b c d e f g h i j
引用:
引用指将字符串用引用符号括起来,以防止特殊字符被Shell脚本重解释为其他意义,特殊字符是指除了字面意思之外还可以解释为其他意思的字符
eg
ls i*
列出以i开头的文件
ls “i*”
则列出 i* 这个文件
双引号引用除美圆符号($)、反引号(`)和反斜线(\)之外的所有字符,即$、`和\在双引号中仍被解释为特殊意义
eg
脚本:
#!/bin/bash
variable1=2010
echo "$variable1"
echo $variable1
variable2="X Y Z"
echo "$variable2"
echo $variable2
执行结果:
2010
2010
X Y Z (由于要保留原有的空格,则必须使用””引号)
X Y Z (若不使用,则将空格给变成单个)
在双引号中保持$符号的特殊意义可以引用变量,如“$variable”表示以变量值替换变量名
用双引号引用变量能够防止字符串分割,保留变量中的空格
单引号引用了所有字符,即单引号中字符除单引号本身之外都解释为字面意义,单引号不再具备引用变量的功能
通常将单引号的引用方式称为全引用,将双引号的引用方式称为部分引用
eg
echo “$PWD”
/home/ming/shellpractice/variable
echo ‘#PWD’
$PWD
命令替换的两种格式: 命令替换 反引号:`
第一种 `Linux 命令`
第二种 $( Linux 命令)
eg
echo `whoo`
No command 'whoo' found, did youmean:
它将反引号中的内容 当作命令执行!!
eg
echo `who`
ming pts/2 2012-11-21 09:40 (:0.0)ming pts/3 2012-11-21 10:37 (:0.0)
eg
currentTime=`date`
echo $currentTime
2012年 11月 21日 星期三 10:38:53 CST
这个反引号的作用在 它可以和cjava c++等高级语言程序结合起来一起使用
一个c的程序
main.c
#include <stdio.h>
main ()
{
printf ("This is the output from Cprogram.");
}
ming@ming-F83VF:~/shellpractice/variable$gcc -o main main.c
ming@ming-F83VF:~/shellpractice/variable$printdata=`./main`
ming@ming-F83VF:~/shellpractice/variable$echo $printdata
This is the outputfrom C program.
(生城了main可执行文件)
转义:
反斜线符号(\)表示转义,当反斜线后面的一个字符具有特殊意义时,反斜线将屏蔽下一个字符的特殊意义,而已字面意义解析它
shell 中的数组
数组的格式:
ARRAY[Iindex]
定义数据
(1)第一种方式 array={1 2 3 4 5}
(2)第二中方式 array[0] =1;array[0 =2
数组的使用
(1) echo ${arr[1]} 显示某个元素
(2)echo $arr 默认引用数组的第一个元素
(3)echo ${arr[@]:2} 查看数组中 下标大于等于2的所有元素
(4)echo ${#arr[@]} 数组元素中的个数
清除数组
unset arr[0] 清除数组中 第1个元素
unset arr 清除真个数组
间接变量引用
如果第一个变量的值是第二个变量的名字,从第一个变量引用第二个变量的值就称为间接变量引用
variable1=variable2
variable2=value
variable1的值是variable2,而variable2又是变量名,variable2的值为value,间接变量引用是指通过variable1获得变量值value的行为
bash Shell提供了两种格式实现间接变量引用
eval tempvar=\$$variable1
tempvar=${!variable1}
eg
#!/bin/bash
var1=var2
var2=hadoop
echo "var1=$var1"
eval tempvar=\$$var1
echo"tempvar=$tempvar"
echo "var1=${!var1}"
结果
var1=var2
tempvar=hadoop
var1=hadoop
eg
#!/bin/bash
stu1_name=anders
stu1_address=shanghai
stu2_name=james
stu2_address=beijing
PS3="Pls : Enter Number->"
select number in 12
do
stu_name=stu${number}_name 此处的值变为:stu1_name或者为 stu2_address
stu_address=stu${number}_address
echo"name : ${!stu_name}"
echo"address : ${!stu_address}"
break
done
运行:
ming@ming-F83VF:~/shellpractice/chapter9$./test2.sh
1) 1
2) 2
Pls : Enter Number-> 1
name : anders
address : shanghai