[toc]html
Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。Shell 既是一种命令语言,又是一种程序设计语言。 shell是一种脚本语言; 可使用逻辑判断、循环等语法; 可自定义函数; shell是系统命令的集合; shell脚本能够实现自动化运维,能大大增长咱们的运维效率;shell
说明了shell 脚本在工做的重要性,shell脚本就是一些命令的集合,是自动化运维的重要部分编程
下面跟着步骤来一步步学习如何写shell脚本数组
[root@localhost ~]# mkdir shell [root@localhost ~]# cd shell/ [root@localhost shell]# ls [root@localhost shell]# vi 01.sh
shell脚本一般都是.sh为后缀名,但不是说不加.sh的脚本就不能执行,只是你们的一个习惯而已,因此若是发新了以.sh为后缀的文件,那么它可能就是一个shell脚本.bash
本例中,脚本文件01.sh,进入编辑状态后,第一行要以#!/bin/bash开头,表示该文件使用的是bash语法.而/bin/bash是Bash的解释器命令路径.运维
[root@localhost shell]# sh 01.sh 123 22:43:14 up 25 min, 1 user, load average: 0.00, 0.01, 0.01 USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT root pts/0 192.168.72.1 22:26 2.00s 0.08s 0.00s w 01.sh
把#!/bin/bash这一行删除,运行命令后也能执行但这样不符合规范.ssh
使用该方法运行shell脚本的前提是脚本自己有执行权限,须要给脚本加x权限函数
[root@localhost shell]# chmod +x 01.sh [root@localhost shell]# ./01.sh 123 23:18:34 up 1:01, 1 user, load average: 0.00, 0.01, 0.03 USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT root pts/0 192.168.72.1 22:26 2.00s 0.11s 0.01s w 01.sh
[root@localhost shell]# bash 01.sh 123 23:37:15 up 1:19, 1 user, load average: 0.00, 0.01, 0.03 USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT root pts/0 192.168.72.1 22:26 3.00s 0.20s 0.01s w 01.sh
这里是否能够理解有三种方法均可以执行shell脚本,可是本机验证成功,不表明其余机器虚拟机是否成功,后续测试post
[root@localhost shell]# vi /etc/init.d/network #! /bin/bash # # network Bring up/down networking # # chkconfig: 2345 10 90 # description: Activates/Deactivates all network interfaces configured to \ # start at boot time. #
[root@localhost shell]# sh -x 01.sh + echo 123 123 + w 23:40:21 up 1:22, 1 user, load average: 0.00, 0.01, 0.03 USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT root pts/0 192.168.72.1 22:26 5.00s 0.22s 0.01s w + ls 01.sh [root@localhost shell]# bash -x 01.sh + echo 123 123 + w 23:40:29 up 1:23, 1 user, load average: 0.00, 0.01, 0.03 USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT root pts/0 192.168.72.1 22:26 5.00s 0.21s 0.00s w + ls 01.sh
date命令用于显示或设置系统时间与日期。 命令选项:学习
[root@xavi ~]# date //当前日期 2018年 04月 17日 星期二 22:06:22 CST [root@xavi ~]# cal //当前日历 四月 2018 日 一 二 三 四 五 六 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 [root@xavi ~]# date +%Y //年 2018 [root@xavi ~]# date +%y //年缩写 18 [root@xavi ~]# date +%m //月 04 [root@xavi ~]# date +%Y%m%d //年月日 20180417 [root@xavi ~]# date +%F 2018-04-17 [root@xavi ~]# date +%H //小时 22 [root@xavi ~]# date +%M //分钟 23 [root@xavi ~]# date +%S //秒 10 [root@xavi ~]# date +%s //时间戳,时间戳是从1970年1月1日(UTC/GMT的午夜)开始所通过的秒数,不考虑闰秒 1523975099 [root@xavi ~]# date +%T //时间的完整显示 22:27:04 [root@xavi ~]# date "+%Y-%m-%d %H:%M:%S %w" // 年月日,时分秒,星期 2018-04-17 22:20:50 2 [root@xavi ~]# date -d "-1 day" 2018年 04月 16日 星期一 22:31:20 CST [root@xavi ~]# date -d "-1 day" +%F 2018-04-16 [root@xavi ~]# date -d "-1 month" +%F 2018-03-17 [root@xavi ~]# date -d "-1 year" +%F 2017-04-17 [root@xavi ~]# date -d "-1 hour" +%T 21:44:30 [root@xavi ~]# date +%s -d "2018-04-17 22:46" // 日期转化为时间戳 1523976360
当脚本中使用某个字符串较频繁而且字符串长度很长时就应该使用变量代替 使用条件语句时,常使用变量 if [ $a -gt 1 ]; then ... ; fi 引用某个命令的结果时,用变量替代 n=`wc -l 1.txt` 写和用户交互的脚本时,变量也是必不可少的 read -p "Input a number: " n; echo $n 若是没写这个n,能够直接使用$REPLY 内置变量 $0, $1, $2… $0表示脚本自己,$1 第一个参数,$2 第二个 .... $#表示参数个数 数学运算a=1;b=2; c=$(($a+$b))或者$[$a+$b]
在命令行提示符直接执行env、set查看系统或环境变量。env显示用户环境变量,set显示Shell预先定义好的变量以及用户变量。能够经过export导出成用户变量。 一些写Shell脚本时经常使用的系统变量:
普通变量定义:VAR=value 临时环境变量定义:export VAR=value 变量引用:$VAR
下面看下他们之间区别:
Shell进程的环境变量做用域是Shell进程,当export导入到系统变量时,则做用域是Shell进程及其Shell子进程。
[root@xaviyunserver sbin]# ps axjf |grep pts 1229 1773 1773 1773 ? -1 Ss 0 0:00 \_ sshd: root@pts/0 1773 1775 1775 1775 pts/0 2631 Ss 0 0:00 \_ -bash 1775 1825 1825 1775 pts/0 2631 T 0 0:00 \_ sh test2.sh 1775 2631 2631 1775 pts/0 2631 R+ 0 0:00 \_ ps axjf 1775 2632 2631 1775 pts/0 2631 S+ 0 0:00 \_ grep --color=auto pts [root@xaviyunserver sbin]# echo $$ 1775 [root@xaviyunserver sbin]# VAR=123 [root@xaviyunserver sbin]# echo $VAR 123 [root@xaviyunserver sbin]# bash [root@xaviyunserver sbin]# echo $$ 2633 [root@xaviyunserver sbin]# ps axjf |grep pts 1229 1773 1773 1773 ? -1 Ss 0 0:00 \_ sshd: root@pts/0 1773 1775 1775 1775 pts/0 2649 Ss 0 0:00 \_ -bash 1775 1825 1825 1775 pts/0 2649 T 0 0:00 \_ sh test2.sh 1775 2633 2633 1775 pts/0 2649 S 0 0:00 \_ bash 2633 2649 2649 1775 pts/0 2649 R+ 0 0:00 \_ ps axjf 2633 2650 2649 1775 pts/0 2649 S+ 0 0:00 \_ grep --color=auto pts [root@xaviyunserver sbin]# echo $VAR [root@xaviyunserver sbin]# exit exit [root@xaviyunserver sbin]# echo $VAR 123 [root@xaviyunserver sbin]# ps -ef |grep ssh root 1229 1 0 07:58 ? 00:00:00 /usr/sbin/sshd -D
ps axjf输出的第一列是PPID(父进程ID),第二列是PID(子进程ID) 当SSH链接Shell时,当前终端PPID(-bash)是sshd守护程序的PID(root@pts/0),所以在当前终端下的全部进程的PPID都是-bash的PID,好比执行命令、运行脚本。 因此当在-bash下设置的变量,只在-bash进程下有效,而-bash下的子进程bash是无效的,当export后才有效。
[root@xaviyunserver sbin]# sh test.sh 1229 1773 1773 1773 ? -1 Ss 0 0:00 \_ sshd: root@pts/0 1773 1775 1775 1775 pts/0 2693 Ss 0 0:00 \_ -bash 1775 1825 1825 1775 pts/0 2693 T 0 0:00 \_ sh test2.sh 1775 2693 2693 1775 pts/0 2693 S+ 0 0:00 \_ sh test.sh 2693 2694 2693 1775 pts/0 2693 R+ 0 0:00 \_ ps -axjf 2693 2695 2693 1775 pts/0 2693 R+ 0 0:00 \_ sh test.sh 2693 [root@xaviyunserver sbin]# cat test.sh #!/bin/bash ps -axjf |grep pts echo $$ echo $VAR [root@xaviyunserver sbin]# sh test.sh 1229 1773 1773 1773 ? -1 Ss 0 0:00 \_ sshd: root@pts/0 1773 1775 1775 1775 pts/0 2693 Ss 0 0:00 \_ -bash 1775 1825 1825 1775 pts/0 2693 T 0 0:00 \_ sh test2.sh 1775 2693 2693 1775 pts/0 2693 S+ 0 0:00 \_ sh test.sh 2693 2694 2693 1775 pts/0 2693 R+ 0 0:00 \_ ps -axjf 2693 2695 2693 1775 pts/0 2693 R+ 0 0:00 \_ sh test.sh 2693 [root@xaviyunserver sbin]# export VAR [root@xaviyunserver sbin]# sh test.sh 1229 1773 1773 1773 ? -1 Ss 0 0:00 \_ sshd: root@pts/0 1773 1775 1775 1775 pts/0 2696 Ss 0 0:00 \_ -bash 1775 1825 1825 1775 pts/0 2696 T 0 0:00 \_ sh test2.sh 1775 2696 2696 1775 pts/0 2696 S+ 0 0:00 \_ sh test.sh 2696 2697 2696 1775 pts/0 2696 R+ 0 0:00 \_ ps -axjf 2696 2698 2696 1775 pts/0 2696 R+ 0 0:00 \_ sh test.sh 2696 123
在/etc/profile下定义的变量就是这个原理,后面有章节会讲解Linux经常使用变量文件。
$1-$n,须要注意的是从第10个开始要用花括号调用,例如${10}
#!/bin/bash echo "1: $1" shift echo "2: $2" shift echo "3: $3" shift [root@xaviyunserver sbin]# sh postion.sh 1: 2: 3: [root@xaviyunserver sbin]# sh postion.sh a b c 1: a 2: c 3:
Shell中全部变量引用使用$符,后跟变量名。 有时个别特殊字符会影响正常引用,那么须要使用${VAR},例如:
# VAR=123 # echo $VAR 123 # echo $VAR_ # Shell容许VAR_为变量名,因此此引用认为这是一个有效的变量名,故此返回空 # echo ${VAR} 123
# echo $VAR456 # echo ${VAR}456 123456
# VAR=`echo 123` # echo $VAR 123 # VAR=$(echo 123) # echo $VAR 123
在变量赋值时,若是值有空格,Shell会把空格后面的字符串解释为命令:
# VAR=1 2 3 -bash: 2: command not found # VAR="1 2 3" # echo $VAR 1 2 3 # VAR='1 2 3' # echo $VAR 1 2 3
看不出什么区别,再举个说明:
# N=3 # VAR="1 2 $N" # echo $VAR 1 2 3 # VAR='1 2 $N' # echo $VAR 1 2 $N
单引号是告诉Shell忽略特殊字符,而双引号则解释特殊符号原有的意义,好比$、!。
Shell注释也很简单,只要在每行前面加个#号,即表示Shell忽略解释。
用${}引用变量,${}还有一个重要的功能,就是文本处理,单行文本基本上能够知足你全部需求。
# VAR='hello world!' # echo $VAR hello world! # echo ${#VAR} 12
格式:
${parameter:offset} ${parameter:offset:length}
截取hello字符串: # VAR='hello world!' # echo ${VAR:0:5} hello
截取wo字符: # echo ${VAR:6:2} wo
截取world!字符串: # echo ${VAR:5} world!
截取最后一个字符: # echo ${VAR:(-1)} ! 截取最后二个字符: # echo ${VAR:(-2)} d! 截取从倒数第3个字符后的2个字符: # echo ${VAR:(-3):2} ld
格式:${parameter/pattern/string}
# VAR='hello world world!' 将第一个world字符串替换为WORLD: # echo ${VAR/world/WORLD} hello WORLD world! 将所有world字符串替换为WORLD: # echo ${VAR//world/WORLD} hello WORLD WORLD!
格式:
${parameter#word} # 删除匹配前缀 ${parameter##word} ${parameter%word} # 删除匹配后缀 ${parameter%%word}
# URL="http://www.baidu.com/baike/user.html" 以//为分隔符截取右边字符串: # echo ${URL#*//} www.baidu.com/baike/user.html 以/为分隔符截取右边字符串: # echo ${URL##*/} user.html 以//为分隔符截取左边字符串: # echo ${URL%%//*} http: 以/为分隔符截取左边字符串: # echo ${URL%/*} http://www.baidu.com/baike 以.为分隔符截取左边: # echo ${URL%.*} http://www.baidu.com/baike/user 以.为分隔符截取右边: # echo ${URL##*.} html
${VAR:-string} 若是VAR变量为空则返回string ${VAR:+string} 若是VAR变量不为空则返回string ${VAR:=string} 若是VAR变量为空则从新赋值VAR变量值为string ${VAR:?string} 若是VAR变量为空则将string输出到stderr
若是变量为空就返回hello world!:
# VAR= # echo ${VAR:-'hello world!'}
hello world! 若是变量不为空就返回hello world!:
# VAR="hello" # echo ${VAR:+'hello world!'}
hello world! 若是变量为空就从新赋值:
# VAR= # echo ${VAR:=hello} hello # echo $VAR hello
若是变量为空就将信息输出stderr:
# VAR= # echo ${VAR:?value is null} -bash: VAR: value is null
${}主要用途大概就这么多了,另外还能够获取数组元素。
再介绍下字符串输出颜色,有时候关键地方须要醒目,颜色是最好的方式:
格式:
[ ] \033[1;31;40m # 1是显示方式,可选。31是字体颜色。40m是字体背景颜色。
[ ] \033[0m # 恢复终端默认颜色,即取消颜色设置。
#!/bin/bash # 字体颜色,显示方式默认为空 for i in {31..37}; do echo -e "\033[$i;40mHello world!\033[0m" done # 背景颜色,显示方式默认为空 for i in {41..47}; do echo -e "\033[47;${i}mHello world!\033[0m" done # 显示方式 for i in {1..8}; do echo -e "\033[$i;31;40mHello world!\033[0m" done