为什么学习 shell 编程
shell 脚本语言是实现 Linux/unix 系统管理机自动化运维所必备的重要工具, Linux/unix 系统的底层及基础应用软件的核心大部分涉及 shell 脚本的内容. 每一个合格的 Linux 系统管理员或运维工程师, 都需要熟练的编写 shell 脚本语言, 并能够阅读系统及各类软件附带的 shell 脚本内容
什么是 shell
shell 是一个命令解释器, 它在操作系统的最外层, 负责直接与用户对话, 把用户的输入解释给操作系统, 并处理各种各样的操作系统的输出结果, 输出到屏幕返回给用户, 这种对话方式可以是交互式 (从键盘输入命令, 可以立即得到 shell 的回应), 或非交互(执行脚本程序) 的方式
shell 种类
交互式 shell
非交互式 shell
登录式 shell
/etc/profile -> /etc/profile.d/*.sh -> ~/.bash_profile -> ~/.bashrc -> /etc/bashrc
非登录式 shell
~/.bashrc -> /etc/bashrc
shell 执行方式
1, bash script-name 或 sh script-name (生成一个子 shell 执行)
2, path/script-name 或 ./script-name (添加执行权限执行, 默认根据脚本第一行指定的解释器执行, 如果没有指定则以当前默认 shell 解释器执行)
3, source script-name 或 . script-name (以当前默认 shell 解释器执行)
4,cat script-name |bash
子 shell
子 shell 的本质是 shell 的子进程
子进程是由父进程的概念引申而来, 在 Linux 系统下, 我们所运行的应用程序几乎都是从 init(systemd)(pid 为 1 的进程)进程延伸出来的, 所以这些应用程序都视为 init 进程的子进程, 而 init 则为它们的父进程
shell 子进程是从一个父 shell 进程调用 shell 程序而产生的一个全新的 shell, 我们将这种全新的 shell 统称为这个父 shell 的子 shell
产生子 shell 的情况
1, 在父 shell 中执行一个 shell 脚本
bash , 执行环境不同, 不能直接引用父 shell 变量, 需 export, 定义的变量不能被父 shell 引用
2, 在父 shell 中执行一条命令, 在命令的末尾加上 &
&, 执行环境相同, 直接引用父 shell 变量, 定义的变量不能被父 shell 引用
- STR0='123';STR0='abc' &
- echo $STR0
3, 在父 shell 中执行一条命令, 使用 () 中执行
(), 执行环境相同, 直接引用父 shell 变量, 定义的变量不能被父 shell 引用
- [root@web01 shell_class_03]# STR2='123' && (STR2='abc') && echo $STR2
- 123
4, 在父 shell 中执行带管道的命令
管道, 执行环境相同, 直接引用父 shell 变量, 定义的变量不能被父 shell 引用
- [root@web01 shell_class_03]# STR1='123';echo 111 |STR1='ABC';echo $STR1
- 123
shell 应用场景
系统基础配置
部署应用服务
配置应用服务
部署业务代码
应用服务备份
日志分析
监控应用服务
shell 基础
命令补全和文件路径补全, 如果写错无法补全 table
命令历史记忆功能 history
别名功能 alias,unalias
常用快捷键 ctrl+u,k,a,e,l,c,z,d,r
前后台作业控制 bg,fg,jobs,screen
输入输出重定向>>> 2> 2>> <<< &> cat
| 将前者命令的标准输出交给后者命令的输入
|& 将前者命令的错误输出交给后者命令的输入
命令之间的关系; 没有逻辑关系, 无论分号前面的命令执行是否成功都执行后者命令 && 前面执行成功, 则执行后者 || 前面执行不成功, 则执行后者
shell 通配符
匹配任意多个字符
? 匹配任意一个字符
[] 匹配括号中任意一个字符 a-z,0-9,A-Z,a-Z
() 在子 shell 中执行(cd /boot;ls) (umask 077; touch file1000)
{} 集合 touch file{1..9}
\ 转义符
shell 模式匹配
使用 shopt 内置命令启用 shell 选项 (extglob) 则会识别几个扩展模式匹配运算符.
模式列表是由 | 分割
查看 shell 选项 extglob
shopt |grep extglob
启动 shell 选项 extglob
shopt -s extglob
关闭 shell 选项 extglob
shopt -u extglob
** 模式 ** | ** 说明 ** |
---|---|
?(pattern-list) | 匹配给定模式零或一次 |
*(pattern-list) | 匹配给定模式零次或多次 |
+(pattern-list) | 匹配给定模式一次或多次 |
@(pattern-list) | 匹配给定模式之一 |
!(pattern-list) | 匹配除了给定的模式 |
- [root@mycentos6-clone ~]# ll
- total 0
- -rw-r--r-- 1 root root 0 Nov 1 07:02 123
- -rw-r--r-- 1 root root 0 Nov 1 07:02 aaaac
- -rw-r--r-- 1 root root 0 Nov 1 06:51 aaab
- -rw-r--r-- 1 root root 0 Nov 1 07:02 aad
- -rw-r--r-- 1 root root 0 Nov 1 07:02 aadg
- -rw-r--r-- 1 root root 0 Nov 1 07:02 bb
- -rw-r--r-- 1 root root 0 Nov 1 07:02 c
- [root@mycentos6-clone ~]# ls !(c|bb|123)
- aaaac aaab aad aadg
- [root@mycentos6-clone ~]# rm !(c|bb|123) -f
- [root@mycentos6-clone ~]# ll
- total 0
- -rw-r--r-- 1 root root 0 Nov 1 07:02 123
- -rw-r--r-- 1 root root 0 Nov 1 07:02 bb
- -rw-r--r-- 1 root root 0 Nov 1 07:02 c
单引号 - 双引号 - 没有引号
引号和不加引号的区别 1
- [root@zeqtx ~]# touch a b
- [root@zeqtx ~]# ll
- total 0
- -rw-r--r--. 1 root root 0 Jun 25 16:25 a
- -rw-r--r--. 1 root root 0 Jun 25 16:25 b
- [root@zeqtx ~]# touch "a b"
- [root@zeqtx ~]# ll
- total 0
- -rw-r--r--. 1 root root 0 Jun 25 16:25 a
- -rw-r--r--. 1 root root 0 Jun 25 16:25 a b
- -rw-r--r--. 1 root root 0 Jun 25 16:25 b
引号和不加引号的区别 2:
[root@zeq36 tmp]# ll
总用量 0
-rw-r--r-- 1 root root 0 6 月 25 19:36 ?
-rw-r--r-- 1 root root 0 6 月 25 19:32 *
-rw-r--r-- 1 root root 0 6 月 25 19:33 aa
-rw-r--r-- 1 root root 0 6 月 25 19:33 abc
-rw-r--r-- 1 root root 0 6 月 25 19:33 b
[root@zeq36 tmp]# ll ?
-rw-r--r-- 1 root root 0 6 月 25 19:36 ?
-rw-r--r-- 1 root root 0 6 月 25 19:32 *
-rw-r--r-- 1 root root 0 6 月 25 19:33 b
[root@zeq36 tmp]# ll "?"
-rw-r--r-- 1 root root 0 6 月 25 19:36 ?
[root@zeq36 tmp]# ll *
-rw-r--r-- 1 root root 0 6 月 25 19:36 ?
-rw-r--r-- 1 root root 0 6 月 25 19:32 *
-rw-r--r-- 1 root root 0 6 月 25 19:33 aa
-rw-r--r-- 1 root root 0 6 月 25 19:33 abc
-rw-r--r-- 1 root root 0 6 月 25 19:33 b
[root@zeq36 tmp]# ll "*"
-rw-r--r-- 1 root root 0 6 月 25 19:32 *
双引号和单引号区别 1:
关于 $
- [root@zeqtx ~]# echo "$LANG"
- en_US.UTF-8
- [root@zeqtx ~]# echo '$LANG'
- $LANG
双引号和单引号区别 2:
关于 ``
- [root@zeqtx ~]# echo "`which awk`"
- /bin/awk
- [root@zeqtx ~]# echo '`which awk`'
- `which awk`
双引号和单引号区别 3:
关于!
- [root@zeqtx ~]# echo '!ll'
- !ll
- [root@zeqtx ~]# echo "!ll"
- echo "ll /bin/awk"
- ll /bin/awk
shell 常用命令与工具
- cat
- cat<<-EOF
- 1.[install lamp]
- 2.[install lnmp]
- 3.[exit]
- EOF
- cat>> /etc/profile <<'EOF'
- $PATH
- EOF
- read
格式:
read [options] varible1 varible2 ...
参数:
-p 显示提示信息
-t 超时时间
-s 取消回显
-u 绑定文件描述符作为输入
-a 后跟一个变量, 该变量会被认为是个数组, 然后给其赋值, 默认是以空格为分割符
eval
执行参数做为 shell 命令
- [root@VM_153_209_centos ~]# echo $a
- 3
- [root@VM_153_209_centos ~]# echo $b
- stu
- [root@VM_153_209_centos ~]# eval echo ${
- b
- }{
- 1..$a
- }
- stu1 stu2 stu3
- tee
从标准输入读取写到出和文件
-a 追加到文件
- printf
- a=1
- b=3
- printf "%.2f" `echo "scale=2;$a/$b"|bc`
- :
空命令
echo
字体颜色
- echo -e "\033[30m 黑色字 zeq trainning \033[0m"
- echo -e "\033[31m 红色字 zeq trainning \033[0m"
- echo -e "\033[32m 绿色字 zeq trainning \033[0m"
- echo -e "\033[33m 黄色字 zeq trainning \033[0m"
- echo -e "\033[34m 蓝色字 zeq trainning \033[0m"
- echo -e "\033[35m 紫色字 zeq trainning \033[0m"
- echo -e "\033[36m 天蓝字 zeq trainning \033[0m"
- echo -e "\033[37m 白色字 zeq trainning \033[0m"
背景颜色
- echo -e "\033[40;37m 黑底白字 welcome to old1boy\033[0m"
- echo -e "\033[41;37m 红底白字 welcome to old2boy\033[0m"
- echo -e "\033[42;37m 绿底白字 welcome to old3boy\033[0m"
- echo -e "\033[43;37m 黄底白字 welcome to old4boy\033[0m"
- echo -e "\033[44;37m 蓝底白字 welcome to old5boy\033[0m"
- echo -e "\033[45;37m 紫底白字 welcome to old6boy\033[0m"
- echo -e "\033[46;37m 天蓝白字 welcome to old7boy\033[0m"
- echo -e "\033[47;30m 白底黑字 welcome to old8boy\033[0m"
- trap
trap [-lp] [ [参数] 信号 ...]
参数 : shell 命令
信号
HUP(1) 挂起, 通常因终端掉线或用户退出而引发
INT(2) 中断, 通常因按下 Ctrl+C 组合键而引发
QUIT(3) 退出, 通常因按下 Ctrl + 组合键而引发
ABRT(6) 中止, 通常因某些严重的执行错误而引发
ALRM(14) 报警, 通常用来处理超时
TERM(15) 终止, 通常在系统关机时发送
SIGTSTP 停止进程 终端来的停止信号
- trap ':' INT EXIT TSTP TERM HUP
- http://jumpserver.sh/
- #!/bin/bash
- LB02=10.0.0.6
- WEB01=10.0.0.7
- menu(){
- cat <<EOF
- 1) LB02
- 2) WEB01
- 6) h
- EOF
- }
- while true
- do
- trap ':' INT TSTP TERM HUP
- menu
- read -p "please input hostname num:" NUM
- case $NUM in
- 1|LB02)
- SSH root@$LB02
- ;;
- 2|WEB01)
- SSH root@$WEB01
- ;;
- h)
- menu
- ;;
- exec)
- exit 1
- ;;
- esac
- done
- expect
- #!/usr/bin/expect
- set ip 10.0.0.6
- set user root
- set password 123456
- set timeout 5
- spawn SSH $user@$ip
- expect {
- "yes/no" { send "yes\r"; exp_continue }
- "password:" { send "$password\r" };
- }
- # 交互方式
- interact
- expect-copy-sshkey.exp
- #!/usr/bin/expect
- if { $argc != 1 } {
- send_user "usage: expect expect-copy-sshkey.exp host \n"
- exit
- }
- #define var
- set host [lindex $argv 0]
- set password "123456"
- spawn SSH-copy-id -i /home/oldgirl/.SSH/id_dsa.pub "oldgirl@$host"
- #spawn SSH -p 50718 disdata@$host /sbin/ifconfig
- set timeout 60
- expect {
- -timeout 20
- "yes/no" { send "yes\r";exp_continue }
- "*password" { send "$password\r" }
- timeout { puts "expect connect timeout,pls contact zeq."; return }
- }
- expect eof
- exit -onexit {
- send_user "zeq say good bye to you!\n"
- }
- cat http://dis-sshkey.sh/
- #!/bin/sh
- . /etc/init.d/functions
- [ ! -f iplist ] && echo "hostlists.txt is not exist." && exit 1
- for host in `cat /home/oldgirl/iplist`
- do
- expect expect-copy-sshkey.exp $host &>/dev/null
- if [ $? -eq 0 ];then
- action "$host dis data" /bin/true
- else
- action "$host dis data" /bin/false
- fi
- done
- mkpasswd openssl
- mkpasswd -l 10 -c 3 -C 3 -d 3
- openssl rand -base64 80
- basename dirname
- basename /etc/init.d/network
- network
- dirname /etc/init.d/network
- /etc/init.d
shell 脚本
脚本第一行
指定脚本解释器
- #!/bin/sh
- #!/bin/bash
- #! /usr/bin/awk
- #! /bin/sed
- #! /usr/bin/tclsh
- #! /usr/bin/expect
- #! /usr/bin/perl
- #! /usr/bin/env python
脚本注释
单行注释 #
多行注释
<<'EOF'
语句 1
语句 2
...
语句 n
EOF
脚本构成
主脚本
模块(子脚本)
主脚本 调用模块
模块中 有 函数
先调用模块, 再调用函数
脚本执行参数
-x 将执行的脚本内容及输出显示到屏幕上
-n 不会执行该脚本, 仅查询脚本语法是否有问题, 并给出错误提示.
-v 在执行脚本时, 先将脚本的内容输出到屏幕上然后执行脚本, 如果有错误, 也会给出错误提示
变量
变量类型
自定义变量
1. 定义变量变量名 = 变量值 , 不允许数字命名, 不能使用横岗命名
2. 引用变量 $ 变量名 或 ${变量名}
3. 查看变量 echo $ 变量名 set 显示所有变量, 包括自定义变量和环境变量
4. 取消变量 unset 变量名 作用范围: 仅在当前 shell 中有效
系统环境变量
1. 定义环境变量 export export 变量 , 将自定义变量转换成环境变量
2. 引用环境变量 $ 变量名 或 ${变量名}
3. 查看环境变量 echo $ 变量名 env |grep Name
4. 取消环境变量 unset 变量名
5. 作用范围在当前 shell 和子 shell 有效
位置参数变量
$1
$2
$3
${10}
预先定义变量
$0 脚本文件名
$* 所有的参数
$@ 所有的参数
- set "I am" handsome zeq
- for i in "$*" ; do echo $i; done
- for i in "$@" ; do echo $i; done
- $# 参数的个数
$$ 当前进程的 PID
$! 上一个后台进程的 PID
$? 上一个命令的返回值 0 表示成功
$_ 在此之前执行的命令或脚本的最后一个参数
变量赋值方式
1. 显式赋值(变量名 = 变量值)
2.read 从键盘读入变量值
- read -p "请输入数字:"
- echo $REPLY
3. 定义或引用变量时注意事项: "" 弱引用' '强引用
4.`` 命令替换等价于 $()反引号中的 shell 命令会被先执行
变量子串
变量长度
${#string}
从前往后删除变量内容
- ${
- string#substring
- } 从变量 $string 开头开始删除最短匹配 $substring 子串
- ${
- string##substring
- } 从变量 $string 开头开始删除最长匹配 $substring 子串
从后往前删除变量内容
${string%substring} 从变量 $string 结尾开始删除最短匹配 $substring 子串
${string%%substring} 从变量 $string 结尾开始删除最长匹配 $substring 子串
索引及切片
${string:position} 在 $string 中, 从 $position 个开始提取子串(从 0 开始计数)
${string:position:length} 在 $string 中, 从位置 $position 之后开始提取长度为 $length 的子串
变量内容替换
${parameter/pattern/string} 使用 string 代替第一个匹配的 pattern
- ${
- parameter//pattern/string
- } 使用 string 代替所有的 pattern
- ${
- parameter/#pattern/string
- } 从开头匹配 string 变量中的 pattern, 用 string 替换匹配的 pattern
${parameter/%pattern/string} 从结尾匹配 string 变量中的 pattern, 用 string 替换匹配的 pattern
变量替代
${value:-Word} 如果变量名存在且非 null, 则返回变量的值. 否则, 返回 Word 字符串 用途: 如果变量未定义, 则返回备用的值
${value:=Word} 如果变量名存在且非 null, 则返回变量值. 否则, 设置这个变量值为 Word 并返回其值 用途: 如果变量未定义, 则设置变量为默认值, 并返回默认值
${value:?"not defined"} 如果变量名存在且非 null, 则返回变量的值. 否则显示变量名: message, 并退出当前的命令或者脚本 用途: 用于捕捉由于变量未定义而导致的错误, 并退出程序
${value:+Word} 如果变量名存在且非 null, 则返回 Word. 否则返回 null 用途: 测试变量是否存在
变量作用域
环境变量
使用 export 定义, 在当前 shell 及其子 shell 中生效
本地变量
仅在当前 shell 中生效
局部变量
使用 local 定义 , 仅在函数中生效
表达式
运算符
++ -- 自增 自减
! ~ 正号 负号 逻辑取反 按位取反
/ % 乘 除 取余
加 减
<<=>>= 比较符号
== != 等于 不等于
<<>> 左移 右移
& | ^ 按位与 按位或 按位异或
&& || 逻辑与 逻辑或
= += -= *= /= %= &= |= ^= <<=>>= 各种赋值运算符
** 幂运算
算术运算(整数)
** [] test ** | ** (()) [[]] ** |
---|---|
-eq | == 或 = |
-ne | != |
-gt | > |
-ge | >= |
-lt | < |
-le | <= |
自增 / 自减
- http://ping.sh/
- #!/bin/bash
- IP=223.5.5.5
- i=1
- while((i<=4))
- do
- if ping $IP -c 1 &> /dev/null;then
- echo "ping $IP is ok!"
- else
- echo "ping $IP is faild..."
- fi
- let i++
- done
表达式符号
[ ]
[[ ]]
(( )) 仅用于整数
- ((1<2&&1>3))
- ((1<2||1>3))
算术运算 - bc
- # a=1.2
- # b=3
- # echo "$a<$b" |bc
- 1
- # echo "$a>$b" |bc
- 0
- # echo "$a+$b" |bc
- 4.2
- # x=$(echo "$a+$b" |bc)
- # echo $x
- 4.2
- [root@VM_153_209_centos scripts]# a=9.8
- [root@VM_153_209_centos scripts]# b=10.1
- [root@VM_153_209_centos scripts]# echo "$a>$b" |bc
- 0
- [root@VM_153_209_centos scripts]# echo "$a<$b" |bc
- 1
- cat test.bc
- #!/bin/bc
- 1+2
- quit
- bc -q test.bc 3
- #!/bin/bc
- array[1]=1
- array[2]=2
- array[1]+array[2]
- quit
- bc -q test.bc 3
逻辑运算
** [] test ** | ** [[]] ** | ** 说明 ** |
---|---|---|
-a | && | and 与 |
-o | || | or 或 |
! | ! | not 非 |
字符串运算
-z "str" 若串长度为 0 则真,-z 可以理解为 zero
-n "str" 若串长度不为 0 则真,-n 可以理解为 no zero
"str1" = "str2" 若串 1 等于串 2 则真, 可以使用 "==" 代替 "="
"str1" != "str2" 若串 1 不等于串 2 则真
"str1" =~ "pattern" 字符串匹配成功则为真 [[ ]]
文件测试
[ -f 文件 ] 文件存在且为普通文件则真, 条件表达式成立
[ -d 目录 ] 目录存在且为目录文件则真, 条件表达式成立
[ -s 文件 ] 文件存在且文件大小不为 0 则真, 条件表达式成立
[ -e 文件 ] 文件存在则真, 只要有文件就行
[ -r 文件 ] 文件存在且可读则真, 条件表达式成立
[ -w 文件 ] 文件存在且可写则真, 条件表达式成立
[ -L 文件 ] 文件存在且为链接文件则真, 条件表达式成立
[ f1 -nt f2 ] 文件 f1 比文件 f2 新则真, 条件表达式成立
[ f1 -ot f2 ] 文件 f1 比文件 f2 旧则真, 条件表达式成立
流程控制
顺序 选择 循环
条件表达式
条件表达式的值只有真 (非 0 | 非空 | 条件成立 | $? 为 0(此条 shell 特有)), 假(0 | 空 | 条件不成立 | $? 不为 0(此条 shell 特有)) 此规则适用于所有的计算机高级语言
算术运算
逻辑运算
Linux 命令
选择(分支)
if
if 条件表达式; then
命令
- fi
- #/bin/bash
- http="ss -lntup|grep nginx &> /dev/null"
- if eval $http
- then
- echo 1
- else
- echo 0
- fi
流程图
st=>start: Start
op=>operation: 命令 1
cond=>condition: 条件表达式为真?
- e=>end
- st->cond
- cond(yes)->op->e
- cond(no)->e
- if else
if 条件表达式; then
命令 1
else
命令 2
- fi
- st=>start: Start
op=>operation: 命令 1
op2=>operation: 命令 2
cond=>condition: 条件表达式为真?
- e=>end
- st->cond
- cond(yes)->op->e
- cond(no)->op2->e
- if elif else
if 条件表达式; then
命令 1
elif 条件表达式 2;then
命令 2
else
命令 3
- fi
- st=>start: Start
op=>operation: 命令 1
op2=>operation: 命令 2
op3=>operation: 命令 3
cond=>condition: 条件表达式为真?
cond2=>condition: 条件表达式 2 为真?
- e=>end
- st->cond
- cond(yes)->op->e
- cond(no)->cond2
- cond2(yes)->op2->e
- cond2(no)->op3->e
- case
case 模式名 in
模式 1)
命令 1
;;
模式 2)
命令 2
;;
模式 3)
命令 3
;;
*)
其它命令
- esac
- st=>start: Start
io=>inputoutput: 模式名
op=>operation: 命令 1
op2=>operation: 命令 2
op3=>operation: 命令 3
op4=>operation: 其它命令
cond=>condition: 模式名 == 模式 1 ?
cond2=>condition: 模式名 == 模式 2 ?
cond3=>condition: 模式名 == 模式 3 ?
- e=>end
- st->io->cond
- cond(yes)->op->e
- cond(no)->cond2
- cond2(yes)->op2->e
- cond2(no)->cond3
- cond3(yes)->op3->e
- cond3(no)->op4->e
循环
for
for 变量名 in 取值列表
do
命令
- done
- for ((expr1;expr2;expr3))
- do
命令
done
expr1 初值 expr2 终值 expr3 步长值
st=>start: Start
op=>operation: 命令
- op1=>operation: expr1
- op3=>operation: expr3
cond=>condition: expr2 为真 ?
- e=>end
- st->op1->cond
- cond(yes)->op->op3->cond
- cond(no)->e
- IFS
- #!/bin/bash
- data='a,b,c,d'
- IFS=,
- for i in $data;do
- echo $i
- done
- while
while 条件表达式
do
命令
- done
- st=>start: Start
op=>operation: 命令
cond=>condition: 条件表达式为真 ?
- e=>end
- st->cond
- cond(yes)->op->cond
- cond(no)->e
把 a.txt 文件中的内容倒腾到 b.txt 文件中
- cat a.txt
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- cat b.txt
- 10
- 9
- 8
- 7
- 6
- 5
- 4
- 3
- 2
- 1
- #!/bin/bash
- touch b.txt
- while [ -n "$(cat a.txt)" ]
- do
- if [ -z "$(cat b.txt)" ];then
- head -1 a.txt> b.txt
- else
- sed -i "1i `head -1 a.txt`" b.txt
- fi
- sed -i 1d a.txt
- done
- while read
- while read -p "请输入:"
- do
- if [[ $REPLY =~ ^[0-9]+$ ]];then
- echo "输出:$((REPLY*=${REPLY}00))"
- elif [[ "$REPLY" = "q" ]];then
- break
- fi
- done
while 读取文件三种方式
- 1,
- cat ./a.txt | while read LINE
- do
- echo $LINE
- done
- 2,
- while read LINE
- do
- echo $LINE
- done <./a.txt
- 3,
- exec < ./a.txt
- while read LINE
- do
- echo $LINE
- done
- break
break n 表示跳出循环的层数
省略 n 表示跳出整个循环
continue
continue n 退到第 n 层继续循环
省略 n 表示跳出本次循环, 继续下一次循环
- select
- #PS3=[$USER@$0]#
- select VAR in var1 var2 quit
- do
- case $VAR in
- var1)
- echo 1
- ;;
- var2)
- echo 2
- ;;
- quit)
- break
- ;;
- esac
- done
函数
函数定义
function 函数名(){
命令
}
函数参数
- $1
- $2
- $3
- $#
- $*
- $@
函数调用
函数名 参数 1 参数 2 参数 3
函数返回
返回数字作为函数执行状态 返回给 $? 取值范围 0-255 (使用 return)
返回数字作为函数执行结果 (使用 echo)
返回字符串, 作为函数执行结果 (使用 echo)
系统函数库
系统函数库
/etc/init.d/functions
action 函数
action "xxxxx" /bin/trueaction "xxxxx" /bin/false
功能函数库
- # 脚本初始化
- function scripts_init(){
- prog=`basename $0 .sh`
- LockFile=/var/lock/subsys/${prog}.lock # 使用锁文件
- LogFile=/var/log/${prog}.log # 脚本记录日志
- PidFile=/var/run/${prog}.pid # 记录进程号, 可以管理脚本
- [ -f $LockFile ] && echo "There $LockFile is exist!!" && exit 1 ||touch $LockFile
- [ ! -f $LogFile ] && touch $LogFile
- [ -f $PidFile ] && echo "There $PidFile is exist!!" && exit 2|| echo $$> $PidFile
- }
- # 记录日志
- function writelog(){
- Date=$(date "+%F_%T")
- ShellName=`basename $0`
- Info=$1
- echo "$Date : ${ShellName} : ${Info}">> ${LogFile}
- }
- # 脚本退出扫尾
- function closeout(){
- [ -f $LockFile ] && rm -f $LockFile
- [ -f $PidFile ]&& rm -f $PidFile
- }
- # 判断输入是整数
- function int_judge(){
- fun_a=$1
- expr $fun_a + 1 &>/dev/null
- RETVAL=$?
- return $RETVAL
- }
- # 判断输入非空
- function input_judge(){
- RETVAL=0
- fun_a=$1
- [ ${#fun_a} -eq 0 ]&& RETVAL=1
- return $RETVAL
- }
数组
数组名代表首地址
下标是从 0 开始的整数
普通数组(索引数组)
定义数组
array=(a b c)
获取所有元素
${array[*]}
获取元素下标
${!a[@]}
获取数组长度
${#array[*]}
获取一个元素的长度
${#name[0]}
获取第一个元素
${array[0]}
获取第二个元素
${array[1]}
获取多个元素
- array=(1 2 3 4 5)
- echo ${
- array[@]:1
- }
- 2 3 4 5
- #array[@]: 下标: 截取元素个数
- echo ${
- array[@]:1:3
- }
- 2 3 4
添加元素
array[3]=d
添加多个元素
array+=(e f g)
删除第一个元素
unset array[0] # 删除会保留元素下标
删除数组
unset array
数组切片
${name[4]:0:7}
关联数组
关联数组的下标是字符串
定义关联数组
declare -A M
关联数组赋值
M=([a]=11 [b]=22)
获取关联数组元素
echo ${M[a]} 11
获取关联数组元素个数
echo ${#M[@]} 2
获取关联数组下标
echo ${!M[*]} a b
获取关联数组所有元素
echo ${M[@]} 11 22
添加元素
M[c]=33
添加多个元素
M+=([d]=33 [e]=44)
综合题
找出一个网络中最大的空闲 ip 地址段
- #!/bin/bash
- SUB_NET="10.0.0."
- for NUM in {1..254}
- do
- {
- if ping -c 1 ${SUB_NET}${NUM} &> /dev/null;then
- echo $NUM>> ip.txt
- fi
- }&
- done
- wait
- sort -n ip.txt -o ip.txt
- if [ $(tail -1 ip.txt) -ne 254 ];then
- echo 254>> ip.txt
- fi
- while read LINE
- do
- array+=($LINE)
- done <ip.txt
- for ((i=0;i<${#array[*]}-1;i++))
- do
- DIFF=$((${array[$((i+1))]}-${array[$i]}))
- echo -e "${SUB_NET}${array[$((i+1))]}\t${SUB_NET}${array[$i]}\t$DIFF">> result.txt
- done
- sort -rnk3 result.txt
- rm *.txt -f
- #!/bin/bash
- SUB_NET="10.0.0."
- for NUM in {1..254}
- do
- {
- if ping -c 1 ${SUB_NET}${NUM} &> /dev/null;then
- echo $NUM>> ip.txt
- fi
- }&
- done
- wait
- sort -n ip.txt -o ip.txt
- if [ $(tail -1 ip.txt) -ne 254 ];then
- echo 254>> ip.txt
- fi
- awk -v.NET=$SUB_NET '{if(NR==1){last=$1}if(NR>1){printf"%s%d\t%s%d\t%d\n",net,$1,net,last,$1-last;last=$1}}' ip.txt |sort -nrk 3
- rm ip.txt -f
抓阄
- #!/bin/bash
- function rand(){
- echo $((RANDOM%100+1))
- }
- > /tmp/user.txt
- while true
- do
- clear
- echo "抓阄获奖名单如下:"
- sort -rnk2 /tmp/user.txt |head -3
- read -p 'please input name:' NAME
- [ -z "$NAME" ] && continue
- if [ "$NAME" = "q" ];then
- break
- fi
- if grep -w "$NAME" /tmp/user.txt &> /dev/null;then
- continue
- fi
- RAND=$(rand)
- while grep -w "$RAND" /tmp/user.txt &> /dev/null
- do
- RAND=$(rand)
- done
- echo -e "$NAME\t$RAND">>/tmp/user.txt
- done
- echo "抓阄获奖名单如下:"
- sort -rnk2 /tmp/user.txt |head -3
来源: https://www.cnblogs.com/zeq912/p/9991439.html