目录:
前言
在linux管理中,shell脚本很是重要,它可以帮助我们完成很多繁琐的工作,专注于更重要的事情上来,脚本的学习也是我们学习linux中所要遇到的比较困难的部分,因为它需要对vim,正则,逻辑,程序化语言有一定的熟悉,shell编程是过程式,解释执行的。它包括各种系统指令的组合,数据存储(变量,数组)、表达式、语句。
在shell脚本中,包含一些命令或声明,并符合一定格式的文本文件,在首行是shebang机制,如:
#!/bin/bash
#!/usr/bin/python
#!/usr/bin/perl
脚本在开头查找执行本脚本的程序,此程序就在第一行命令。Shell脚本经常用于自动化常用命令,执行系统管理和故障排除,创建简单的应用程序,处理文本或文件。
如何创建一个脚本
第一步,使用文本编辑器(vim)创建一个文件,一般都是以.sh结尾,在第一行必须包括shell声明#!(即shebang机制)我们一般使用#!/bin/bash
[root@CT71 bin]# vim test.sh
#!/bin/bash
~
~
~
~
~
~
~
~
~
~ -- INSERT -- , All
第二步,添加注释,shell脚本中的注释都是以#开头,后面跟上注释内容(一般注释写什么,我们一会儿就会说到)
#!/bin/bash
#Filename: test.sh
#Revision: 1.0
#Date: --
#Author: hahaha
#Description: ################
~
~
~
第三步,编写脚本内容,脚本内容可以写我们常用的一些命令,比如查找我们磁盘中使用量最大的百分比等
#!/bin/bash
#Filename: disk.sh
#Revision: 1.0
#Date: --
#Author: hahaha
#Dessciption: df | grep "dev/sd" | tr -s " " % | cut -d"%" -f5 | sort -nr | head -
~
~
~
~
~
第四步,给予脚本执行权限,即chmod +x shellname.sh,最后我们就可以执行我们的脚本了
[root@CT71 bin]# ll | grep "test.sh"
-rw-r--r--. root root Aug : test.sh
[root@CT71 bin]# chmod +x test.sh
[root@CT71 bin]# ll | grep "test.sh"
-rwxr-xr-x. root root Aug : test.sh
接下来我们说说们可以在注释里写啥东西。
1. 第一行一般为调用使用的语言
2. 程序名,避免更改文件名为无法找到正确的文件
3. 版本号
4. 更改后的时间
5. 作者相关信息
6.该程序的作用,及注意事项
7. 最后是各版本的更新简要说明
比如说:
1 #!/bin/bash
2 # Filename: hello.sh
3 # Revision: 1.1
4 # Date: 2017/06/01
5 # Author: wang
6 # Description: This is the first script
脚本调试
我们咋运行脚本之前,可以对脚本进行调试,这样可以保证我们的脚本出错的几率更低,一般我们常用的有两个参数:
检测脚本中的语法错误
bash -n /path/to/some_script
调试执行
bash -x /path/to/some_script
[root@CT71 bin]# bash -x link.sh
+ netstat -tn
+ grep tcp
+ cut -d: -f6
+ sort -nr
+ uniq -c
+ tr -s ' ' :
192.168.111.1
接下来我们开始与脚本内容相关的知识,基础知识包括变量(变量的种类,变量的命令规则,本地变量,环境变量,位置变量),执行后的状态及状态码,算数运算与赋值。
变量相关
在shell脚本中的变量是弱类型的变量,语言的运行时会隐式做数据类型转换。无须指定类型,默认均为字符型;参与运算会自动进行隐式类型转换,变量无须事先定义可直接调用。
变量的命令规则
1. 不能使程序中的保留字:例如if, for
2. 只能使用数字、字母及下划线,且不能以数字开头
3. 见名知义
4. 统一命名规则:驼峰命名法
for:错误
23var:错误
ip_w:正确
var:正确
_min:正确
someIp:正确
bash中变量的种类
根据变量的生效范围等标准:
本地变量:生效范围为当前shell进程;对当前shell之外的其它shell进程,包括当前shell的子shell进程均无效
环境变量:生效范围为当前shell进程及其子进程局部变量:生效范围为当前shell进程中某代码片断(通常指函数)
位置变量: $1, $2, ...来表示,用于让脚本在脚本代码中调用通过命令行传递给它的参数
特殊变量:
$?, $0, $*, $@, $#,$$
在这些变量中,本地变量仅对当前shell有效,对子shell是没有效的。而环境变量对当前shell及其子shell都有效,我们可以用env查询所有的环境变量,用set查询本地变量和环境,我们有一点需要知道,在linux中变量声明以后会一直存在,除非我们把他们给删除掉,删除变量我们可以用unset varname
[root@CT71 bin]# echo $A
string
[root@CT71 bin]# unset A
[root@CT71 bin]# echo $A [root@CT71 bin]# set | grep "^A"
ABRT_DEBUG_LOG=/dev/null
删除了A变量
本地变量
设置变量:
(1) 可以是直接字串; name=“root"
(2) 变量引用: name="$USER"
(3) 命令引用: name=`COMMAND` name=$(COMMAND)
引用变量:
${varname}
$varname
“$varname”
[root@CT71 bin]# myName=BUG
[root@CT71 bin]# echo $myName
BUG
[root@CT71 bin]# echo "$myName"
BUG
[root@CT71 bin]# echo ${myName}
BUG
"":弱引用,其中的变量引用会被替换为变量值
'':强引用,其中的变量引用不会被替换为变量值,而保持原字符串
[root@CT71 bin]# echo "$USER"
root
[root@CT71 bin]# echo '$USER'
$USER
转译:
\ 完全转译
""部分转译 \ ` ! $(""无法转译的字符)
'' 完全转译
转译的原因是因为有些字符在linux下有特殊含义,但是,我们又需要用到它普通意义,所以我们需要对他们转译成非特殊字符供我们使用。
[root@CT71 app]# echo "$20.0"
0.0
[root@CT71 app]# echo "\$20.0"
$20.0
[root@CT71 app]# echo '$20.0'
$20.0
[root@CT71 app]# echo "!ll"
echo "ll"
ll
[root@CT71 app]# echo '!ll'
!ll
环境变量
环境变量的声明:
export name=value
declare -x name=value
环境变量的引用:
$name
${name}
在前面我们已经说过如何查看我们的变量,但是,查看环境变量的命令还有几个,如:env,printenv,export,declare –x,在bash中还有一些内建的环境变量:
PATH:命令查找的路径
SHELL:我们使用的shell
USER:当前用户名
UID:当前用户UID
HOME:家目录
PWD:当前工作目录
SHLVL:当前所在的几级shell
LANG:使用的字符集
MAIL:邮箱路径
HOSTNAME:主机名
HISTSIZE:历史命令记录长度
_:上次执行的命令
[root@CT71 app]# env
XDG_SESSION_ID=
HOSTNAME=CT71 -----------------------------------------------------------------------主机名
SELINUX_ROLE_REQUESTED=
TERM=xterm
SHELL=/bin/bash ---------------------------------------------------------------------使用的shell
HISTSIZE=1000 -----------------------------------------------------------------------历史命令记录长度
SSH_CLIENT=192.168.111.1
SELINUX_USE_CURRENT_RANGE=
SSH_TTY=/dev/pts/
USER=root ---------------------------------------------------------------------------当前用户名
LS_COLORS=rs=:di=;:ln=;:mh=
... ...
MAIL=/var/spool/mail/root --------------------------------------------------------------邮箱路径
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin --------------------命令查找路径
PWD=/app ----------------------------------------------------------------------------当前的工作目录
LANG=en_US.UTF-8 --------------------------------------------------------------------使用的字符集
... ...
SHLVL=1 -----------------------------------------------------------------------------当前所在的几级shell
HOME=/root --------------------------------------------------------------------------当前用户家目录
LOGNAME=root
SSH_CONNECTION=192.168.111.1 52880 192.168.111.110 22
LESSOPEN=||/usr/bin/lesspipe.sh %s
XDG_RUNTIME_DIR=/run/user/0
OLDPWD=/root/bin
_=/usr/bin/env ----------------------------------------------------------------------上次执行的命令
只读和位置变量
我们可以在linux中设置只读变量,它的特点是只能声明,但不能修改和删除
声明只读变量:
readonly name
declare –r name
查看只读变量:
readonly –p
[root@CT71 app]# readonly H=
[root@CT71 app]# H=werq
-bash: H: readonly variable
[root@CT71 app]# readonly -p
declare -r BASHOPTS="checkwinsize:cmdhist:expand_aliases:extglob:extquote:force_fignore:histappend:interactive_comments:login_shell:progcomp:promptvars:sourcepath"
declare -ir BASHPID
declare -r BASH_COMPLETION_COMPAT_DIR="/etc/bash_completion.d"
declare -ar BASH_REMATCH='()'
declare -ar BASH_VERSINFO='([0]="4" [1]="2" [2]="46" [3]="1" [4]="release" [5]="x86_64-redhat-linux-gnu")'
declare -ir EUID=""
declare -r H=""
declare -ir PPID=""
declare -r S
declare -r SHELLOPTS="braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor"
declare -ir UID=""
[root@CT71 app]# unset -f S 删除只读变量
[root@CT71 app]# echo $S [root@CT71 app]#
declare是一个shell的内建命令,用来显示所有变量属性和和值的,它还有一些常用的参数,比如上面的declare –r是用来设置只读变量的,declare –f不仅显示变量,还显示函数,还有declare –x设置环境变量等
位置变量
位置变量其实就是在脚本代码中调用通过命令行传递给脚本的参数。我们可以通过外在的参数传递给脚本以实现与脚本的交互操作,增强脚本功能。
在脚本中的$1,$2,$3…分别对应着脚本外面的第1个,第2个,第3个参数,$0代表的是命令本身,$*是传递给脚本的所有参数,全部参数合为一个字符串
$@是传递给脚本的所有参数,每个参数为独立字符串,$#是传递给脚本的参数的个数($@ $* 只在被双引号包起来的时候才会有差异)
set -- 清空所有位置变量
#!/bin/bash echo "$1"
~
~
-------------------------------------------
[root@CT71 app]# chmod +x test.sh
[root@CT71 app]# ll
total
-rwxr-xr-x. root root Aug : test.sh
[root@CT71 app]# ./test.sh Hello
Hello
#!/bin/bash
echo "filename :$(basename $0)"
~
~
~
-----------------------------------------
[root@CT71 app]# ./test2.sh
filename :test2.sh
#!/bin/bash #tt1.sh
./tt2.sh "$@"
~
~
#!/bin/bash #tt2.sh echo "$@"
~
[root@CT71 app]# ./tt1.sh ---------------------------------------------------------------------
#!/bin/bash #tt1.sh
./tt2.sh "$#"
~
~
#!/bin/bash #tt2.sh echo "$#"
~
[root@CT71 app]# ./tt1.sh
由于我不是在PATH所在的路径下执行的脚本所以直接执行脚本是找不到的,必须要跟上确定的路径./tt2.sh就是在本目录下执行tt2.sh脚本
查询变量
本地变量的查询
set (即查本地,也查环境)
[root@CT71 app]# set | grep -C "^PWD"
PROMPT_COMMAND='printf "\033]0;%s@%s:%s\007" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/~}"'
PS1='[\u@\h \W]\$ '
PS2='> '
PS4='+ '
PWD=/app
SELINUX_LEVEL_REQUESTED=
SELINUX_ROLE_REQUESTED=
SELINUX_USE_CURRENT_RANGE=
SHELL=/bin/bash
环境变量的查询
env
printenv
export
declare -x
[root@CT71 app]# printenv
XDG_SESSION_ID=
HOSTNAME=CT71
SELINUX_ROLE_REQUESTED=
TERM=xterm
SHELL=/bin/bash
HISTSIZE=
SSH_CLIENT=192.168.111.1
SELINUX_USE_CURRENT_RANGE=
... ...
进程的退出状态与状态码
我们在系统中没执行一个命令都会开辟一个进程,配置一个PID,当程序运行结束后,即进程结束后,都会返回一个值给变量“?”,通过返回的值,我们就可以了解到这个进程执行的结果如何,在返回的中,0 代表执行成功,1-255代表着不同的失败,$?变量保存着最近的命令执行后的状态。
除了程序自动的赋值外,我们也可以手动自定义程序退出的状态码,特别是在我们写脚本时,通过条件语句进行判断时,自定义的退出码就派上大用场。
自定义退出状态码:
exit[n] n={1..255}
注意:脚本中一旦遇到exit命令,脚本会立即终止;终止退出状态取决于exit命令后面的数字
注意:如果未给脚本指定退出状态码,整个脚本的退出状态码取决于脚本中执行的最后一条命令的状态码
#!/bin/bash echo "Myname is Tony!" exit echo "Show my name"
~
~
--------------------------------------------------
[root@CT71 app]# chmod +x tt3.sh
[root@CT71 app]# ./tt3.sh
Myname is Tony!
在这我们多说一点东西,如何查看进程以及PID,这里有几个变量和命令,我们来看一下:
变量$$:查看当前的PID
PPID:查看父进程的PID
SHLVL:显示当前的shell是几级shell
pstree:显示进程树
-p:同时显示进程的PID
ps –ef :显示进程信息
[root@CT71 app]# echo $$ [root@CT71 app]# echo $PPID [root@CT71 app]# pstree -p | grep -C "bash"
| `-{rsyslogd}()
|-smartd()
|-sshd()---sshd()---bash()-+-grep()
| `-pstree()
|-systemd-journal()
[root@CT71 app]# echo $SHLVL [root@CT71 app]# ps -ef | grep "bash"
root Jul31 ? :: /bin/bash /usr/sbin/ksmtuned
root : pts/ :: -bash
root : pts/ :: grep --color=auto bash