shell 中的变量用法及说明
1.变量
用一个固定的字符串(也可能是字符、数字等组合)代替更多、更复杂的内容、该内容里可能还包含变量、路径、字符串等其它的内容。 变量是暂时存储数据的地方及数据标记,所存储的数据存在于内存空间中,通过正确的调用内存空间中变量的名字就可以去除与变量对应的数据。
变量的特性:
默认情况下bash shell中是不会区分变量类型的,整数型、字符串、小数等,也可以使用declare显示定义变量的类型。
变量类型:
环境变量(也可称为全局变量),可以在创建他们的shell及其派生出来的任意进程shell中使用,环境变量又可分为自定义环境变量和bash内置的环境变量。 普通变量(也可以称为局部变量),只能在创建他们的shell函数或shell脚本中使用,普通变量一般由开发者在开发脚本程序时创建。
(1).环境变量
一般是指用export内置命令导出的变量,用于定义shell的运行环境,保证shell命令的正确执行。shell通过环境变量来确定登陆用户名、命令路径、终端类型、登录目录等,所有的环境变量都是系统全局变量,可用于所有子进程中,这包括编辑器、shell脚本和各类应用。 环境变量可以在命令行中设置和创建,但用户退出命令行时这些变量值就会丢失,因此,如果想永久保存环境变量,可以在用户的家目录下的.bash_profile或 .bashr(非用户登录模式特有,例如远程SSH)文件中,或者全局配置/etc/bashrc(非用户登录模式特有,例如远程SSH)或/etc/profile文件中定义。在将环境变量放入上述文件中,每次用户登录时这些变量都将被初始化。 按照系统规范,所有的环境变量的名字均采用大写形式。 IFS=$'\t\n' 内部字段分隔符,一般是空格符、制表符和换行符,用于划分由命令替换、循环结构中和所读取的输入产生的词的字段。 PS1='[\u@\h \w]\$' 主题是符串,默认是$ PS2='>' 次提示符,默认值是 > 显示变量值的命令: set:输出所有的变量,包括全局变量和局部变量;set -o显示bash shell的所有参数配置信息。 env:只显示全局变量; declare:输出所有的变量、函数、整数和已经导出的变量
(1.1).自定义环境变量
export 大写变量名=value 大写变量名=value;export 大写变量名 declare -x 变量名=value
(1.2).常见的全局环境变量的配置
/etc/profile /etc/bashrc /etc/profile.d 若要在登录后初始化或显示加载内容,则把脚本文件放在/etc/profile.d/下即可(无须加执行权限)
设置登录提示符
(1)、cat /etc/motd (2)、cat /etc/profile.d/dada.sh echo "here is dada training"
.显示与取消环境变量
echo 和printf命令打印环境变量 printf "$HOME\n" unset HOME:取消变量
(1.3)环境变量小总结:
变量名通常要大写; 变量可以在自身的shell及子shell中使用; 常用export来定义环境变量; 执行env默认可以显示所有的环境变量名称及对应的值; 输出时间用“$变量名 ”,取消时用“unset变量名”; 书写crond定时任务时要注意,脚本要用到的环境变量里最好先在执行的shell脚本中重新定义; 如果希望环境变量永久生效,则可以将其放在用户环境变量文件/.bashrc或全局环境变量文件里/etc/bashrc;
(1.4).环境变量生效顺序:
/etc/profile 全局环境变量 /etc/profile.d/脚本文件 /.bash_profile用户环境变量文件 /.bashrc 用户环境变量文件 /etc/bashrc 全局环境变量文件 系统运行shell十五方式一般有三种: 通过系统用户登录后默认运行的shell; 非登录交互式运行shell; 执行脚本运行非交互式shell; 如果用户的shell不是登录时启动的(比如手动敲下bash时启动或者其它不需要输入密码的登录及远程连接情况),那么这种非登录shell指挥加载$HOME/.bashrc,并会去找/etc/bashrc(全局环境变量文件)。因此如希望在非登录shell下也可读到设置的环境变量等内容,就需要将变量设定等写入$HOME/.bashrc 或者/etc/bashrc,而不是$HOME/.bash_profile或/etc/profile。 非交互式登录的只会加载家目录下 ./bashrc (用户环境变量文件),并会去找/etc/bashrc(全局环境变量文件)。
(2).普通变量:
普通变量定义:
变量名=value 变量名=‘value’ 变量名=“value”
定义变量名要求及总结:
变量名只能为字母、数字、下划线只能以字母或下划线开头; 一般的变量定义,赋值常用双引号;简单的、连续的字符串可以不加引号;希望原样输出的使用单引号; 希望变量的内容是命令的解析结果时,要用反引号(` `),或者用 $() 把命令括起来再赋值; 变量名=`ls` :把命令用反引号引起来 ls a=`ls` echo $a 变量名=$(ls) :把命令用$()括起来 a=$(ls) echo $a
2.shell中特殊且重要的变量
(1).shell中的特殊位置参数变量
$0:获取当前执行的shell脚本的文件名,如果执行脚本包含了路径,那么就包括脚本路径。 $0的作用为取出执行脚本的名称(包括路径) dirname:获取脚本的路径 basename :获取脚本的名字 $n:获取当前执行的shell脚本的第n个参数值,n=1..9,当n为0时表示脚本的文件名;如果n>9,则用大括号{}括起来,例如${10},后面接的参数以空格分开。 $n如果想要输出正确内容,数字大于9的,必须给数字加上大括号{} $#:获取当前执行的脚本后面的参数的总个数。 $*:获取当前shell脚本所有传参的参数,不加引号和$@相同;如果给$*加上双引号,例如:"$*",则表示将所有的参数视为单个字符串,相当于"$1 $2 $3". $@:获取当前shell脚本所有传参的参数,不加引号和$*相同;如果给$@加上双引号,例如:$*",则表示将所有的参数视为不同的独立字符串,相当于”"$1" "$2" "$3""..."。这里将多参数传递给其他程序的最佳方式,因为他们会有所保留的内嵌在每一个参数里的任何空白。当"$@"和"$*"都加双引号时。两者是有区别的;都不加双引号时,两者无区别。
$#获取传参的个数 [root@localhost ~]# cat t2.sh if [ $# -ne 2 ] then echo "$0" exit 1 fi echo $1 $2 [root@localhost ~]# sh t2.sh t2.sh [root@localhost ~]# sh t2.sh wang yu feng t2.sh [root@localhost ~]# sh t2.sh wang yu wang yu
[root@localhost ~]# set "i am" clever girl.(用set设置位置参数) [root@localhost ~]# echo $# 3 [root@localhost ~]# echo $1 i am [root@localhost ~]# echo $2 clever [root@localhost ~]# echo $3 girl.
(*和@不加双引号输出内容相同)
[root@localhost ~]# for i in $*;do echo $i;done i am clever girl. [root@localhost ~]# for i in $@;do echo $i;done i am clever girl.
(@加上双引号)
[root@localhost ~]# for i in "$@";do echo $i;done(有双引号,每个参数均以独立的内容输出) i am clever girl. [root@localhost ~]# for i in "$*";do echo $i;done(有双引号,参数里的内容当作一个参数输出了) i am clever girl.
(如果$*不加双引号,会输出所有参数,第一个参数i am也被拆开输出)
[root@localhost ~]# for i in $*;do echo $i;done i am a girl [root@localhost ~]# for i in "$*";do echo $i;done i am a girl
(用shift将位置参数移位、左移)
[root@localhost ~]# set "i am" a clever girl [root@localhost ~]# shift [root@localhost ~]# echo $1 a [root@localhost ~]# echo $2 clever [root@localhost ~]# echo $3 girl
(2).shell进程中的特殊状态变量
$?:获取执行上一个指令状态返回值(0为成功,非0为 失败),常用 $$:获取当前执行的shell脚本的进程号(PID),不常用 $!:获取上一个在后台工作的进程的进程号(PID),不常用 $_:获取在此之前执行的命令或脚本的最后一个参数,不常用
$?:
判断命令、脚本或函数等程序是否执行成功; 若在脚本中调用执行“exit数字” 则会返回这个数字给”$?“变量 如果是在函数里,则通过”return数字“把这个数字以函数返回值的形式传给”$?“
$$:获取当前执行的shell脚本的进程号
[root@localhost sh]# cat test_pid.sh echo $$>/tmp/a.pid sleep 300 [root@localhost sh]# ps -ef|grep test_pid|grep -v grep root 8522 8003 0 05:32 pts/1 00:00:00 sh test_pid.sh [root@localhost sh]# sh test_pid.sh & [2] 8555 [root@localhost sh]# cat /tmp/a.pid 8555
(相同的脚本只能有一个在运行,当新脚本运行时,必须关闭未运行完或未退出的上一次的同名脚本)
[root@localhost sh]# cat pid.sh #!/bin/bash pidpath=/tmp/a.pid if [ -f "$pidpath" ] then kill `cat $pidpath`>/dev/null 2>&1 rm -f $pidpath fi echo $$ >$pidpath sleep 300 [root@localhost sh]# sh pid.sh & [1] 8564 [root@localhost sh]# ps -ef|grep pid.sh|grep -v grep root 8564 8003 0 05:47 pts/1 00:00:00 sh pid.sh [root@localhost sh]# sh pid.sh & [1] 8576 [root@localhost sh]# sh pid.sh & [2] 8580 [root@localhost sh]# sh pid.sh & [3] 8584 [root@localhost sh]# sh pid.sh & [4] 8588 [2] Terminated sh pid.sh
$:获得上一条命令的最后一个参数值_
[root@localhost sh]# ls -ld drwxr-xr-x. 2 root root 172 Sep 17 05:47 . [root@localhost sh]# echo $_ -ld
$!:获取上一次执行脚本的pid
[root@localhost sh]# ps -ef|grep pid.sh|grep -v grep [root@localhost sh]# sh pid.sh & [1] 8624 [root@localhost sh]# echo $! 8624
(3).bash shell内置变量命令
echo 在屏幕上输出信息
···-n :不换行输出 -e:解析转义字符 转义字符: \n:换行 \r:回车 \t:制表符 \b:退格 \v:纵向制表符
[root@localhost ~]# echo like;echo you like you [root@localhost ~]# echo -n like;echo you likeyou [root@localhost ~]# echo "i like you" i like you [root@localhost ~]# echo "ilikeyou" ilikeyou [root@localhost ~]# echo "i\tlike\tyou" i\tlike\tyou [root@localhost ~]# echo -e "i\tlike\tyou" i like you
eval
[root@localhost sh]# cat noeval.sh echo \$$# [root@localhost sh]# sh noeval.sh $0 [root@localhost sh]# sh noeval.sh heng ha(传入两个参数,没有打印ha) $2 [root@localhost sh]# sh eval.sh eval.sh [root@localhost sh]# sh eval.sh heng ha(传入两个参数,输出了ha) ha [root@localhost sh]# cat eval.sh #!/bin/bash eval "echo \$$#"
exec
exec命令能够在不创建新进程的子进程的前提下,转去执行指定的命令,当指定的命令执行完毕后,该进程(也就是最初的shell)就终止了。 当使用exec打开文件后,read命令每次都会将文件指针移动到文件的下一行进行读取,直到文件末尾,利用这个可以实现处理文件内容 。
read
从标准输入读取字符串等信息,传给shell程序内部定义的变量。
shift
在程序中每使用一次 shift语句,都会使所有的位置参数依次向左移动一个位置,并使位置参数$#减1,直到减到0为止。即使$2成为$1,$3成为$2等。
exit
退出shell程序,在exit之后可以有选择地指定一个数位作为返回状态。
(4).shell变量子串
${a}:返回变量$a的内容。 ${#a}:返回$a内容的长度。 ${a:offset}:在返回${a}中,从位置offset之后开始提取子串到结尾。 ${a:offset:length}:在变量${a}中,从位置offset之后开始提取长度为length的子串。 ${a#word}:从变量${a}开头开始删除最短匹配的word子串。 ${a##word}:从变量${a}开头开始删除最长匹配的word子串。 ${a%word}:从变量${a}结尾开始删除最短匹配的word子串。 ${a%%word}:从变量${a}结尾开始删除最短匹配的word子串。 ${a/pattern/string}:使用string代替第一个匹配的pattern。 ${a//pattern/string}:使用string代替所有匹配的pattern。
利用time命令及佛循环对几种获取字符串长度的方法进行性能比较:
(1)变量自带的获取长度的方法
[root@localhost ~]# time for n in {1..10000};do char=`seq -s "oldboy"100`;echo ${#char} &>/dev/null;done real 0m10.453s user 0m5.863s sys 0m3.183s
(2)利用管道加wc的方法
[root@localhost ~]# time for n in {1..10000};do char=`seq -s "oldboy" 100`;echo${char} |wc -l &>/dev/null;done real 0m22.482s user 0m11.795s sys 0m10.616s
(3)利用expr自带的length函数方法
[root@localhost ~]# time for n in {1..10000};do char=`seq -s "oldboy"100`;expr length "${#char}"&>/dev/null;done real 0m19.465s user 0m10.198s sys 0m7.429s
(4)利用awk自带的length函数方法
[root@localhost ~]# time for n in {1..10000};do char=`seq -s "oldbor" 100`;echo $char|awk '{print length($0)}' &>/dev/null;done real 0m22.917s user 0m16.402s sys 0m6.451s
比较结果:
变量自带的计算长度的方法效率最高,在要求效率的场景中尽量多用。
使用管道统计的方法的效率都比较差,在要求效率的场景中尽量不用。
(5)替换字符串
[root@localhost ~]# a="i am a boy boy"
[root@localhost ~]# echo a
i am a boy boy
[root@localhost ~]# echo{a/boy/girl}
i am a girl boy
[root@localhost ~]# echo ${a//boy/girl}
i am a girl girl
[root@localhost ~]#
小结:一个“/”表示替换匹配到的第一个字符串;
两个“//”表示替换匹配的所有字符串;
(6)批处理修改文件名;
[root@localhost ~]# touch file{a..z}.feng [root@localhost ~]# ll [root@localhost ~]# f=filea.feng [root@localhost ~]# echo ${f//.feng/ } [root@localhost ~]# for f in `ls *.feng`;do mv $f `echo ${f//.feng/ }`;done
3.shell特殊扩展变量介绍
${parameter:-word}: 如果parameter的变量值为空或未赋值,则会返回word字符串并替代变量的值。 ${parameter:=word}: 如果parameter的变量值为空或未赋值,则设置这个值为word,并返回其值。 ${parameter:?word}: 如果parameter的变量值为空或未赋值,那么word字符串将被作为标准错误输出,否则输出变量的值。 ${parameter:?word}: 如果parameter的变量值为空或未赋值,则什么都不做,否则word字符串将替代变量的值。
4.算数运算符
!、&&、||:逻辑非(取反)、逻辑与(and)、逻辑或(or)* - - - / % - - :幂运算 ++ -- < <= > >= == != = << >> :向左移位、向右移位 ~ | & ^:按位取反、按位异或、按位与、按位或 = += -= *= /= %= :赋值运算符,例如a+=1相当于a=a+1,a-=1相当于a=a-1* (()): 用于整数运算的常用运算符,效率很高。 let: 用于整数运算,类似于“(())” expr:可用于整数运算 bc: Linux下的一个计算器程序(适合整数及小数运算) $[]: 用于整数运算 awk:awk既可以用于整数运算,也可以用于小数运算 declare:定义变量值和属性,-i 参数可以用于定义整形变量,做运算
(()):进行数值运算与数值比较
((i=i+1)):赋值计算 [root@localhost ~]# echo $((1+1)) 2 i=$((i+1)):可以“(())”前加$符,表示将表达式运算后赋值给 i [root@localhost ~]# echo 2=$((2+3)) 2=5 ((8>7&&5==5)):可以进行比较,还可以加入逻辑卷与逻辑或,用于条件判断 echo $(2+1):需要直接输出运算表达式的运算结果时,可以在“(())“前加上$符 [root@localhost ~]# echo $((2+1)) 3 echo $((3<8)):双括号进行比较及判断 ,1为真,0为假 [root@localhost ~]# echo $((a+=1)) 9 [root@localhost ~]# echo $((a**2)) 81 [root@localhost ~]# echo $((a+=1)) 10 [root@localhost ~]# echo $((a**2)) 100
各种”(())“运算的脚本
[root@localhost ~]# cat test.sh #!/bin/bash a=6 b=2 echo "a-b=$(($a-$b))" echo "a+b=$(($a+$b))" echo "a*b=$(($a*$b))" echo "a/b=$(($a/$b))" echo "a**b=$(($a**$b))" echo "a%b=$(($a%$b))" [root@localhost ~]# sh test.sh a-b=4 a+b=8 a*b=12 a/b=3 a**b=36 a%b=0 传参: [root@localhost ~]# sh test.sh 5 2 a-b=3 a+b=7 a*b=10 a/b=2 a**b=25 a%b=1 [root@localhost ~]# cat test.sh #!/bin/bash a=$1 b=$2 echo "a-b=$(($a-$b))" echo "a+b=$(($a+$b))" echo "a*b=$(($a*$b))" echo "a/b=$(($a/$b))" echo "a**b=$(($a**$b))" echo "a%b=$(($a%$b))"
let运算、let赋值表达式:
[root@localhost ~]# i=1 [root@localhost ~]# let i=i+3 [root@localhost ~]# echo $i 4 let i=i+5 相当于 ((i=i+8))
expr命令、
expr用于运算** [root@localhost ~]# expr 2 + 2 4 [root@localhost ~]# expr 2 - 2 0 [root@localhost ~]# expr 2 \* 2 4 **expr配合变量计算:** [root@localhost ~]# i=5 [root@localhost ~]# i=`expr $i + 4` [root@localhost ~]# echo $i 9 **expr可以判断某个变量** 将一个位置的变量和一个已知的整数相加,看返回值是否为0,如果为0就认为加法的变量为整数,否则就不是整数。 [root@localhost ~]# i=2 [root@localhost ~]# expr $i + 6 &>/dev/null [root@localhost ~]# echo $? 0 [root@localhost ~]# i=dada [root@localhost ~]# expr $i + 6 &>/dev/null [root@localhost ~]# echo $i dada **通过传参判断输出内容是否为整数** [root@localhost ~]# vi 1_expr.sh [root@localhost ~]# cat 1_expr.sh #!/bin/bash expr $1 + 1 >/dev/null 2>&1 [ $? -eq 0 ] && echo int||echo chars [root@localhost ~]# sh 1_expr.sh boy chars [root@localhost ~]# sh 1_expr.sh 2 int expr的特殊用法:(判断文件扩展名是否符合要求) [root@localhost ~]# cat expr1.sh #!/bin/bash if expr "$1" : ".*\.pub" &>/dev/null then "you are using $1" else echo "pls use *.pub file" fi [root@localhost ~]# sh expr1.sh file pls use *.pub file 利用expr计算字符串长度: [root@localhost ~]# char="i am girl" [root@localhost ~]# expr length "$char" 9 [root@localhost ~]# echo ${#char} 9 [root@localhost ~]# echo ${char}|wc -L 9 [root@localhost ~]# echo ${char}|awk '{print length ($0)}' 9
注意: 运算符及用于计算的数字左右都至少要有一个空格,否则会报错。 使用乘号时,必须用反斜线屏蔽其特定含义,因为shell可能会误解星号的含义。
read:通过read读入持续等待输入例子
[root@localhost ~]# cat 1_int.sh #!/bin/bash while true do read -p "Pls input:" a expr $a + 0 >/dev/null 2>&1 [ $? -eq 0 ] && echo int || echo chars done
[root@localhost ~]# sh 1_int.sh Pls input:2 int Pls input:dada chars Pls input:2da chars Pls input:^C
6.基于shell变量输入read命令的运算
shell变量除了可以直接赋值或脚本传参外,还可以使用read命令从标准输入中获得 ,read为bash内置命令。 read [参数] [变量名] 参数: -p prompt:设置提示信息。 -t timeout:设置输入等待的时间,单位默认为秒。
read的基本读入: [root@localhost ~]# read -p "shu ru shuzi:" num(输入一个数字,赋值给num变量,num前面需要有空格) shu ru shuzi:2 [root@localhost ~]# echo $num(输出变量值) 2 [root@localhost ~]# read -p "please input two number:" a1 a2(读入两个输入,以空格分开,分别赋值给a1和a2变量,a1和a2之间要有空格) please input two number:1 2 [root@localhost ~]# echo $a1 1 [root@localhost ~]# echo $a2 2
read的读入功能相当于交互式接受用户输入,然后给变量赋值。
read -p 的功能可以用echo和read来实现。
[root@localhost ~]# read -t 6 -p "please input two number:"(在6秒内输入两个数) please input two number:1 3 [root@localhost ~]# read -t 6 -p "please input two number:"(超过6秒自动退出) please input two number:[root@localhost ~]#
用read方式读入整数变量进行加减乘除运算:
[root@localhost ~]# cat test.sh #!/bin/bash read -t 5 -p "please input two numbers:" a b echo "a-b=$(($a-$b))" echo "a+b=$(($a+$b))" echo "a*b=$(($a*$b))" echo "a/b=$(($a/$b))" echo "a**b=$(($a**$b))" echo "a%b=$(($a%$b))" [root@localhost ~]# sh test.sh please input two numbers:1 3 a-b=-2 a+b=4 a*b=3 a/b=0 a**b=1 a%b=1
注意:脚本传参和read读入只用一种就好。 接受read的变量,不该带$符号。
用match进行整数判断:
[root@localhost ~]# sh t1.sh 2 2 is a num [root@localhost ~]# sh t1.sh da da is not a num [root@localhost ~]# cat t1.sh #!/bin/bash if [[ `expr match "$1" "[0-9][0-9]*$" ` == 0 ]] then echo "$1 is not a num" exit 2 else echo "$1 is a num" fi
5 .编写shell脚本,打印下面语句中字符数不大于6的单词:
[root@localhost ~]# cat word_length.sh
#!/bin/bash
for n in I am good child linux welcome to our training
do
if [ `expr length $ n` -le 6 ]
then
echo $
fi
done
[root@localhost ~]# sh word_length.sh
I
am
good
child
linux
to
our
bc命令的用法:
bc是unix/linux下的计算器,因此,除了可以作为计算器来使用,还可以作为命令行工具来使用。
[root@localhost ~]# bc bc 1.06.95 Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc. This is free software with ABSOLUTELY NO WARRANTY. For details type `warranty'. 1+1 2 4*77 308 2-1 1
bc用在命令行下面
[root@localhost ~]# echo 3+5|bc 8 [root@localhost ~]# echo 3*4+5*1|bc 17 [root@localhost ~]# echo "scale=2;355/113"|bc(scale=2:保留两位小数) 3.14 [root@localhost ~]# echo "scale=6;355/113"|bc(scale=6:保留6位小数) 3.141592
利用bc配合变量运算:
[root@localhost ~]# i=5 [root@localhost ~]# i=`echo $i+4|bc` [root@localhost ~]# echo $i 9
例:通过一条命令计算输出1+2+3+~+10的表达式,并计算出结果:
使用bc计算:
[root@localhost ~]# echo "`seq -s '+' 10`=`seq -s "+" 10|bc`" 1+2+3+4+5+6+7+8+9+10=55 [root@localhost ~]# echo `seq -s '+' 10`=`seq -s "+" 10|bc` 1+2+3+4+5+6+7+8+9+10=55 [root@localhost ~]# echo `seq -s "+" 10|bc` 55
使用expr计算:
[root@localhost ~]# echo `seq -s '+' 10`=`seq -s " + " 10|xargs expr`(+两边要有空格) 1+2+3+4+5+6+7+8+9+10=55 使用 $[] 计算: [root@localhost ~]# echo `seq -s "+" 10`=$(echo $[`seq -s "+" 10`]) 1+2+3+4+5+6+7+8+9+10=55
使用(())计算:
echo `seq -s '+' 10`="$((`seq -s "+" 10`))" (4-2=2) [root@localhost ~]# echo "4 2"|awk '{print ($1-$2)}' 2 (17-2)/3 [root@localhost ~]# echo "17 3"|awk '{print ($1-2)/$2}' 5 (4-2)/2 [root@localhost ~]# echo "4 2"|awk '{print ($1-2)/$2}' 1
$[]符号运算:
[root@localhost ~]# i=5 [root@localhost ~]# i=$[i+6] [root@localhost ~]# echo $i 11 [root@localhost ~]# echo $[2*4] 8 [root@localhost ~]# echo $[2/4] 0