Shell编程之变量进阶
一、变量知识进阶
1.特殊的位置参数变量

实例1:测试$n(n为1...15)
[root@codis-178 ~]# cat p.sh
echo $1
[root@codis-178 ~]# sh p.sh oldboy
oldboy
[root@codis-178 ~]# sh p.sh oldboy oldgirl
oldboy
[root@codis-178 ~]# sh p.sh "oldboy oldgirl"
oldboy oldgirl
实例2:在脚本中同时加入$1和$2
[root@codis-178 ~]# cat p.sh
echo $1 $2
[root@codis-178 ~]# sh p.sh longge bingbing
longge bingbing
[root@codis-178 ~]# sh p.sh "longge bingbing" oldgirl
longge bingbing oldgirl
实例3:设置15个位置参数
[root@codis-178 ~]# echo \${1..15}
$1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 $14 $15
[root@codis-178 ~]# cat n.sh
echo $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 $14 $15
[root@codis-178 ~]# echo {a..z}
a b c d e f g h i j k l m n o p q r s t u v w x y z
[root@codis-178 ~]# sh n.sh {a..z}
a b c d e f g h i a0 a1 a2 a3 a4 a5
# 位置参数大于9,输出内容就不对了
# 数字大于9时,需要大括号将数字括起来
[root@codis-178 ~]# cat n.sh
echo $1 $2 $3 $4 $5 $6 $7 $8 $9 ${10} ${11} ${12} ${13} ${14} ${15}
[root@codis-178 ~]# sh n.sh {a..z}
a b c d e f g h i j k l m n o
实例4:获取脚本的名称及路径
[root@codis-178 ~]# cat n.sh
echo $0
# 不带路径时为脚本名
[root@codis-178 ~]# sh n.sh
n.sh
# 全路径执行时为路径加脚本名
[root@codis-178 ~]# sh /data/cron/n.sh
/data/cron/n.sh
实例5:dirname和basename的用法
[root@codis-178 ~]# dirname /data/cron/n.sh
/data/cron
[root@codis-178 ~]# basename /data/cron/n.sh
n.sh
实例6:利用$0和dirname、basename分别取脚本名称和路径
[root@codis-178 ~]# cat /data/cron/n.sh
dirname $0
basename $0
[root@codis-178 ~]# sh /data/cron/n.sh
/data/cron
n.sh
实例7:生产环境中的脚本使用说明
[root@codis-178 ~]# cat /data/cron/n.sh
echo $"Usage: $0 {start|stop|status|restart|reload}"
[root@codis-178 ~]# sh /data/cron/n.sh
Usage: /data/cron/n.sh {start|stop|status|restart|reload}
实例8:通过$#获取脚本传参的个数
[root@codis-178 ~]# cat n.sh
echo $1 $2 $3 $4 $5 $6 $7 $8 $9
echo $#
[root@codis-178 ~]# sh n.sh {a..z}
a b c d e f g h i
26
实例9:根据用户在命令行的传参个数判断用户的输入,不合要求的给予提示并退出
[root@codis-178 ~]# cat t1.sh
[ $# -ne 2 ] && {
echo "must two args"
exit 1
}
echo oldgirl
[root@codis-178 ~]# sh t1.sh
must two args
[root@codis-178 ~]# sh t1.sh arg1 arg2
oldgirl
# 改良版
[root@codis-178 ~]# cat t2.sh
if [ $# -ne 2 ]
then
echo "USAGE:/bin/sh $0 arg1 arg2"
exit 1
fi
echo $1 $2
[root@codis-178 ~]# sh t2.sh
USAGE:/bin/sh t2.sh arg1 arg2
[root@codis-178 ~]# sh t2.sh oldboy oldgirl
oldboy oldgirl
实例10:利用set设置位置参数,测试$#和$@
# 设置三个字符串参数,--表示清除所有参数变量,重新设置后面的参数变量
[root@codis-178 ~]# set -- "I am" handsome oldboy
[root@codis-178 ~]# echo $#
3
[root@codis-178 ~]# echo $1
I am
[root@codis-178 ~]# echo $2
handsome
[root@codis-178 ~]# echo $3
oldboy
# 不带双引号
[root@codis-178 ~]# echo $*
I am handsome oldboy
[root@codis-178 ~]# echo $@
I am handsome oldboy
[root@codis-178 ~]# for i in $*;do echo $i;done
I
am
handsome
oldboy
[root@codis-178 ~]# for i in $@;do echo $i;done
I
am
handsome
oldboy
# 带双引号
[root@codis-178 ~]# echo "$*"
I am handsome oldboy
[root@codis-178 ~]# echo "$@"
I am handsome oldboy
[root@codis-178 ~]# for i in "$*";do echo $i;done # 当做一个参数
I am handsome oldboy
[root@codis-178 ~]# for i in "$@";do echo $i;done # 每个参数独立输出
I am
handsome
oldboy
实例11:生产环境中的引用,分析以下语句含义runlevel=$(set -- $(runlevel); eval "echo $$#" )
# set是设置参数,这里设置的是runlevel的返回值作为参数
# runlevel命令拿到运行级别
[root@codis-178 ~]# runlevel
N 3
# $#是取命令有几个参数,上面的命令有2个返回参数
# \$$#,就是$2,因为$#=2
# eval是对之后的命令进行二次扫描,把echo的字符串,当做命令解析,首先扫描到echo输出$2,第二次解析$2的值为等级3
2.特殊的状态变量

实例1:执行命令后获取返回值
# 不同命令的执行结果中的返回值也不相同,0为成功,非0为失败
[root@codis-178 ~]# pwd
/root
[root@codis-178 ~]# echo $?
0
[root@codis-178 ~]# ls /eee
ls: cannot access /eee: No such file or directory
[root@codis-178 ~]# echo $?
2
[root@codis-178 ~]# oldboy
-bash: oldboy: command not found
[root@codis-178 ~]# echo $?
127
实例2:根据返回值来判断软件的安装步骤是否成功
[root@codis-178 fping-3.10]# ./configure prefix=/usr/local/fping
...略过部分过程
configure: creating ./config.status
config.status: creating Makefile
config.status: creating doc/Makefile
config.status: creating src/Makefile
config.status: creating config.h
config.status: executing depfiles commands
[root@codis-178 fping-3.10]# echo $?
0
[root@codis-178 fping-3.10]# make
...略过部分过程
make[2]: Leaving directory `/root/fping-3.10'
make[1]: Leaving directory `/root/fping-3.10'
[root@codis-178 fping-3.10]# echo $?
0
[root@codis-178 fping-3.10]# make install
...略过部分过程
make[2]: Leaving directory `/root/fping-3.10'
make[1]: Leaving directory `/root/fping-3.10'
[root@codis-178 fping-3.10]# echo $?
0
实例3:通过获取$?的返回值确定网站备份是否正确
[root@codis-178 ~]# tar czvf /root/fping-3.10.tar.gz ./fping-3.10
...略过部分过程
./fping-3.10/config.guess
./fping-3.10/config.h
[root@codis-178 ~]# echo $?
0
实例4:通过脚本控制命令及脚本执行后的返回值
[root@codis-178 ~]# cat test4.sh
[ $# -ne 2 ] && {
echo "must be two args."
exit 119 # 终止程序运行并指定119状态值赋值给$?
}
echo oldgirl
[root@codis-178 ~]# sh test4.sh
must be two args.
[root@codis-178 ~]# echo $?
119
[root@codis-178 ~]# sh test4.sh a1 a2
oldgirl
[root@codis-178 ~]# echo $?
0
在生产环境中的用法总结:
- 判断命令、脚本、函数等程序是否执行成功
- 若在脚本中调用执行"exit 数字",则会返回这个数字给"$?"变量
- 如果是在函数里,则通过"return 数字"把这个数字以函数返回值的形式传给"$?"
实例5:获取脚本执行的进程号
[root@codis-178 ~]# cat test_pid.sh
echo $$ > /tmp/a.pid
sleep 60
[root@codis-178 ~]# sh test_pid.sh &
[1] 1733
[root@codis-178 ~]# ps -ef |grep test_pid|grep -v grep
root 1733 28243 0 14:44 pts/0 00:00:00 sh test_pid.sh
[root@codis-178 ~]# cat /tmp/a.pid
1733
实例6:实现系统中多次执行某一个脚本后的进程只有一个
[root@codis-178 ~]# cat pid.sh
#!/bin/sh
pidpath=/tmp/a.pid
if [ -f "$pidpath" ]
then
kill `cat $pidpath` > /dev/null 2>&1
rm -f $pidpath
fi
echo $$ > $pidpath
sleep 60
[root@codis-178 ~]# sh pid.sh &
[1] 4142
[root@codis-178 ~]# ps -ef |grep pid.sh|grep -v grep
root 4142 28243 0 15:27 pts/0 00:00:00 sh pid.sh
[root@codis-178 ~]# sh pid.sh &
[2] 4158
[root@codis-178 ~]#
[1]- Terminated sh pid.sh
[root@codis-178 ~]# ps -ef |grep pid.sh|grep -v grep
root 4158 28243 0 15:27 pts/0 00:00:00 sh pid.sh
实例7:$_获取上一条命令的最后一个参数
[root@codis-178 ~]# /etc/init.d/ntpd start oldboy
Starting ntpd: [ OK ]
[root@codis-178 ~]# echo $_
oldboy
[root@codis-178 ~]# /etc/init.d/ntpd stop oldgirl
Shutting down ntpd: [ OK ]
[root@codis-178 ~]# echo $_
oldgirl
实例8:$!获取上一次执行脚本的pid
[root@codis-178 ~]# ps -ef |grep pid.sh|grep -v grep
[root@codis-178 ~]# sh pid.sh &
[1] 4439
[root@codis-178 ~]# echo &!
[2] 4450
[root@codis-178 ~]# ps -ef |grep pid.sh|grep -v grep
root 4439 28243 0 15:31 pts/0 00:00:00 sh pid.sh
二、Shell内置变量命令
1.常用的内部命令
echo、eval、exec、export、read、shift
2.内部命令用法
(1)echo:在屏幕输出信息

示例:
[root@codis-178 ~]# echo oldboy;echo oldgirl
oldboy
oldgirl
[root@codis-178 ~]# echo -n oldboy;echo oldgirl
oldboyoldgirl
[root@codis-178 ~]# echo "oldboy\toldgirl\noldboy\toldgirl"
oldboy\toldgirl\noldboy\toldgirl
[root@codis-178 ~]# echo -e "oldboy\toldgirl\noldboy\toldgirl"
oldboy oldgirl
oldboy oldgirl
[root@codis-178 ~]# printf "oldboy\toldgirl\noldboy\toldgirl"
oldboy oldgirl
oldboy oldgirl
[root@codis-178 ~]# echo -e "1\b23"
23
[root@codis-178 ~]# printf "1\b23"
23
(2)eval:当Shell执行到eval语句时,读入参数args,并将它们组合成一个新的命令执行
示例:
[root@codis-178 ~]# cat noeval.sh
echo \$$#
[root@codis-178 ~]# sh noeval.sh arg1 arg2
$2
[root@codis-178 ~]# cat noeval.sh
eval "echo \$$#"
[root@codis-178 ~]# sh noeval.sh arg1 arg2
arg2
# 使得打印的特殊位置参数重新解析输出,而不是$2
(3)exec:在不创建新的子进程的前提下,转去执行指定的命令,当命令执行完后,该进程终止
示例:
[root@codis-178 ~]# exec date
Wed Jul 12 15:46:37 CST 2017
[xiaoda@codis-178 ~]$
# 退到普通用户下
# exec打开文件后,read每次将文件指针移动到下一行进行读取,直到文件末尾
[xiaoda@codis-178 ~]$ seq 5 > /tmp/tmp.log
[xiaoda@codis-178 ~]$ cat exec.sh
exec < /tmp/tmp.log
while read line
do
echo $line
done
echo ok
[xiaoda@codis-178 ~]$ sh exec.sh
1
2
3
4
5
ok
(4)read:从标准输入读取字符串等信息,传给Shell内部定义的变量
(5)shift:每使用一次,会使所有位置参数依次向左移动一个位置,并使$#减1,直到0为止
示例:
[root@codis-178 ~]# cat n.sh
echo $1 $2
if [ $# -eq 2 ];then
shift
echo $1
fi
[root@codis-178 ~]# sh n.sh 1111 2222
1111 2222
2222
应用场景:
当shell命令行的命令通过参数控制不同的功能时,例如sh shift.sh -c oldboy,我们就拿到了第二个参数
(6)exit:退出Shell程序,可在后面指定一个数位作为返回值
三、Shell变量子串
1.子串介绍


2.子串的实践
# 定义一个变量
[root@codis-178 ~]# OLDBOY="I am oldboy"
[root@codis-178 ~]# echo ${OLDBOY}
I am oldboy
[root@codis-178 ~]# echo $OLDBOY
I am oldboy
# 返回变量值得长度
[root@codis-178 ~]# echo ${#OLDBOY}
11
# 截取变量内容,也可理解为删除前面的多个字符
[root@codis-178 ~]# echo ${OLDBOY:2}
am oldboy
[root@codis-178 ~]# echo ${OLDBOY:3}
m oldboy
[root@codis-178 ~]# echo ${OLDBOY:4}
oldboy
[root@codis-178 ~]# echo ${OLDBOY:2:2}
am
[root@codis-178 ~]# echo ${OLDBOY:2:5}
am ol
# 从变量内容的开头删除最短匹配"a*C"以及"a*c"的子串
[root@codis-178 ~]# echo ${OLDBOY#a*C}
123ABCabc
[root@codis-178 ~]# echo ${OLDBOY#a*c}
ABC123ABCabc
# 从变量内容的开头删除最长匹配"a*C"以及"a*c"的子串
[root@codis-178 ~]# echo ${OLDBOY##a*C}
abc
[root@codis-178 ~]# echo ${OLDBOY##a*c}
# 从变量内容的结尾删除最短匹配"a*C"以及"a*c"的子串
[root@codis-178 ~]# echo ${OLDBOY%a*C}
abcABC123ABCabc
[root@codis-178 ~]# echo ${OLDBOY%a*c}
abcABC123ABC
# 从变量内容的结尾删除最长匹配"a*C"以及"a*c"的子串
[root@codis-178 ~]# echo ${OLDBOY%%a*C}
abcABC123ABCabc
[root@codis-178 ~]# echo ${OLDBOY%%a*c}
# 用oldgirl代替变量中匹配oldboy的子串
[root@codis-178 ~]# echo ${OLDBOY/oldboy/oldgirl} # 替换第一个子串
I am oldgirl,yes,oldboy
[root@codis-178 ~]# echo ${OLDBOY//oldboy/oldgirl} # 全部替换
I am oldgirl,yes,oldgirl
3.子串在生产环境中的应用
去掉下面所有文件的文件名中的_finished字符串
[root@codis-178 log]# ls -l *.log
-rw-r--r-- 1 root root 0 Jul 12 16:29 stu_102999_1_finished.log
-rw-r--r-- 1 root root 0 Jul 12 16:29 stu_102999_2_finished.log
-rw-r--r-- 1 root root 0 Jul 12 16:29 stu_102999_3_finished.log
-rw-r--r-- 1 root root 0 Jul 12 16:29 stu_102999_4_finished.log
-rw-r--r-- 1 root root 0 Jul 12 16:29 stu_102999_5_finished.log
[root@codis-178 log]# for f in `ls *fin*.log`;do mv $f `echo ${f//_finished/}`;done
[root@codis-178 log]# ls -l *.log
-rw-r--r-- 1 root root 0 Jul 12 16:29 stu_102999_1.log
-rw-r--r-- 1 root root 0 Jul 12 16:29 stu_102999_2.log
-rw-r--r-- 1 root root 0 Jul 12 16:29 stu_102999_3.log
-rw-r--r-- 1 root root 0 Jul 12 16:29 stu_102999_4.log
-rw-r--r-- 1 root root 0 Jul 12 16:29 stu_102999_5.log
进阶版1:
ls |awk -F 'finished' '{print "mv "$0" "$1$2" "}'|/bin/bash
进阶版2:
rename "_finished" "" *
说明:
1)${f//_finished/}利用变量子串替换功能把变量$f里的finished替换为空
2)利用for循环依次拿到文件名
3)利用mv命令修改,注意目标命令要用反引号括起来
面试题:
编写Shell脚本以打印下面语句中字符数小于6的单词
I am oldboy linux,welcome to our training.
四、特殊扩展变量
1.特殊扩展变量介绍

2.特殊扩展变量实践
# ${parameter:-word}作用是如果parameter变量值为空或未赋值,则返回word字符串替代变量的值
[root@codis-178 log]# echo $test
[root@codis-178 log]# result=${test:-UNSET}
[root@codis-178 log]# echo $result
UNSET
[root@codis-178 log]# test=oldboy
[root@codis-178 log]# echo ${test}
oldboy
[root@codis-178 log]# result=${test:-UNSET}
[root@codis-178 log]# echo $result # 变量是否已定义
oldboy
[root@codis-178 log]# result=${test-UNSET}
[root@codis-178 log]# echo $result
oldboy
# ${parameter:=word}作用是如果变量值为空或未赋值,就设置这个变量值为word,并返回其值
(位置变量和特殊变量不适用)
[root@codis-178 log]# unset result # 撤销result变量定义
[root@codis-178 log]# echo $result
[root@codis-178 log]# unset test
[root@codis-178 log]# echo $test
[root@codis-178 log]# result=${test:=UNSET}
[root@codis-178 log]# echo $result
UNSET
[root@codis-178 log]# echo $test
UNSET
# ${parameter:?word}作用是如果变量值为空或未赋值,word字符串将被作为标准错误输出
# 用于变量未定义而报错的具体内容
[root@codis-178 log]# echo ${key:?not defined}
-bash: key: not defined
[root@codis-178 log]# key=1
[root@codis-178 log]# echo ${key:?not defined}
1
[root@codis-178 log]# unset key
[root@codis-178 log]# echo ${key:?not defined}
-bash: key: not defined
# ${parameter:+word}作用是如果变量值为空或未赋值,则什么都不做,否则word字符串将替代变量的值
[root@codis-178 log]# oldboy=${oldgirl:+word}
[root@codis-178 log]# echo $oldboy
[root@codis-178 log]# oldgirl=19
[root@codis-178 log]# oldboy=${oldgirl:+word}
[root@codis-178 log]# echo $oldboy
word
3.特殊扩展变量在生产环境中的应用案例
针对目录路径等的处理可以采用上述变量不存在的方式,防止因目录路径不存在而导致的异常。
实例:删除7天前的过期数据备份
如果忘记了定义path变量,又不希望path值为空,就可以定义/tmp替代path为返回值
[root@codis-178 log]# cat del.sh
find ${path-/tmp} -name "*.log" -type f -mtime +7|xargs rm -f
[root@codis-178 log]# sh -x del.sh
+ find /tmp -name '*.log' -type f -mtime +7
+ xargs rm -f
Shell编程之变量进阶的更多相关文章
- Linux学习——shell编程之变量
shell编程之变量:Linux shell编程基础中的变量. 包括Bash变量的分类和各变量的详细使用,如:用户自定义变量.环境变量.语系变量.位置参数变量和预定义变量. 1:什么是Bash变量? ...
- Linux —— Shell编程之变量赋值和引用
Linux的shell编程是一种非常成熟的编程语言,它支持各种类型的变量.有三种主要的变量类型:环境变量.内部变量和用户变量. 环境变量(environment variable)是系统环境的一部分, ...
- Linux编程 21 shell编程(环境变量,用户变量,命令替换)
一.概述 这篇介绍shell的变量使用,跟其实语言一样,都有声明变量,使用变量,在shell中变量允许你临时地将信息存储中shell脚本中,以便和脚本的其他命令一起使用. 1.1 环境变量 在前面章节 ...
- Shell编程-02-Shell变量
目录 什么是Shell变量 变量类型 环境变量初始化及其对应文件的生效顺序 什么是Shell变量 在初等数学数学方程式中,我们会经常碰到类似于这样的方程式:y=x+1 ,等号左右两边的x和y称 ...
- Linux Shell编程、变量、控制语句
为什么要学习Shell编程 1)Linux运维工程师在进行服务器集群管理时,需要编写Shell程序来进行服务器管理. 2)对于JavaEE和Python程序员来说,工作的需要,你的老大会要求你编写一些 ...
- linux shell编程之变量和bash配置文件(第一篇)
编程语言有两类 强类型:如C语言.数据具有其特定的类型,先声明定义后才能使用.数据运算时必须符合类型要求(如不能把字符串类型数据直接与整型数据做算数运算) 弱类型:如shell.数据默认为字符型,不用 ...
- SHELL编程概念&变量剖析
一.shell软件概念和应用场景 1) 学习Linux技术,不是为了学习系统安装.命令操作.用户权限.配置IP.网络管理,学习Linux技术重点:基于Linux系统部署和维护各种应用软件.程序(Apa ...
- Shell 编程 (变量和条件测试)
变量: 1 . 变量声明 直接使用变量 + 赋值 #!/bin/bash NAME='HELLO WORD' echo $NAME 使用 declare 关键字声明 declare(选项)(参数) + ...
- Shell编程——环境变量
在Shell程序启动时会自动定义一组变量,这组变量就是环境变量,系统中的所有命令都可以使用这些变量参数. 1.如果在父Shell定义环境变量,在子Shell中也能查看到. (1)父Shell与子She ...
随机推荐
- Android中*_handle_t/ANativeWindowBuffer/ANativeWindow/GraphicBuffer/Surface的关系
在阅读SurfaceFlinger HardwareComposer以及gralloc相关代码的过程中,我们经常会遇到native_handle private_handle_t ANativeWin ...
- python django -4 模板
模板介绍 作为Web框架,Django提供了模板,可以很便利的动态生成HTML 模版系统致力于表达外观,而不是程序逻辑 模板的设计实现了业务逻辑(view)与显示内容(template)的分离,一个视 ...
- GDB调试,转载一位大牛的东西
http://www.wuzesheng.com/?p=1327 手把手教你玩转GDB(一)——牛刀小试:启动GDB开始调试 写在最前面:GDB是unix相关操作系统中C/C++程序开发必不可少的工具 ...
- java打开后台程序
try{ String cmds="java -version"; Process p = Runtime.getRuntime().exec(cmds); int exitVal ...
- Linux 进程(二):进程关系及其守护进程
进程关系 进程组 进程组是一个或多个进程的集合.通常,它们是在同一作业中结合起来的,同一进程组中的各进程接收来自同一终端的各种信号,每个进程组有一个唯一的进程组ID.每个进程组有一个组长进程,该组长进 ...
- Palindrome Function
Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 256000/256000 K (Java/Others)Total Submissio ...
- 巨蟒python全栈开发django2:初识django
今日内容大纲: 1.起飞版web框架 2.自定制框架的流程 3.jinja2模板渲染初识 4.MVC&&MTV 5.django版本介绍及django安装 6.django初识(一些操 ...
- Nginx服务监听端口修改启动bug
监听的端口从80 修改到其他端口出现启动不起来问题. 解决方案如下: yum install policycoreutils-python sudo cat /var/log/audit/audit. ...
- CSS3 Flex布局(项目)
一.order属性 order属性定义项目的排列顺序.数值越小,排列越靠前,默认为0. 二.flex-grow属性 flex-grow属性定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大. ...
- AJAX 入门
1. 同步交互与异步交互 1.1 同步交互 客户端发送一个请求, 需要等待服务器的响应结束,才能发送第二个请求! 刷新的是整个页面. 1.2 异步交互 客户端发送一个请求,无需等待服务器的响应,然后就 ...