将本身以前的shell脚本笔记搬到segmentfault,顺带复习一下shell基础。笔记大可能是读<<跟老男孩学Linux运维:Shell编程实站>>时所记录,推荐想学shell的能够去看看。2019-1-26
系列笔记传送门:linux
Shell介绍
Shell是一个命令解释器,做用是解释执行用户输入的命令程序等,用户每输入一条命令,Shell就执行解释一条。这种从键盘输入命令就能够获得回应的方式叫作交互的方式。git
Shell存在于操做系统的最外层,负责与用户直接对话,把用户的输入解释给操做系统,并处理各类操做系统的输出结果,而后输出到屏幕给用户。shell
Shell脚本
当命令或程序语句不在命令行下执行,而是经过一个程序文件来执行,这个文件就叫作Shell脚本。
Shell脚本很适合用于处理纯文本类型的数据,而Linux系统中几乎全部的配置文件,日志文件(NFS,Rsync,Httpd,Nginx,LVS 等),以及绝大多数的启动文件都是纯文本类型的文件。所以,学好shell语言,就能够利用它在linux系统中发挥巨大的做业。编程
查看CentOS系统默认的Shellvim
[root@moli_linux1 ~]# echo $SHELL /bin/bash [root@moli_linux1 ~]# grep root /etc/passwd root:x:0:0:root:/root:/bin/bash
Shell脚本的建立
一个规范的Shell脚本在第一行会指出由那个程序(解释器)来执行脚本的内容,这一行内容在Linux bash编程中通常为:segmentfault
#!/bin/bash
或者bash
#!/bin/sh
注意:这一行必须位于每一个脚本顶端的第一行,若是不是第一行则为脚本注释行。且shell脚本文件的后缀名一般以.sh
结尾。服务器
Shell脚本的执行
运维
1. bash script-name
(脚本的路径名字)或者sh script-name
:这是当脚本文件没有可执行权限时经常使用的放法
2. path/script-name
或者./script-name
:指在当前路径下执行脚本(脚本须要有可执行权限)。即须要将脚本文件的权限先修改成可执行,chmod +xscript-name
。而后经过脚本的绝对路径和相对路径就能够直接执行脚本。函数
什么是变量
变量是暂时存储数据的地方及数据标记,所存储的数据存在于内存空间中,经过正确地调用内存空间中变量的名字就能够取出与变量对应的数据。CentOS中变量的定义直接由一个赋值符号=
就能够建立一个变量,而echo
命令相似于其余语言的print
命令,打印这个变量的值。
[root@moli_linux1 ~] name="laowan" #定义一个变量 [root@moli_linux1 ~] echo $name #打印这个变量的值 laowan [root@moli_linux1 ~] age=14 [root@moli_linux1 ~] echo $age 14
shell变量的特性默认状况下,在bash shell 中是不会区分变量类型的。
变量类型
变量分为:环境变量(全局变量)和普通变量(局部变量)
环境变量能够在建立它们的shell以及其派生出来的任意子进程shell中使用。环境变量又分为自定义环境变量和bash内置的环境变量。
普通变量只能在建立它们的shell函数或shell脚本中使用。
提示:有三个命令能够查看系统中变量的值:set、env、declare。
环境变量的定义
上面定义一个变量是在一个shell中直接使用赋值符号对这个变量进行建立,可是当打开一个新的子shell,打印这个变量却不能打印出来。这是由于咱们建立的变量是一个普通变量,若想在其余子shell中使用这个变量,须要将这个变量设置为全局变量。而定义一个全局变量的方法以下:
export 变量名=value 或者 declare -x 变量名=value
第二个方法是将变量名添加到环境变量文件/etc/profile
编辑环境配置文件 vim /etc/profile 在文件最后面添加 export name="laowan" 保存,退出。从新加载文件 source /etc/profile 打印变量的值 echo $name laowan
而CentOS中,全局环境变量的配置文件有三个,分别是:
当用户登陆Linux系统时,首先会先加载/etc/profile全局环境变量文件,这是Linux系统默认的Shell主配置文件,其次会执行/etc/profile.d下的脚本文件,要作重启Linux系统后初始化或者显示某些内容,只须要把脚本文件放在/etc/progile.d下便可,最后才会执行bashrc文件。
设置登陆提示符
Linux中能够设置登陆以后,或者远程链接服务器打开的shell中显示登陆提示符。设置登陆提示内容的文件是/etc/motd,编辑这个文件就能够设置每次登陆提示的内容。例如:
[root@moli_linux1 ~]# cat /etc/motd welcome to my Linux Server! 打开一个新的shell Connecting to 192.168.30.3:22... Connection established. To escape to local shell, press 'Ctrl+Alt+]'. WARNING! The remote SSH server rejected X11 forwarding request. Last login: Sat Jan 26 19:35:54 2019 from 192.168.30.1 welcome to my Linux Server!
能够看到登陆提示符。
定义变量不加单引号和双引号,加单引号,加双引号的区别
[root@moli_linux1 ~] a=10 [root@moli_linux1 ~] b=10-$a [root@moli_linux1 ~] c='100-$a' [root@moli_linux1 ~] d="100-$a" [root@moli_linux1 ~] echo $a 10 [root@moli_linux1 ~] echo $b 10-10 [root@moli_linux1 ~] echo $c 100-$a [root@moli_linux1 ~] echo $d 100-10
第一种定义b变量的方式,当内容为简单连续的数字,字符串,路径名时,能够这样用,不加引号时,值里有变量的会被解析后输出。
第二种定义c的变量有加单引号,这样输出变量时单引号里面内容是什么就是什么,即便有变量和命令也是直接输出。
第三种定义d变量的方式加了双引号,这种输出变量内容时引号里的变量以及命令会通过解析后再输出内容,这种方式比较适合字符串中附带有变量以及命令且想将其解析后再输出的变量定义。
取消变量
取消变量使用unset命令,注意要取消的变量以前不用添加$
符号。
[root@moli_linux1 ~] a=100 [root@moli_linux1 ~] echo $a 100 [root@moli_linux1 ~] unset a [root@moli_linux1 ~] echo $a #能够看到这个变量的为空 [root@moli_linux1 ~]#
将一个命令的结果赋值给一个新的变量
生产环境中把命令的结果做为变量的内容进行赋值的方法在脚本开发时很常见。有两个方法能够实现。
变量名=$(命令) 或者: 变量名=`命令` [root@moli_linux1 ~] ls 192.168.229 anaconda-ks.cfg git_data server shell-100 test-find [root@moli_linux1 ~] file=$(ls) [root@moli_linux1 ~] echo $file 192.168.229 anaconda-ks.cfg git_data server shell-100 test-find [root@moli_linux1 ~] file2=`ls` [root@moli_linux1 ~] echo $file2 192.168.229 anaconda-ks.cfg git_data server shell-100 test-find
shell中特殊位置参数变量
要从命令行,函数或脚本执行等处传递参数时,就要在shell脚本中使用位置参数变量。
示例1,特殊位置变量$1
[root@moli_linux1 script] cat test.sh #!/bin/bash echo $1 #脚本的功能是打印脚本传递的第一个参数的值 [root@moli_linux1 script] sh test.sh laowan #传入一个字符串参数,赋值给$1 laowan [root@moli_linux1 script] sh test.sh laowan xiaoming #传入多个参数,但脚本不会接收多个参数,所以只输出第一个参数的值 laowan [root@moli_linux1 script] sh test.sh "I am laowan" #用双引号括起来表明一个参数 I am laowan
示例2,特殊位置变量$1,$2,$3....${10}
[root@moli_linux1 script] echo \${1..15} > test2.sh [root@moli_linux1 script] cat test2.sh #!/bin/bash echo $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 $14 $15 [root@moli_linux1 script] sh test2.sh {a..z} #传入26个字母a~z,做为26个参数 a b c d e f g h i a0 a1 a2 a3 a4 a5 #位置参数的数字大于9后,输出内容就不对了 [root@moli_linux1 script] vim test2.sh [root@moli_linux1 script] cat test2.sh #!/bin/bash #位置参数的数字大于9时,须要用大括号将数字括起来 echo $1 $2 $3 $4 $5 $6 $7 $8 $9 ${10} ${11} ${12} ${13} ${14} ${15} [root@moli_linux1 script] sh test2.sh {a..z} a b c d e f g h i j k l m n o #大于9的数字加上大括号后显示正确的内容
示例3,特殊变量$0--获取脚本的名称以及路径:
[root@moli_linux1 shell_test] cat 05-getName.sh #!/bin/bash echo $0 [root@moli_linux1 shell_test] sh 05-getName.sh 05-getName.sh
示例4,$#获取脚本传递参数个数:
[root@moli_linux1 shell_test] cat 06-getNum.sh #!/bin/bash echo $0 $1 $2 $3 $4 $5 $6 $7 $8 $9 echo $# #传递的参数个数 [root@moli_linux1 shell_test] ./06-getNum.sh {a..z} #传递了26个字母,即26个参数 ./06-getNum.sh a b c d e f g h i #接受了9个参数,所以打印9个字母 26 #传递了26个参数,打印出26
示例5,$#的常见实际应用
根据用户在命令行传参的个数判断用户的输入,不符合的给出提示并退出,符合的打印出传入的参数内容。
[root@moli_linux1 shell_test] cat t1.sh #!/bin/bash if [ $# -ne 2 ] #若是执行脚本传参的个数不等于2 then echo "USAGE:/bin/sh $0 arg1 arg2" #则给用户提示正确的用法,此处$0,打印脚本名字和路径 exit 1 #不满要求,则退出脚本,返回值为1 fi echo $1 $2 #符合要求,则打印$1 $2所获取到的传参的字符串 [root@moli_linux1 shell_test] sh t1.sh arg1 agr2 #符合传参个数=2,打印出传入参数的内容 arg1 agr2 [root@moli_linux1 shell_test] sh t1.sh arg1 agr2 arg3 #不符合传参个数=2,给出提示并退出 USAGE:/bin/sh t1.sh arg1 arg2
上一个指令
的执行状态返回值(0为成功,非0为失败),这个变量最经常使用。$?
的实践1
[root@moli_linux1 ~] pwd #执行pwd获取当前路径,用echo $?查看执行命令的状态返回值 /root [root@moli_linux1 ~] echo $? 0 #返回0表示上一条命令执行成功 [root@moli_linux1 ~] rm shell_test/ #删除目录shell_test rm: 没法删除"shell_test/": 是一个目录 #没加参数-r ,没法删除 [root@moli_linux1 ~] echo $? 1 #状态码非0,表示上一条执行不成功或者错误
$?
的实践2
[root@moli_linux1 ~] cat test1.sh #!/bin/bash [ $# -ne 2 ] && { #若是参数个数不=2 echo "must be two args." #则输出提示 exit 119 #终止程序并以指定的119状态码退出程序,赋值给当前shell的“$?”变量。 } echo "success!" [root@moli_linux1 ~]# sh test1.sh 1 2 3 #参数个数不=2 must be two args. [root@moli_linux1 ~]# echo $? 119 #状态码为119
"$?"
的注意点:
变量字串表达式
表达式 | 说明 |
---|---|
${parameter} | 返回变量${parameter}的内容 |
${#parameter} | 返回变量${parameter}内容的长度(按字符) |
${parameter:offset} | 在变量${parameter}的内容中,从位置offset以后开始提取字串到结尾 |
${parameter:offset:length} | 在变量${parameter}中,从位置offset以后开始提取长度为length的字串 |
${parameter#word} | 从变量${parameter}开头 开始删除最短 匹配的word字串 |
${parameter##word} | 从变量${parameter}开头 开始删除最长 匹配的word字串 |
${parameter%word} | 从变量${parameter}结尾 开始删除最短 匹配的word字串 |
${parameter%%word} | 从变量${parameter}结尾 开始删除最短 匹配的word字串 |
${parameter/pattern/string} | 使用string替换第一个 匹配的pattern |
${parameter//pattern/string} | 使用string替换全部 匹配的pattern |
#
”:表示从开头删除最短匹配##
”:表示从开头删除最长匹配%
”:表示从结尾开始删除最短匹配%%
”:表示从结尾开始删除最长匹配/
”:表示替换第一个//
”:表示替换全部示例1,变量的打印和提取切片:
# 定义变量parameter,内容为abc123ABC456 [root@moli_linux1 script]# parameter="abc123ABC456" # 变量的两种打印方式 [root@moli_linux1 script]# echo $parameter abc123ABC456 [root@moli_linux1 script]# echo ${parameter} abc123ABC456 # 打印这个变量内容的长度,一共12个字符 [root@moli_linux1 script]# echo ${#parameter} 12 # 从变量内容的第三个开始,提取剩下的全部内容 [root@moli_linux1 script]# echo ${parameter:3} 123ABC456 # 从变量内容的第三个开始,提取接下来的6个字符 [root@moli_linux1 script]# echo ${parameter:3:6} 123ABC
示例2,变量的截取与替换:
# 定义变量,mori [root@moli_linux1 script]# echo $mori abc123ABC456abc # 从开头删除了最短的a*c字串为abc [root@moli_linux1 script]# echo ${mori#a*c} 123ABC456abc # 从开头删除了最长的a*c字串为abc123ABC456abc,所有删除了 [root@moli_linux1 script]# echo ${mori##a*c} [root@moli_linux1 script]# # 从左到右将第一个遇到的小写a替换为大写A [root@moli_linux1 script]# echo ${mori/a/A} Abc123ABC456abc # 将变量里全部的小写a替换为大写A [root@moli_linux1 script]# echo ${mori//a/A} Abc123ABC456Abc