主控制脚本实现 Shell场景脚本
提取Linux操作系统信息
获取操作系统运行状态
分析应用状态
应用日志分析
VIM编辑器设置
为什么要设置VIM编辑器
友好的设置VIM编辑器,能更加方便、快捷的提高Shell语言编程效率
设置方式分类
VIM编辑器设置的内容
语法高亮
1 2 syntax on 开启 syntax off 关闭
显示行号
自动缩进
1 2 set autoindentset cindent
自动加入文件头
1 2 3 4 5 6 7 8 9 10 11 12 13 14 autocmd BufNewFile *.py,*.sh, exec ":call SetTitle()" let $author_name ="jinglv" let $author_email ="lvjing0705@126.com" func SetTitle() if &filetype == 'sh' call setline(1,"\######################################################" ) call append(line("." ),"\# File Name:" .expand ("%" )) call append(line("." )+1,"\# Author:" .$author_name ) call append(line("." )+2,"\# Email:" .$author_email ) call append(line("." )+3,"\# Created Time:" .strftime("%c" )) call append(line("." )+4,"\#==============================================" ) call append(line("." )+5,"\#!/bin/bash" ) endif endfunction
Shell高亮显示
基本格式
1 echo -e 终端颜色 + 显示内容 + 结束后的颜色
例如:
1 2 echo -e "\e[1;30m Jing sey hi~ \e[1;0m" echo -e "\e[1;30m" "Jing sey hi~" $(tput sgr0)
场景脚本结构
Shell中关联数组 关联数组:
普通数组:只能使用整数作为数组索引
关联数组:可以使用字符串作为数组索引
声明关联数组变量:
数组名[索引]=变量值
脚本实现 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 31 32 33 34 35 36 # # File Name:monitor_man.sh # Author:jinglv # Email:lvjing0705@126.com # Created Time:2021年03月20日 星期六 17时27分21秒 # ============================================== # !/bin/bash # 定义变量,终端经常执行的命令写入到变量中 resettem=$(tput sgr0) # 关联数组,存储文件的号码和名字 declare -A ssharray # 文件号码变量 i=0 numbers="" # 遍历当前目录下,sh的文件,过滤monitor_man.sh文件 for script_file in `ls -I "monitor_man.sh" ./` do # 高亮显示文件 echo -e "\e[1;35m" "The Script:" ${i} '===>' ${resettem} ${script_file} # grep -E "^\#Program function" ${script_file} # 关联数组存储值{文件号码:文件名} ssharray[$ i]=${script_file} numbers="${numbers} | ${i}" # 文件号码自增 i=$((i+1)) done while true do read -p "Please input a number [ ${numbers} ]:" execshell if [[ ! ${execshell} =~ ^[0-9]+ ]];then exit 0 fi /bin/sh ./${ssharray[$execshell]} done
测试执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 [root@lvjing use]# ls check_http_log.sh check_server.sh monitor_man.sh system_monitor.sh [root@lvjing use]# sh monitor_man.sh The Script: 0 ===> check_http_log.sh The Script: 1 ===> check_server.sh The Script: 2 ===> system_monitor.sh Please input a number [ | 0 | 1 | 2 ]:0 check_http_log.sh Please input a number [ | 0 | 1 | 2 ]:1 check_server.sh Please input a number [ | 0 | 1 | 2 ]:2 system_monitor.sh Please input a number [ | 0 | 1 | 2 ]:c [root@lvjing use]#
系统信息及运行状态获取 脚本:system_monitor.sh
功能一:提取操作系统信息(内核、系统版本、网络地址等) Shell脚本实现
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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 # # File Name:system_monitor.sh # Author:jinglv # Email:lvjing0705@126.com # Created Time:2021年03月21日 星期日 13时57分54秒 # ============================================== # !/bin/bash # 清屏,清理当前屏幕显示的信息 clear if [ $# -eq 0 ] then # 定义变量,高亮输出 reset_terminal=$(tput sgr0) # 提取系统相关的信息 # 获取操作系统的类型 os=$(uname -o) echo -e '\E[32m' "Operating System Type:" $reset_terminal $os # 获取操作系统的版本信息和名称 os_name=$(cat /etc/issue|grep -e "Server") echo -e '\E[32m' "Check OS Release Version and Name:" $reset_terminal $os_name # 获取CPU的指令集 architecture=$(uname -m) echo -e '\E[32m' "Check Architecture:" $reset_terminal $architecture # 获取内核信息 kernel_release=$(uname -r) echo -e '\E[32m' "Check Kernel Release:" $reset_terminal $kernel_release # 获取主机名 $HOSTNAME echo -e '\E[32m' "Check hostname:" $reset_terminal $HOSTNAME # 获取内网IP internal_ip=$(hostname -I) echo -e '\E[32m' "Check Internal IP:" $reset_terminal $internal_ip # 获取公网IP external_ip=$(curl -s curl -s icanhazip.com) echo -e '\E[32m' "Check External IP:" $reset_terminal $external_ip # 获取DNS name_servers=$(cat /etc/resolv.conf | grep -E "\<nameserver[ ]+" | awk '{print $NF}') echo -e '\E[32m' "Check DNS:" $reset_terminal $name_servers # 判断网络是否通畅 ping -c 2 baidu.com &>/dev/null && echo "Internet:Connected" || echo "Internet:Disconnected" # 获取当前用户数 who> /tmp/who echo -e '\E[32m' "Logged In Users" $reset_terminal && cat /tmp/who # 临时文件显示后及时删除,避免下次一直读取 rm -rf /tmp/who fi
执行结果
1 2 3 4 5 6 7 8 9 10 11 12 13 [root@lvjing use]# sh system_monitor.sh Operating System Type: GNU/Linux Check OS Release Version and Name: Check Architecture: x86_64 Check Kernel Release: 4.18.0-240.10.1.el8_3.x86_64 Check hostname: lvjing Check Internal IP: 172.25.151.135 172.17.0.1 Check External IP: 8.140.112.109 Check DNS: 100.100.2.136 100.100.2.138 Internet:Connected Logged In Users root pts/0 2021-03-21 13:41 (1.202.112.134) root pts/1 2021-03-21 14:08 (1.202.112.134)
功能二:分析系统的运行状态(CPU负载、内存及磁盘使用率等)
分析系统的运行状态
系统是使用的内存和应用使用内存区别
系统使用内存=Total-Free
应用使用内存=Total-(Free+Cached+Buffers)
内存中cache和buffer区别
| 内存类型 | 功能 | 读取策略 | | ———— | —————————————————- | —————————- | | Cache | 缓存主要用于打开的文件 | 最少使用原则(LRU) | | Buffer | 分缓存主要用于目录项、inode等文件系 | 先进先出策略 |
Shell脚本实现
1 2 3 4 system_men_usages=$(awk '/MemTotal/{total=$2}/MemFree/{free=$2}END{print (total-free)/1024}' /proc/meminfo) apps_men_usages=$(awk '/MemTotal/{total=$2}/MemFree/{free=$2}/^Cached/{cached=$2}/Buffers/{buffers=$2}END{print (total-free-cached-buffers)/1024}' /proc/meminfo) echo -e '\E[32m' "System memuserages:" $reset_terminal $system_men_usages echo -e '\E[32m' "Apps memuserages:" $reset_terminal $apps_men_usages
CPU负载概念
系统负荷为0,意味着大桥上一辆车也没有。
系统负荷为0.5,意味着大桥一半的路段有车。
系统负荷为1.0,意味着大桥的所有路段都有车,也就是说大桥已经”满”了。但是必须注意的是,直到此时大桥还是能顺畅通行的。
系统负荷为1.7,意味着车辆太多了,大桥已经被占满了(100%),后面等着上桥的车辆为桥面车辆的70%。以此类推,系统负荷2.0,意味着等待上桥的车辆与桥面的车辆一样多;系统负荷3.0,意味着等待上桥的车辆是桥面车辆的2倍。总之,当系统负荷大于1,后面的车辆就必须等待了;系统负荷越大,过桥就必须等得越久。
CPU的系统负荷,基本上等同于上面的类比。大桥的通行能力,就是CPU的最大工作量;桥梁上的车辆,就是一个个等待CPU处理的进程(process)。
Linux获取CPU负载值的命令
1 top -n 1 -b |grep "load average:" |awk '{print $12 $13 $14}'
系统磁盘容量
1 2 3 4 5 6 7 8 [root@lvjing use]# df -h 文件系统 容量 已用 可用 已用% 挂载点 devtmpfs 1.8G 0 1.8G 0% /dev tmpfs 1.8G 0 1.8G 0% /dev/shm tmpfs 1.8G 572K 1.8G 1% /run tmpfs 1.8G 0 1.8G 0% /sys/fs/cgroup /dev/vda1 40G 9.6G 31G 24% / ……
Filesystem(文件系统):磁盘设备名称
Size(容量):设备总容量
Used(已用):已用容量
Avail(可用):可用容量
Use%(已用%):使用容量百分比
Mounted on(挂载点):设备挂载的系统目录文件
系统磁盘已使用(%),Linux命令如下:
1 df -h | grep -vE '文件系统|tmpfs' | awk '{print $1 " " $5}'
注意:df -h输出的中英文,和系统有关
完整Shell脚本 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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 clear if [ $# -eq 0 ]then reset_terminal=$(tput sgr0) os=$(uname -o) echo -e '\E[32m' "Operating System Type:" $reset_terminal $os os_name=$(cat /etc/issue|grep -e "Server" ) echo -e '\E[32m' "Check OS Release Version and Name:" $reset_terminal $os_name architecture=$(uname -m) echo -e '\E[32m' "Check Architecture:" $reset_terminal $architecture kernel_release=$(uname -r) echo -e '\E[32m' "Check Kernel Release:" $reset_terminal $kernel_release echo -e '\E[32m' "Check hostname:" $reset_terminal $HOSTNAME internal_ip=$(hostname -I) echo -e '\E[32m' "Check Internal IP:" $reset_terminal $internal_ip external_ip=$(curl -s curl -s icanhazip.com) echo -e '\E[32m' "Check External IP:" $reset_terminal $external_ip name_servers=$(cat /etc/resolv.conf | grep -E "\<nameserver[ ]+" | awk '{print $NF}' ) echo -e '\E[32m' "Check DNS:" $reset_terminal $name_servers ping -c 2 baidu.com &>/dev/null && echo "Internet:Connected" || echo "Internet:Disconnected" who >/tmp/who echo -e '\E[32m' "Logged In Users" $reset_terminal && cat /tmp/who rm -rf /tmp/who system_men_usages=$(awk '/MemTotal/{total=$2}/MemFree/{free=$2}END{print (total-free)/1024}' /proc/meminfo) apps_men_usages=$(awk '/MemTotal/{total=$2}/MemFree/{free=$2}/^Cached/{cached=$2}/Buffers/{buffers=$2}END{print (total-free-cached-buffers)/1024}' /proc/meminfo) echo -e '\E[32m' "System memuserages:" $reset_terminal $system_men_usages echo -e '\E[32m' "Apps memuserages:" $reset_terminal $apps_men_usages load_average=$(top -n 1 -b |grep "load average:" |awk '{print $12 $13 $14}' ) echo -e '\E[32m' "Load average:" $reset_terminal $load_average disk_average=$(df -h | grep -vE '文件系统|tmpfs' | awk '{print $1 " " $5}' ) echo -e '\E[32m' "Disk average:" $reset_terminal $disk_average fi
脚本执行结果如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 [root@lvjing use]# sh system_monitor.sh Operating System Type: GNU/Linux Check OS Release Version and Name: Check Architecture: x86_64 Check Kernel Release: 4.18.0-240.10.1.el8_3.x86_64 Check hostname: lvjing Check Internal IP: 172.25.151.135 172.17.0.1 Check External IP: 8.140.112.109 Check DNS: 100.100.2.136 100.100.2.138 Internet:Connected Logged In Users root pts/0 2021-03-21 13:41 (1.202.112.134) root pts/1 2021-03-21 14:08 (1.202.112.134) System memuserages: 3044.86 Apps memuserages: 1705.32 Load average: 0.00,0.00,0.00 Disk average: /dev/vda1 24% overlay 24%
nginx和mysql应用状态分析 脚本:check_server.sh
应用运行状态监控脚本 利用操作系统命令:
网络命令:ping、nslookup、nm-tool、tracertroute、dig、telent、nc、curl
监控进程:ps、netstat、pgrep
利用客户端命令、工具:
应用客户端:mysql、ab、mongo、php、jstack
第三方工具包:nginxstatus、nagios-libexec
服务端接口支持:
nginx-http_stub_status_module
nutcracker监控集群(redis、memcache)状态
Mongodb
……
nginx监控脚本 监控nginx需要在nginx在配置文件中开启监控,Linux监控命令如下:
1 curl -m 5 -s -w %{http_code} http://8.140.112.109/nginx_status -o /dev/null
Shell脚本如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 resettem=$(tput sgr0) nginx_server='http://8.140.112.109/nginx_status' check_nginx_server (){ status_code=$(curl -m 5 -s -w %{http_code} ${nginx_server} -o /dev/null) if [ $status_code -eq 000 -o $status_code -ge 500 ];then echo -e '\E[32m' "Check Http Server Error! Response status code is " $resettem $status_code else http_content=$(curl -s $(nginx_server)) echo -e '\E[32m' "Check Http Server OK! \n" $resettem $http_content fi } check_nginx_server
未启动nginx情况下,执行脚本结果如下
1 2 [root@lvjing use]# sh check_server.sh Check Http Server Error! Response status code is 000
监控MySQL主从复制状态
搭建MySQL主从复制环境
基于mysql客户端连接,获取主从复制状态
1 mysql> show slave status\G;
Slave_IO_Running — IO线程是否有连接到主服务器上
Seconds_Behind_Master — 主从同步的延时时间
在MySQL从库里设置监控普通用户
1 mysql> grant replication slave, replication client on *.* to 用户名@'%' identified by '密码' ;
Shell脚本如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 mysql_slave_server='8.140.112.109' mysql_slave_port='3306' mysql_slave_user='rep' mysql_slave_pass='123123' check_mysql_server (){ nc -z -w2 ${mysql_slave_server} ${mysql_slave_port} &>/dev/null if [ $? -eq 0 ];then mysql -u${mysql_slave_user} -p${mysql_slave_pass} -h${mysql_slave_server} -e "show slave status\G" | grep "Slave_IO_Running" | awk '{if($2!="Yes"){print "Slave thread not running!";exit 1}}' if [ $? -eq 0 ];then mysql -u${mysql_slave_user} -p${mysql_slave_pass} -h${mysql_slave_server} -e "show slave status\G" | grep "Seconds_Behind_Master" fi else echo "Connect MySQL Server not Succeeded!" fi } check_mysql_server
完整的Shell脚本 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 31 32 33 34 35 36 37 38 39 40 41 resettem=$(tput sgr0) nginx_server='http://8.140.112.109/nginx_status' check_nginx_server (){ status_code=$(curl -m 5 -s -w %{http_code} ${nginx_server} -o /dev/null) if [ $status_code -eq 000 -o $status_code -ge 500 ];then echo -e '\E[32m' "Check Http Server Error! Response status code is " $resettem $status_code else http_content=$(curl -s $(nginx_server)) echo -e '\E[32m' "Check Http Server OK! \n" $resettem $http_content fi } check_nginx_server mysql_slave_server='8.140.112.109' mysql_slave_port='3306' mysql_slave_user='rep' mysql_slave_pass='123123' check_mysql_server (){ nc -z -w2 ${mysql_slave_server} ${mysql_slave_port} &>/dev/null if [ $? -eq 0 ];then mysql -u${mysql_slave_user} -p${mysql_slave_pass} -h${mysql_slave_server} -e "show slave status\G" | grep "Slave_IO_Running" | awk '{if($2!="Yes"){print "Slave thread not running!";exit 1}}' if [ $? -eq 0 ];then mysql -u${mysql_slave_user} -p${mysql_slave_pass} -h${mysql_slave_server} -e "show slave status\G" | grep "Seconds_Behind_Master" fi else echo "Connect MySQL Server not Succeeded!" fi } check_mysql_server
应用日志分析 常见系统日志文件
系统日志
/var/log/messages 系统主日志文件
/var/log/secure 认证、安全
/var/log/dmesg 和系统启动相关
应用服务
access.log nginx访问日志
mysqld.log mysqld运行日志
xferlog 和访问FTP服务器相关
程序脚本
开发语言:C、C++、Java、PHP
框架:Django、MVC、Servlet
脚本语言:Shell、Python
日志输出的格式,在nginx.conf配置文件中,进行设置
nginx大致有三类变量能够记录在log_format 中
HTTP请求变量- arg_PARAMETER http_HEADER send_http_HEADER(服务端返回)
内置变量- Nginx内置的
自定义变量- 自己定义的
变量含义:
remote_addr:对应客户端的地址
remote_user:是请求客户端请求认证的用户名,如果没有开启认证模块的话是值为空。
time_local:表示nginx服务器时间
request:表示request请求头的行
status:表示response的返回状态
body_bytes_sent:表示从服务端返回给客户端的body数据大小
http_referer:表示请求的上一级页面
http_user_agent:表示agent信息 http_x_forwarded_for:会记录每一级请求中信息
HTTP状态码
1** 信息,服务器收到请求,需要请求者继续执行操作
2** 成功,操作被成功接收并处理
3** 重定向,需要进一步的操作以完成请求
4** 客户端错误,请求包含语法错误或无法完成请求
5** 服务器错误,服务器在处理请求的过程中发生了错误
日志分析脚本 nginx.log日志的示例:
1 2 3 4 5 113.87.161.17 - - [05/Dec/2018:00:11:39 +0000] "GET /cable HTTP/1.1" 101 3038 "-" "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36" 112.418 112.418 . 216.244.66.241 - - [05/Dec/2018:00:11:46 +0000] "GET /topics/10079/replies/119591/edit HTTP/1.1" 301 5 "-" "Mozilla/5.0 (compatible; DotBot/1.1; http://www.opensiteexplorer.org/dotbot, help@moz.com)" 0.001 0.001 . 216.244.66.241 - - [05/Dec/2018:00:11:46 +0000] "GET /topics/10089?locale=zh-TW HTTP/1.1" 301 5 "-" "Mozilla/5.0 (compatible; DotBot/1.1; http://www.opensiteexplorer.org/dotbot, help@moz.com)" 0.002 0.002 . 144.76.81.72 - - [05/Dec/2018:00:11:46 +0000] "GET / HTTP/1.1" 200 10096 "-" "Mozilla/5.0 (compatible; MJ12bot/v1.4.8; http://mj12bot.com/)" 0.070 0.070 . ……
脚本实现功能介绍
功能一:分析HTTP状态码在100-200、200-300、300-400、400-500、500以上,五个区间的请求条数
获取HTTP协议及状态码,Linux命令如下
1 2 3 4 5 6 7 [root@lvjing ~]# cat nginx.log | grep -ioE "HTTP\/1\.[1|0]\"[[:blank:]][0-9]{3}" HTTP/1.1" 101 HTTP/1.1" 101HTTP/1.1" 301 HTTP/1.1" 301HTTP/1.1" 200 ……
Shell脚本实现如下
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 resettem=$(tput sgr0) logfile_path='/root/nginx.log' check_http_status (){ http_status_codes=(`cat $logfile_path | grep -ioE "HTTP\/1\.[1|0]\"[[:blank:]][0-9]{3}" | awk -F"[ ]+" '{ if($2>=100 && $2<200) {i++} else if($2>=200 && $2<300) {j++} else if($2>=300 && $2<400) {k++} else if($2>=400 && $2<500) {n++} else if($2>=500) {p++} }END{ print i?i:0,j?j:0,k?k:0,n?n:0,p?p:0,i+j+k+n+p }' `) echo -e '\E[33m' "The number of http status[100+]:" ${resettem} ${http_status_codes[0]} echo -e '\E[33m' "The number of http status[200+]:" ${resettem} ${http_status_codes[1]} echo -e '\E[33m' "The number of http status[300+]:" ${resettem} ${http_status_codes[2]} echo -e '\E[33m' "The number of http status[400+]:" ${resettem} ${http_status_codes[3]} echo -e '\E[33m' "The number of http status[500+]:" ${resettem} ${http_status_codes[4]} echo -e '\E[33m' "All request numbers:" ${resettem} ${http_status_codes[5]} } check_http_status
功能二:分析日志中HTTP状态码为404、500的请求条数
Shell脚本如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 check_http_code (){ http_code=(`cat $logfile_path | grep -ioE "HTTP\/1\.[1|0]\"[[:blank:]][0-9]{3}" | awk -v total=0 -F '[ ]+' '{ if($2!="") {code[$2]++;total++} else {exit} }END{ print code[404]?code[404]:0,code[500]?code[500]:0,total }' `) echo -e '\E[33m' "The number of http status[404+]:" ${resettem} ${http_code[0]} echo -e '\E[33m' "The number of http status[500+]:" ${resettem} ${http_code[1]} echo -e '\E[33m' "All request numbers:" ${resettem} ${http_code[2]} } check_http_code
完整的Shell脚本 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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 resettem=$(tput sgr0) logfile_path='/root/nginx.log' check_http_status (){ http_status_codes=(`cat $logfile_path | grep -ioE "HTTP\/1\.[1|0]\"[[:blank:]][0-9]{3}" | awk -F"[ ]+" '{ if($2>=100 && $2<200) {i++} else if($2>=200 && $2<300) {j++} else if($2>=300 && $2<400) {k++} else if($2>=400 && $2<500) {n++} else if($2>=500) {p++} }END{ print i?i:0,j?j:0,k?k:0,n?n:0,p?p:0,i+j+k+n+p }' `) echo -e '\E[33m' "The number of http status[100+]:" ${resettem} ${http_status_codes[0]} echo -e '\E[33m' "The number of http status[200+]:" ${resettem} ${http_status_codes[1]} echo -e '\E[33m' "The number of http status[300+]:" ${resettem} ${http_status_codes[2]} echo -e '\E[33m' "The number of http status[400+]:" ${resettem} ${http_status_codes[3]} echo -e '\E[33m' "The number of http status[500+]:" ${resettem} ${http_status_codes[4]} echo -e '\E[33m' "All request numbers:" ${resettem} ${http_status_codes[5]} } check_http_status check_http_code (){ http_code=(`cat $logfile_path | grep -ioE "HTTP\/1\.[1|0]\"[[:blank:]][0-9]{3}" | awk -v total=0 -F '[ ]+' '{ if($2!="") {code[$2]++;total++} else {exit} }END{ print code[404]?code[404]:0,code[500]?code[500]:0,total }' `) echo -e '\E[33m' "The number of http status[404+]:" ${resettem} ${http_code[0]} echo -e '\E[33m' "The number of http status[500+]:" ${resettem} ${http_code[1]} echo -e '\E[33m' "All request numbers:" ${resettem} ${http_code[2]} } check_http_code
执行结果如下
1 2 3 4 5 6 7 8 9 10 [root@lvjing use]# sh check_http_log.sh The number of http status[100+]: 433 The number of http status[200+]: 814 The number of http status[300+]: 461 The number of http status[400+]: 273 The number of http status[500+]: 1 All request numbers: 1982 The number of http status[404+]: 266 The number of http status[500+]: 1 All request numbers: 1982