二、Shell变量
类型 注释
强变量 变量在使用前,必须事先声明,甚至还需要初始化
弱变量 变量用时声明,甚至不区分类型
变量的作用:用来保存变化的数据
变量名 名称固定,由系统设定或用户定义
变量值 根据用户设置、系统环境变化而变化
设置方法
变量名=变量值
Shell变量的类型
类型 说明
环境变量(全局变量) 由系统维护,用于设置工作环境,只有个别环境变量用户可以直接更改。可以在创建它们的shell及其派生出来的任意子进程shell中使用。
位置变量 通过命令行给脚本程序传递参数
预定义变量 bash内置的一类有特殊用途的变量,可以直接调用,但不能直接赋值或修改
自定义变量 由用户自己设置、修改及使用
环境变量
在系统启动时,加载系统配置文件定义的变量
变量名和变量值是系统设置
变量名通常用大写字母定义
变量存的值是规定的,通常情况下不建议修改系统环境变量的值
作用域为当前shell进程及其子进程
环境变量用于定义shell的运行环境,保证shell命令的正确执行,shell通过环境变量来确定登陆用户名、命令路径、终端类型、登陆目录等,所有的环境变量都是系统全局变量,可用于所有子进程中,这包括编辑器、shell脚本和各类应用。
环境变量可以在命令行中设置,但用户退出时这些变量值也会丢失,因此最好在用户家目录下的.bash_profile文件中或全局配置/etc/bashrc,/etc/profile文件或者/etc/profile.d/中定义。将环境变量放入profile文件中,每次用户登录时这些变量值都会被初始化。
传统上,所有环境变量均为大写。环境变量应用于用户进程前,必须用export命令导出。
环境变量可用在创建他们的shell和从该shell派生的任意子shell或进程中。他们通常被称为全局变量以区别局部变量。通常,环境变量应该大写。环境变量是已经用export内置命令导出的变量。
有些环境变量,比如HOME、PATH、SHELL、UID、USESR等,在用户登陆之前就已经被/bin/login程序设置好了。通常环境变量定义并保存在用户家目录下的.bash_profile文件中。
配置文件
配置文件 注释
/etc/profile
~/.bashrc_profile
相关操作
env 列出所有的环境变量
set 列出所有变量
常见的环境变量
PWD
PATH
USER
LOGNAME
UID
SHELL
HOME
PS1
PS2
如果想设置环境变量,就要在给变量赋值之后或设置变量时使用export命令。带-x选项的declare内置命令也可完成同样的功能。
(注意:输出变量时不要在变量名前面加$)
①export 变量名=value ②变量名=value;export 变量名 ③declare -x 变量名=value
提示:以上为三种设置环境变量的方法
例:
export NAME = zgy declare -x NAME =zgy NAME=zgy;export NAME
自定义全局环境变量实例:
[zgy@Web ~]$ . .bash_profile [zgy@Web ~]$ echo $ZGY zgy [root@Web ~]# cat /etc/profile | grep ZGY export ZGY='zgy' [root@Web ~]# source /etc/profile 或. /etc/profile使其生效 [root@Web ~]# echo $ZGY zgy [root@Web ~]# env | grep ZGY ZGY=zgy
自定义环境变量生产环境java环境配置实例:tomcat,resin,csvn,hadoop.
export JAVA_HOME=/application/jdk export CLASSPATH=$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib export RESIN_HOME=/application/resin
常见放在:/etc/profile
如何查看变量值
echo $变量名
位置变量:只读变量
位置变量 只读变量
在执行脚本或Shell时,给脚本或函数传值的;表示为$n,n为正整数
$.....$n
${}......${N}
预定义变量(特殊变量)
当前脚本使用的Shell里面预先定义好的变量
变量名是固定的,变量值通常不修改
位置变量
$:获取当前执行的shell脚本的文件名,包括脚本路径。
$n:获取当前执行的shell脚本的第n个参数值,n=..,当n为0时表示脚本的文件名,如果n大于9,用大括号括起来,例如${}
$*:获取当前shell的所有参数,将所有的命令行参数视为单个字符串,相当于”$$$”...注意与$#的区别
$#:获取当前shell命令行中参数的总个数
$@:这个程序的所有参数”$””$””$””...”,这是将参数传递给其他程序的最佳方式,因为他会保留所有内嵌在每个参数里的任何空白。
提示:$*和$@的区别?
进程状态变量
$$:获取当前shell的进程号(PID)
$!:执行上一个指令的PID
$?:获取执行上一个指令的返回值(0为成功,非零为失败) #这个变量很常用
$_:在此之前执行的命令或脚本的最后一个参数
举例:
[root@Web ~]# cat etiantian.sh
echo '$ 获取当前执行的shell脚本的文件名,包括脚本路径:' $
echo '$n 获取当前执行的shell脚本的第n个参数值,n=1..9:' '$1'=$ '$2'=$ "\$3=$3" #当使用双引号时必须把两边括起来,并且要用反斜杠
echo '$* 获取当前shell的所有参数 "$1 $2 $3...注意与$#的区别:'$*
echo '$#:获取当前shell命令行中惨呼的总个数:' $#
echo '$@:这个程序的所有参数”$1””$2””$3””...”:' $@
echo '$$ 获取当前shell的进程号(PID):'$$
sleep
echo '$!:执行上一个指令的PID:' $!
echo '$? 获取执行上一个指令的返回值:' $?
echo '$_:在此之前执行的命令或脚本的最后一个参数:' $_
执行结果:
[root@Web ~]# sh etiantian.sh 参数1 参数2 参数3
'etiantian.sh 获取当前执行的shell脚本的文件名,包括脚本路径:' etiantian.sh
$n 获取当前执行的shell脚本的第n个参数值,n=..: $=参数1 $=参数2 $=参数3
$* 获取当前shell的所有参数 "$1 $2 $3...注意与$#的区别:参数1 参数2 参数3
$#:获取当前shell命令行中参数的总个数:
$@:这个程序的所有参数”$””$””$””...”: 参数1 参数2 参数3
$$ 获取当前shell的进程号(PID):
$!:执行上一个指令的PID:
$? 获取执行上一个指令的返回值:
$_:在此之前执行的命令或脚本的最后一个参数:
$n实例:
(1)$1,$2....$9${10}${11}
()$,$....$${}${}
[root@Web ~]# cat n.sh
echo $
[root@Web ~]# sh n.sh boy zhaoyang
boy
[root@Web ~]# sh n.sh "boy zhaoyang"
boy zhaoyang
提示:加引号括起来表示为一个参数
[root@Web ~]# cat n.sh
echo $ $
[root@Web ~]# sh n.sh boy zhanyang
boy zhanyang
[root@Web ~]# sh n.sh "boy zhanyang" luya
boy zhanyang luya
(2)$0取脚本的名称,包括路径
[root@Web ~]# cat n.sh
echo $
[root@Web ~]# sh n.sh
n.sh
提示:当要执行的脚本为全路径时$0也会带着路径。此时如果希望取出名称或路径,用下面的方法。
[root@Web ~]# cat dirname.sh
dirname $
[root@Web ~]# sh dirname.sh
.
[root@Web ~]# basename /etc/inittab
inittab
[root@Web ~]# cat .sh
dirname $
basename $
[root@Web ~]# sh .sh
.
.sh
$?实例
[root@Web ~]# su - zgy
[zgy@Web ~]$ ll
总用量
-rwxrw-r--. zgy zgy 4月 : test.sh
-rw-rw-r--. zgy zgy 4月 : testsource.sh
[zgy@Web ~]$ echo $? [zgy@Web ~]$ ll /root/
ls: 无法打开目录/root/: 权限不够
[zgy@Web ~]$ echo $? [zgy@Web ~]$ ddd
-bash: ddd: command not found
[zgy@Web ~]$ echo $? )编译软件的时候判断成功与否
make
make install
echo $?
练习:写一个脚本
给脚本传递两个参数(整数);
显示此两者之和,之乘积
#!/bin/bash
#
if [ $# -lt ]; then
echo "Usage: cacl.sh ARG1 ARG2"
exit
fi echo "The sum is: $[$1+$2]."
echo "The prod is: $[$1*$2]."
退出状态及其含义:
$?返回值参考:
退出状态及其含义 注释
表示运行成功,程序执行未遇到任何问题
~ 表示运行失败,脚本命令、系统命令错误或参数传递错误
找到该命令但无法执行
未找到要运行的命令
> 命令被系统强行结束
,, 系统预留
提示:在脚本调用,一般用exit 0,函数return 0.
解析:
:表示运行成功 :权限拒绝 ~:表示运行失败,脚本命令、系统命令错误或参数传递错误 :找到该命令了,但是无法执行 :未找到要运行的命令 >:命令被系统强制结束
提示:在脚本调用,一般用exit 0,函数return 0.
难点理论与实战剖析
$*和$@的区别
$*: 获取当前shell的所有参数,将所有的命令行所有参数视为单个字符串,等同于"$1$2$3"
$@:将命令行每个参数视为单独的字符串,等同于"$1"、"$2"、"$3"。这是将参数传递给其他程序的最佳方式,
因为它会保留所有内嵌在每个参数里的任何空白。
获取当前shell的所有参数,将所有的命令行参数视为单个字符
示例1:
[root@Web ~]# set -- "I am" handsome boy #传入三个参数
[root@Web ~]# echo $# [root@Web ~]# for i in $*;do echo $i;done #循环打印这些参数,用$*,无引号
I
am
handsome
boy
示例2:
[root@Web ~]# for i in $@;do echo $i;done #在没有双引号的情况下,这里的结果$*和$@是一样的
I
am
handsome
boy
[root@Web ~]# for i;do echo $i;done #去掉in变量列表,相当于in “$@”
I am
handsome
boy [root@Web ~]# for i in "$@";do echo $i;done #在有双引号的情况下,参数里引号内容当作一个参数输出了,这才符合我们真正的参数需求,set -- "I am" handsome oldboy.
I am
handsome
boy
[root@Web ~]# for i in "$*";do echo $i;done #加了双引号,$*表示一个字符串
I am handsome boy
[root@Web ~]# shift #用shift去掉第一个参数
[root@Web ~]# echo $# [root@Web ~]# for i in "$*";do echo $i;done #再次打印只剩下后面两个参数了
handsome boy
[root@Web ~]# for i in "$@";do echo $i;done
handsome
boy
其他:https://blog.51cto.com/oldboy/1175971
linux下set和eval的使用小案例精彩解答
linux下set和eval的使用小案例解答
本博文主要是讲解学生提出的如下一行命令脚本定义的真正内涵:
runlevel=$(set -- $(runlevel); eval "echo \$$#" )
以下是老男孩培训14期VIP群内的对话解答记录,内容已做过滤,有的网友以前反映过,说老男孩发的记录时间对不上,其实老男孩只是以对话问答的形式让大家掌握技术而已,内容是加工过的属正常,不要大惊小怪,给大家看的一定是最容易理解的对话过程,也尽量保持了原来的对话。
解答对话:
北京-刘同学() // ::
求问一些服务的启动脚本runlevel=$(set -- $(runlevel); eval "echo \$$#" ) 这个runlevel是怎么把这个运行级别的取到的 北京老男孩老师() ::
你敲一下runlevel看看。 北京-刘同学() ::
[root@G307 ~]# runlevel
N 北京老男孩老师() ::
后面的3就是运行级别 北京-刘同学() ::
啊,明白了,他是 $#= 然后 $=3是这样吧
老男孩老师点评:对。 北京-陶同学<DD@sina.com> ::
$# 获取当前shell命令行中参数的总个数
$n 获取当前执行的shell脚本的第n个参数值,n=,...,当n为0时表示脚本的文件名,如果n大于9,用大括号括起来${}
老男孩老师点评:这个同学说的是命令行脚本传参的内容,也适合本文。 北京-李灿() ::
eval对echo \$$#的双重扫描
假如要的参数不是最后一个 那么这个总数 就不准确了是吧
老男孩老师点评:对的。取最后一个才能这么用。 北京老男孩老师() ::
set 和eval的用法比较特殊,后期课程慢慢的给大家渗透,现在是学习的刚刚开始啊。
先给大家一个例子:
[root@oldboy ~]# set -- "I am" handsome oldboy. #==>传入三个参数
[root@oldboy ~]#
[root@oldboy ~]# echo $# #==>现在有三个参数 [root@oldboy ~]# for i in $*;do echo $i;done #==>循环打印这些参数,用$*,无引号
I
am
handsome
oldboy.
[root@oldboy ~]# for i in $@;do echo $i;done #==>在没有双引号的情况下,这里的结果$*和$@是一样的
I
am
handsome
oldboy. 北京老男孩老师() ::
上面是咱们老男孩培训后期课程教案里的一个例子 北京老男孩老师() ::
[root@oldboy ~]# set -- $(runlevel)
[root@oldboy ~]# echo $# [root@oldboy ~]# echo $(set $(runlevel); eval "echo $2" ) 刘同学同学你理解这个吧。这个会了,那个就差不多了 北京-刘同学() ::
恩,懂了 北京老男孩老师() ::
set可以像命令行一样设置传参,这个用法不多见!
了解就得,工作几乎不需要必须用它 北京-刘同学() ::
恩,好的 北京老男孩老师() ::
既然你懂了,我就在多说下,哈哈!
runlevel=$(set -- $(runlevel); eval "echo \$$#" )
)这里的$#就是参数个数为2,即runlevel的结果, 所以\$$#就是$,即runlevel结果的第二列3
[root@G307 ~]# runlevel
N
)eval就是把echo的字符串,当做命令解析!解答了这么多 其实知识含量已经非常多了。
可以写一篇博文了。 北京-李灿() ::
echo $ #输出括号内的值
(set $(runlevel); #将runlevel参数值,传入shell,N
eval "echo $2" ) #eval二次扫描,首先扫描到echo输出$,第二次解析$2的值为等级3
这样子吗?
bash内部变量
有些内部命令在目录列表时是看不见的,它们由shell本身提供,常见的内部命令有:
echo,eval,exec.export,readonly,read,shift,wait,exit和点(.)
echo 变量名表
将变量名表指定的变量显示到标准输出
evalargs
读入参数args,并将它们组合成一个新的命令,然后执行
exec 命令参数
当shell执行带exec语句时,不会去创建新的子进程,而是转去执行指定的命令,当指定的命令执行完后时,该进程(也就是最初的shell)就终止了,所以shell程序中exec后面的语句将不再被执行
export变量名=value
shell可以用export把它的便利向下带入子shell,从而让子进程继承父进程中的环境变量。但子shell不能用export把它的变量向上带入父shell。
readonly 变量名
只读变量 用readonly显示所有只读变量
read 变量名表
从标准输入读字符串,传给指定变量 可以在函数中用local变量名的方式申请局部变量
shift 语句
Shift语句按如下方式重命名所有的位置参数变量,即$2成为$,$3称为$...在程序中每使用一个shift语句,都使所以的位置参数一次向左移动一个位置,并使位置参数$#减1,直到减到0为止。
内部变量实践:
)shift命令实例 [root@Web ~]# cat n.sh echo $ $ if [ $# -eq ];then shift echo $ fi [root@Web ~]# sh n.sh #这里是echo $ $2的结果 #这里是echo $1的结果但是是传参时$2的值
查看变量值和撤销变量
显示变量值
通过echo命令打印环境变量
echo $变量名或echo ${变量名}
$:通过指定变量名称引用变量值
例子:
$HOME:用户登录时进入的目录
$UID:当前用户的UID(用户标识)相当于id -u
$PWD:当前工作目录的绝对路径名
$SHELL:当前SHELL
$USER:当前用户
.....省略若干
例子2:
[root@Web ~]# echo $USER
root
[root@Web ~]# echo $PWD
/root
[root@Web ~]# echo $UID [root@Web ~]# echo $SHELL
/bin/bash
提示:在写shell脚本时可以直接使用上面的系统默认的环境变量。
env(printenv)或set显示默认的环境变量
set | grep 变量名
env | grep 变量名 看不到自定义变量
用unset消除本地变量和环境变量
unset 变量名
例子:
[zgy@Web ~]$ echo $USER
zgy
[zgy@Web ~]$ unset USER
[zgy@Web ~]$ echo $USER
#此处为输出的空行
可以看到变量的内容显示为空了
本地变量在用户当前的shell生存期的脚本中使用。例如,本地变量OLDBOY取值为ett098,这个值只在用户当前shell生存期中有意义。如果在shell中启动另一个进程或退出,本地变量OLDBOY值将无效。
变量名的设置规则
由数字/字母/下划线组成,区分大小写
不能以数字开头
等号两边不要有空格
不要使用关键字和特殊字符
多次给同一个变量赋值时,最后的值生效
普通字符串变量定义
变量名=value 变量名='value' 变量名="value"
例1:下面的例子会输出什么结果。
a=192.168.1.2
b='192.168.1.2'
c="192.168.1.2"
echo "a=$a"
echo "b=$b"
echo "c=${c}"
提示:
1)$c和${c}在这里等同
2)需要在命令行实践以上内容
思考:想一想a,b,c各是什么结果
答案:
[zgy@Web ~]$ echo "a=$a"
a=192.168.1.2
[zgy@Web ~]$ echo "b=$b"
b=192.168.1.2
[zgy@Web ~]$ echo "c=${c}"
c=192.168.1.2
例2:想一想a,b,c各是什么结果?
a=192.168.1.2-$a
b='192.168.1.2-$a'
c="192.168.1.2-$a"
echo "a=$a"
echo "b=$b"
echo "c=${c}"
思考:再想一想a,b,c现在各是什么结果?为什么是这个结果?
zgy@Web ~]$ echo "a=$a"
a=192.168.1.2-192.168.1.2
[zgy@Web ~]$ echo "b=$b"
b=192.168.1.2-$a
[zgy@Web ~]$ echo "c=${c}"
c=192.168.1.2-192.168.1.2-192.168.1.2
提示:
1.第一种定义a变量的方式是直接定义变量内容,内容一般为简单连续的数字、字符串、路径名等。
2.第二种定义b变量的方式是通过单引号定义变量。这个方式的特点是:输出变量时引号里是什么就输出什么,即使内容中有变量也会把变量名原样输出。此法比较适合于定义显示纯字符串
3.第三种定义c变量方式是通过双引号定义变量。这个方式的特点是:输出变量时引号里的变量会经过解析后输出该变量内容,而不是把引号中变量名原样输出,适合于字符串中附带有变量的内容的定义。
习惯:数字不加引号,其他默认加双引号。
定义变量单引号、双引号与不加引号
有关单引号、双引号与不加引号的简要说明如下:
单引号:
可以说是所见即所得:即将单引号内的内容原样输出,或者描述为单引号里面看到的是什么就会输出什么。
双引号:
把双引号内的内容输出来;如果内容中有命令、变量等,会先把变量、命令解析出结果,然后再输出最终结果。
无引号:
把内容输出来,会将含有空格的字符串视为一个整体输出,如果内容中有命令、变量等,会先把变量、命令解析出结果,然后再输出最终结果来,
如果字符串中带有空格等特殊字符,则不能完整的输出,需要改加双引号,一般连续的字符串,数字,路径等可以不加任何引号,不过最好用双引号替代之。
单引号、双引号与不加引号实践演示:
范例1:经过反引号的`date`命令测试
[root@localhost ~]# echo '`date`' #单引号时看到什么就显示什么
`date`
[root@localhost ~]# echo "`date`" #双引号时如果里面是变量,会先把变量解析成具体内容在显示
2015年 04月 11日 星期六 :: CST [root@localhost ~]# echo `date` #对于连续的字符串等内容一般不加引号也可,加双引号一般比较保险,推荐
2015年 04月 11日 星期六 :: CST
范例2:变量定义后,调用时测试
[root@localhost ~]# ZGY=testchars #创建一个不带引号的变量
[root@localhost ~]# echo $ZGY #不加引号,显示一个变量解析的内容
testchars
[root@localhost ~]# echo '$ZGY' #单引号,显示一个变量本身
$ZGY
[root@localhost ~]# echo "$ZGY" #双引号,显示一个变量内容,引号内可以是变量、字符串等
testchars
范例3:grep过滤字符串例子
[root@localhost ~]# cat >grep.log
testchars
zgy
[root@localhost ~]# grep "$ZGY" grep.log
testchars
[root@localhost ~]# grep $ZGY grep.log
testchars
[root@localhost ~]# grep '$ZGY' grep.log
过滤双引号测试
[root@localhost ~]# cat >grep.log
\"
[root@localhost ~]# grep '\"' grep.log
\"
特殊例子:awk调用shell变量引号例子
[root@localhost ~]# ETT=
[root@localhost ~]# awk 'BEGIN{print '$ETT'}' [root@localhost ~]# awk 'BEGIN {print "$ETT"}'
$ETT
提示:以上的结果正好的前面的结论相反。这是awk调用shell变量的特殊用法
[root@localhost ~]# ETT='abc'
[root@localhost ~]# awk 'BEGIN {print "$ETT"}'
$ETT
[root@localhost ~]# awk 'BEGIN {print '$ETT'}' [root@localhost ~]# awk 'BEGIN {print "'$ETT'"}'
abc
提示:
这个例子更特殊了一点。
有关awk调用shell变量读者还可以参考http://blog.51cto.com/oldboy/760192
一道实用linux运维问题的9种shell解答方法
问题为:
)已知:/etc/hosts的内容为
192.168.1.11 oldboy11.etiantian.org
192.168.1.21 oldboy21.etiantian.org
192.168.1.31 oldboy31.etiantian.org
#192.168.1.111 oldboy111.etiantian.org
请用shell脚本实现,怎么才能在输入IP后找到/etc/hosts里对应的唯一的hostname?
解答:
法1)脚本过滤法 [root@old_boy scripts]# cat judgehost.sh
#!/bin/bash
echo "please input ip address:"
read ip
[ -n "`grep "$ip " /etc/hosts`" ] && \ #注意前面的过滤条件结尾带有空格。
echo "The hostname is: `grep "$ip " /etc/hosts |awk '{print $2}'`" || \
echo "The ip is invalid" 提示:
)这是一个grep过滤加条件判断的实现语法:
)条件判断语法为[ -n "ddd" ] && echo || echo
)[ -n "`grep "$ip " /etc/hosts`" ] && \ #注意前面的过滤条件结尾带有空格。这里啊,是为了排除下面的重复情况
192.168.1.11 oldboy11.etiantian.org
192.168.1.111 oldboy111.etiantian.org
----------------我是每种方法分隔符---------------
法2)脚本精确匹配法: #!/bin/bash
#author oldboy
#judge input
if [ $# -ne ]
then
echo "input error!"
exit
fi flag=
exec < /etc/hosts
while read line
do
if [ "$1" = "`echo $line|awk '{print $1}'`" ]
then
flag=
echo "the $1 's hostname is `echo $line|awk '{print $2}'`"
break;
fi
done
[ $flag -eq ] && echo " sorrry,not find $1 's hostname!" 提示:此题,请大家学习while的用法及设置flag的思路。
执行结果:
[root@old_boy scripts]# sh oldboy.sh 192.168.1.11
the 192.168.1.11 's hostname is oldboy11.etiantian.org
[root@old_boy scripts]# sh oldboy.sh 192.168.1.21
the 192.168.1.21 's hostname is oldboy21.etiantian.org
[root@old_boy scripts]# sh oldboy.sh 192.168.1.311
sorrry,not find 192.168.1.311 's hostname!
----------------我是每种方法分隔符--------------- 特别提示:下面的方法中,老男孩老师大量的使用了awk的不同方法来实现同样的功能,来告诉大家,awk是很强大的, 希望同学们能按照老师的教学要求精通之。 法3)awk精确匹配:
准备:
[root@old_boy scripts]# tail - /etc/hosts
192.168.1.11 oldboy11.etiantian.org
192.168.1.111 oldboy111.etiantian.org
192.168.1.21 oldboy21.etiantian.org
192.168.1.31 oldboy31.etiantian.org
脚本: [root@old_boy scripts]# cat awkhost1.sh
awk 'BEGIN {a="'$'"} {if($1==a) print $2; }' /etc/hosts 执行结果:
[root@old_boy scripts]# sh awkhost1.sh 192.168.1.21
oldboy21.etiantian.org
[root@old_boy scripts]# sh awkhost1.sh 192.168.1.31
oldboy31.etiantian.org
[root@old_boy scripts]# sh awkhost1.sh 192.168.1.11
oldboy11.etiantian.org
提示:注意a="'$1'"的用法,$1为命令行传参。awk程序中调用系统变量的方法a="'$1'"。
----------------我是每种方法分隔符---------------
法4)awk精确匹配法 [root@old_boy scripts]# cat awkhost2.sh
awk '{if($1=="'$'") print $2}' /etc/hosts 执行结果:
[root@old_boy scripts]# awkhost2.sh 192.168.1.11
oldboy11.etiantian.org
[root@old_boy scripts]# awkhost2.sh 192.168.1.21
oldboy21.etiantian.org
[root@old_boy scripts]# awkhost2.sh 192.168.1.311
----------------我是每种方法分隔符---------------
法5)awk过滤法 [root@old_boy scripts]# cat awkhost4.sh
awk '/'"${1} "'/''{print $2}' /etc/hosts
执行结果:
[root@old_boy scripts]# awkhost4.sh 192.168.1.21
oldboy21.etiantian.org
[root@old_boy scripts]# awkhost4.sh 192.168.1.11
oldboy11.etiantian.org
[root@old_boy scripts]# awkhost4.sh 192.168.1.31
oldboy31.etiantian.org
提示:除了语法外,这道题有个学问,就是过滤时传参结尾要带个空格,这样才能过滤重复IP的情况
如:
192.168.1.11 oldboy11.etiantian.org
192.168.1.111 oldboy111.etiantian.org ----------------我是每种方法分隔符---------------
法6)awk过滤法 [root@old_boy scripts]# cat awkhost5.sh
awk '{if($1~/'$'/) print $2}' /etc/hosts ##如果文件第一列包含命令行第一个参数字符则打印第二列
执行结果:
[root@old_boy scripts]# awkhost5.sh 192.168.1.31
oldboy31.etiantian.org
[root@old_boy scripts]# awkhost5.sh 192.168.1.11
oldboy11.etiantian.org
oldboy111.etiantian.org ------>这里有bug了。
[root@old_boy scripts]# awkhost5.sh 192.168.1.21
oldboy21.etiantian.org
改进下来排除bug:
[root@old_boy scripts]# cat awkhost5-.sh
awk '{if($1~/'$' /) print $2}' /etc/hosts ==>用上面加空格的思路不对。
[root@old_boy scripts]# cat awkhost5-.sh
awk '{if($1~/'$'$/) print $2}' /etc/hosts #增加一个正则表达式$
执行结果:
[root@old_boy scripts]# awkhost5-.sh 192.168.1.21
oldboy21.etiantian.org
[root@old_boy scripts]# awkhost5-.sh 192.168.1.11
oldboy11.etiantian.org
[root@old_boy scripts]# awkhost5-.sh 192.168.1.31
oldboy31.etiantian.org ----------------我是每种方法分隔符---------------
法7)awk -v精确匹配法 命令行测试:
[root@old_boy scripts]# awk -v p=192.168.1.21 '$1 == p{print $2}' /etc/hosts
oldboy21.etiantian.org
[root@old_boy scripts]# awk -v p=192.168.1.11 '$1 == p{print $2}' /etc/hosts
oldboy11.etiantian.org
[root@old_boy scripts]# awk -v p=192.168.1.11 '$1 == p {print $2}' /etc/hosts
oldboy11.etiantian.org
实际脚本:
[root@old_boy scripts]# cat awkhost6.sh
#!/bin/bash
#p=$
#awk -v p="$p" '$1 == p{print $2}' /etc/hosts
awk -v p="$1" '$1 == p{print $2}' /etc/hosts 执行结果:
[root@old_boy scripts]# sh awkhost6.sh 192.168.1.11
oldboy11.etiantian.org
[root@old_boy scripts]# sh awkhost6.sh 192.168.1.21
oldboy21.etiantian.org
提示:
)传参非awk程序,因此写法p="$1"
)man awk
-v var=val
--assign var=val
Assign the value val to the variable var, before execution of the program begins. Such vari-
able values are available to the BEGIN block of an AWK program.
----------------我是每种方法分隔符---------------
法8:精确匹配简单的写法 [root@old_boy scripts]# cat awkhost9.sh
awk '$1 == "'$'" {print $2}' /etc/hosts
执行结果:
[root@old_boy scripts]# sh awkhost9.sh 192.168.1.11
oldboy11.etiantian.org
[root@old_boy scripts]# sh awkhost9.sh 192.168.1.21
oldboy21.etiantian.org
[root@old_boy scripts]# sh awkhost9.sh 192.168.1.31
oldboy31.etiantian.org
特别提示:这里老男孩老师大量的使用了awk的不同方法来实现同样的功能,很强大吧,
希望同学们能按照老师的教学要求精通之。 ----------------我是每种方法分隔符---------------
法9:学生的一个不成熟的实现法 #!/bin/bash
b=/$PWD/wang.txt
echo -n "plase input ip : "
read a
if [ $a == "192.168.1.11" ]
then
cat $b | grep $a | awk -F ' ' '{print $2}' elif [ $a == "192.168.1.21" ]
then
cat $b | grep $a | awk -F ' ' '{print $2}' elif [ $a == "192.168.1.31" ]
then
cat $b | grep $a | awk -F ' ' '{print $2}'
else
echo "plase input the correct IP address " && exit
fi
提示:大家看看问题在哪?脚本不通用。 ------老男孩老师改进后 #!/bin/bash
#author oldboy
hosts_file="$PWD/oldboy.txt"
#judge file
[ ! -f $hosts_file ] && echo "no test file!" && exit
echo -n "plase input ip : "
read ip
#judge ip format
[ "${#a}" -lt ] && [ "`echo $ip|sed 's/[0-9]//g'`" != "..." ] && \
echo "Plase input the correct IP address" && exit #start
result1=$(grep "$ip" $hosts_file|awk '{print $1}')
if [ "$ip" == "$result1" ]
then
grep "$ip" $hosts_file|awk '{print $2}'
exit
else
echo "Not find the hostname of $ip"
exit
fi
提示:此法不可取,画蛇添足了。
自定义变量的建议
自定义变量的建议:
(1)纯数字(不带空格),定义方式可以不加引号(单或双),例如:
A.oldboy=33
B.NETWORKING=yes
(2)没特殊情况,字符串一般用双引号定义,特别是多个字符串中间有空格时,例如:
A.NFSD_MODULE="no load" B.MyName="Oldboy is a handsome boy."
(3)变量内容需要原样输出时,要用单引号('')。
A.OLDBOY_NAME='OLDBOY'
变量的命名规范
1)变量命名要统一,使用全部大写字母,如APACHE_ERR_NUM;语义要清晰,能够正确表达变量内容的含义,过长的英文单词可采用前几个字符代替。多个单词连接使用”_”号连接,引用时,最好以${APACHE_ERR_NUM}加大括号或”${APACHE_ERR_NUM}”外面加双引号方式引用变量:
2)避免无含义字符或数字:例如下面的COUNT,并不知道其确切含义;
范例1:COUNT的不确切定义
COUNT=`grep keywords file` if [ ${COUNT} -ne ] then Echo ‘Do Something’ fi
3)全局变量和局部变量命名
A.脚本中的全局变量定义,如OLDBOY_HOME或OLDBOYHOME,在变量使用时,使用{}将变量括起或”${OLDBOY_HOME}”
范例2:操作系统函数库脚本内容全局变量截取例子
[root@Web ~]# cat /etc/init.d/functions # -*-Shell-script-*- # # functions This file contains functions to be used by most or all # shell scripts in the /etc/init.d directory. # TEXTDOMAIN=initscripts
B.脚本中局部变量定义:存在于脚本函数(function)中的变量称为局部变量,要以local方式进行声明,使之只在本函数作用域内有效,防止变量在函数中的命名与变量外部程序中变量重名造成持续异常。下面是函数中的变量定义例子:
范例3:函数内的变量定义
Function TestFunc() { local i for((i=;i<n;i++)) do echo ‘do something’ done }
范例4:操作系统函数库脚本内容局部函数变量截取例子
# Check if any of $pid (could be plural) are running checkpid() { local i for i in $* ; do [ -d "/proc/$i" ] && return done return }
4)变量合并:当某些变量或配置项要组合起来才有意义时,如文件的路径和文件名称,建议将要组合的变量合并到一起赋值给一个新的变量,这样既方便之后的调用,也为以后进行修改提供了方便。
范例5:自动化安装httpd的脚本变量合并定义
VERSION="2.2.22" SOFTWARE_NAME="httpd" SOFTWARE_FILENAME="${SOFTWARE_NAME}-${VERSION}.tar.gz"
5)变量定义总结:多学习模仿操作系统自带的/etc/init.d/functions函数库脚本的定义思路。
扩展赋值操作
三种定界符 注释
双引号"" 允许扩展,通过$引用其他变量
单引号'' 禁用扩展,即便$也视为普通字符
反撇号`` 将命令的执行输出作为变量值 #执行命令本身的功能,$()与``等效,但$()更方便嵌套使用
命令替换:
$(COMMAND), 反引号:`COMMAND`
例子:把命令中某个子命令替换为其执行结果的过程
touch ./file-$(date +%F-%H-%M-%S).txt
rootdata=`df -h | grep /dev/sda2 | awk '{print $4}' | awk -F"G" '{print $1}'`
写一个脚本,分别显示当前系统上所有默认shell为bash的用户和默认shell为/sbin/nologin的用户,并统计各类shell下的用户总数。显示结果形如:
BASH,3users,they are:
root,redhat,gentoo
NOLOGIN, 2users, they are:
bin,ftp
实现脚本:
#!/bin/bash
#
NUMBASH=`grep "bash$" /etc/passwd | wc -l`
BASHUSERS=`grep "bash$" /etc/passwd | cut -d: -f1`
BASHUSERS=`echo $BASHUSERS | sed 's@[[:space:]]@,@g'` echo "BASH, $NUMBASH users, they are:"
echo "$BASHUSERS
例子:
[root@Web ~]#ls
test.sh
[root@Web ~]#CMD=`ls`
[root@Web ~]#echo $CMD
test.sh
[root@Web ~]#CMD1=$(pwd)
[root@Web ~]#echo $CMD1
/root
提示:
、"CMD=`ls`"注意命令变量前后的字符``
、在变量名前加$,可以取得此变量的值,使用echo命令可以显示变量的值,$A和${A}的写法不同,但功能是一样的,推荐使用后者的语法或"${A}"的用法。
、${WEEK}day若变量和其他字符组成新的变量就必须给变量加上大括号。
、养成将所有字符串变量用双引号括起来使用的习惯,将会减少很多编程时遇到的怪异的错误。具体使用方法如:"$A"或"${A}"的语法
生产环境常见应用:
1.对站点按天打包生成不同的文件名
[root@Web ~]# CMD=$(date +%F)
[root@Web ~]# echo $CMD
--
[root@Web ~]# echo $(date +%F).tar.gz
--.tar.gz
[root@Web ~]# H=$(uname -n)
[root@Web ~]# echo $H
Web
[root@Web ~]# tar zcf $H.tar.gz /etc/services
tar: 从成员名中删除开头的“/” #切换到目录下打包就不会出现这种情况
[root@Web ~]# ll Web.tar.gz
-rw-r--r--. root root 4月 : Web.tar.gz
命令的逻辑分隔
分隔符 含义
&& 前边命令执行成功了后边的命令才执行,若前边的命令执行失败后边的命令不执行
; 顺序执行命令 前边命令执行是否成功不影响后边命令的执行
|| 只有当左侧的命令执行失败时,右侧的命令才会执行
从标准输入赋值
语法:read从键盘读入变量值完成赋值
read 选项 变量值
参数选项
参数选项 注释
read [-p "提示信息"] 变量名
-p可选
-t 可指定超时秒数
终端显示控制
注释
-stty -echo 关闭终端输出(无显示)
-stty echo 恢复终端输出(显示)
变量的作用范围
局部变量
新定义的变量默认只在当前Shell环境中有效
无法在子Shell环境中使用
定义本地变量
本地变量在用户当前的shell生存期的脚本中使用。例如,本地变量ZGY取值为ett098,这个值只在用户当前shell生存期中有意义。如果在shell中启动另一个进程或退出,本地变量ZGY值将无效。
1.普通字符串变量定义
变量名=value
变量名='value'
变量名="value"
shell中变量名的要求:一般是字母,数字,下划线组成。字母开头。
全局变量
全局变量在当前Shell及子Shell环境中均有效
使用export可将局部变量声明为全局变量
export
注释
export 局部变量名[=变量值] 为局部变量添加全局属性
export -n 全局变量名 取消指定变量的全局属性
当变量被定义为全局变量后,变量能在当前的Shell和当前Shell的子Shell里使用。
站在用户登录的角度来说,SHELL的类型:
登录式shell:
正常通过某终端登录
su - USERNAME
su -l USERNAME
非登录式shell:
su USERNAME
图形终端下打开命令窗口
自动执行的shell脚本
bash的配置文件:
全局配置
/etc/profile
/etc/profile.d/*.sh
/etc/bashrc
个人配置
~/.bash_profile
~/.bashrc
profile类的文件:
设定环境变量
运行命令或脚本
bashrc类的文件:
设定本地变量
定义命令别名
登录式shell如何读取配置文件?
/etc/profile --> /etc/profile.d/*.sh --> ~/.bash_profile --> ~/.bashrc --> /etc/bashrc
非登录式shell如何配置文件?
~/.bashrc --> /etc/basrc --> /etc/profile.d/*.sh
登录式shell,配置文件及次序:
/etc/profile --> /etc/profile.d/*.sh --> ~/.bash_profile --> ~/.bashrc --> /etc/bashrc
非登录式shell:
~/.bashrc --> /etc/bashrc --> /etc/profile.d/*.sh
系统级配置文件对所有用户生效
/etc/profile
/etc/bashrc
用户级配置文件只针对用户生效(只针对某个用户生效。在这样的文件里配置可以执行脚本、定义变量、执行命令)
~/.bash_profile
~/.bashrc
图形模式 每打开一个新的终端时会调用哪些文件
/etc/bashrc
~/.bashrc
二、Shell变量的更多相关文章
- Shell基础学习(二) Shell变量
1.数据类型: 字符串 数组 2.变量的命名规范: 只能以a-z或A-Z开头 中间不能有空格,可以使用_ 不能使用标点符号 不能使用shell的关键字 3.变量类型: 环境变量 局部变量 shell变 ...
- shell基础篇(二)-shell变量
1. 定义变量 1).定义变量时,变量名不加美元符号($),如: var="hello world"2).注意,变量名和等号之间不能有空格,这可能和你熟悉的所有编程语言都不一样.同 ...
- Shell脚本笔记(二)Shell变量
Shell变量 一)全局环境变量 全局变量对于定义它的shell和其子shell都是可见的,但如果生成它的shell被终止,全局变量也就消失了.另外全局变量会被子shell的同名变量覆盖. #定义一个 ...
- Shell学习(二)Shell变量
一.Shell变量 变量的定义 例子: my_job="Learn Shell" PS:变量名和等号之间不能有空格!!! 命名只能使用英文字母,数字和下划线,首个字符不能以数字开头 ...
- 【转】shell学习笔记(二) ——shell变量
在shell中有3种变量:系统变量,环境变量和用户变量,其中系统变量在对参数判断和命令返回值判断时会使用,环境变量主要是在程序运行时需要设置,用户变量在编程过程中使用量最多. 1 系统变量 变量名 ...
- shell 基础(二)变量
1. shell变量的定义 1)Shell 支持以下三种定义变量的方式: variable=value variable='value' variable="value" 特点 1 ...
- Shell脚本编程(二):shell变量
定义变量 定义变量时,变量名不加美元符号($,PHP语言中变量需要),如: your_name="runoob.com" 注意,变量名和等号之间不能有空格,这可能和你熟悉的所有编程 ...
- 学习Shell(二)变量
如何给shell脚本传入参数 1.执行“vi test.sh”创建一个新的shell脚本. vi test.sh 2.脚本test.sh的内容如下: #!/bin/sh name=$ echo &qu ...
- 二、Shell 变量
Shell 变量 定义变量时,变量名不加美元符号($,PHP语言中变量需要),如: your_name="runoob.com" 注意,变量名和等号之间不能有空格,这可能和你熟悉的 ...
随机推荐
- 美国权威媒体CRN预测:2020年值得关注的10个新兴云计算趋势
云计算在过去一年里极速发展,其速度之快,让人难以预测未来会发生什么.即使依照这些趋势而新发明的技术在不断变化并且极其脆弱,而推动这些趋势和技术不断发展的企业和组织最终也很有可能发生变化,但不妨碍这些大 ...
- Vue-cli2.0
本文的学习来自技术胖大神的教程:https://jspang.com/ Vue-cli是vue官方出品的快速构建单页应用的脚手架 开发一个项目,在开始的时候,会构建项目结构.webpack.怎么运行. ...
- 跌宕起伏的java帝国史,剖析谷歌甲骨文长达8年的版权战争
这篇博文是我在B站上发的一个科普java的视频文案整理,本来发过一次了,但是有几种不严谨的地方只能删掉重新发了一下,内容如标题,感兴趣的码农朋友可以观看视频的版本,欢迎提提意见啥的,感谢~https: ...
- 1059 C语言竞赛 (20 分)C语言
C 语言竞赛是浙江大学计算机学院主持的一个欢乐的竞赛.既然竞赛主旨是为了好玩,颁奖规则也就制定得很滑稽: 0.冠军将赢得一份"神秘大奖"(比如很巨大的一本学生研究论文集--). 1 ...
- Linux网络管理之多网卡绑定
一.bonding介绍 在企业Linux服务器管理里中,服务器的可靠性.可用性以及I/O速度都非常重要,保持服务器的高可用和安全性是生产环境的重要指标,其中最重要的一点是服务器网络连接的高可用性.通常 ...
- 830. String Sort
830. String Sort 题解 int alpha[256] = {0};//记录字符的次数 bool cmp(char a,char b) { if(alpha[a]==alpha[b])/ ...
- 抽象工厂模式(C++)
#include <iostream> using namespace std; class Fruit { public: ; }; class AbstractFactory { pu ...
- C语言之数组用法总结
一维数组的定义:1.数组的数据类型:每一元素占内存空间的字节数.2.数组的存储类型:内存的动态. 静态存储区或CPU的寄存器.3.一维数组在内存中占用的字节数为:数组长度X sizeof (基类型). ...
- 微信授权流程和JSSDK调用流程
概念理解 业务域名:当前业务使用的是哪个网站,好处:设置业务域名后,在微信内访问该域名下页面时,不会被重新排版.不出现“防欺诈盗号,请误支付或输入qq密码”的提示,微信认为该域名是安全的,客户也不觉得 ...
- pom文件继承与聚合
1.简介 pom.xml文件是Maven进行工作的主要配置文件.在这个文件中我们可以配置Maven项目的groupId.artifactId和version等Maven项目必须的元素:可以配置Mave ...