shell脚本之变量与状态码

目录:

   前言

如何创建一个脚本

脚本调试

变量相关

变量的命令规则

bash中变量的种类

本地变量

环境变量

只读和位置变量

位置变量

查询变量

进程的退出状态与状态码

前言

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
 1 #!/bin/bash
 2 ~                                                                                                    
 3 ~                                                                                                    
 4 ~                                                                                                    
 5 ~                                                                                                    
 6 ~                                                                                                    
 7 ~                                                                                                    
 8 ~                                                                                                    
 9 ~                                                                                                    
10 ~                                                                                                    
11 ~                                                                                                    
12                                                                                                 
13 -- INSERT --                                                                   1,12   All

第二步,添加注释,shell脚本中的注释都是以#开头,后面跟上注释内容(一般注释写什么,我们一会儿就会说到)

1 #!/bin/bash
2 #Filename: test.sh
3 #Revision: 1.0
4 #Date: 2017-8-2
5 #Author: hahaha
6 #Description: ################ 
~
~
~

 第三步,编写脚本内容,脚本内容可以写我们常用的一些命令,比如查找我们磁盘中使用量最大的百分比等

  1 #!/bin/bash
  2 #Filename: disk.sh
  3 #Revision: 1.0
  4 #Date: 2017-8-2
  5 #Author: hahaha
  6 #Dessciption: 
  7 
  8 df | grep "dev/sd" | tr -s " " % | cut -d"%" -f5 | sort -nr | head -1
~                                                                                                    
~                                                                                                    
~                                                                                                    
~                                                                                                    
~                      

第四步,给予脚本执行权限,即chmod +x shellname.sh,最后我们就可以执行我们的脚本了

[root@CT71 bin]# ll | grep "test.sh"
-rw-r--r--. 1 root root    0 Aug  3 16:06 test.sh
[root@CT71 bin]# chmod +x test.sh
[root@CT71 bin]# ll | grep "test.sh"
-rwxr-xr-x. 1 root root    0 Aug  3 16:06 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 ' ' :
      1 192.168.111.1

接下来我们开始与脚本内容相关的知识,基础知识包括变量(变量的种类,变量的命令规则,本地变量,环境变量,位置变量),执行后的状态及状态码,算数运算与赋值。

变量相关

shell脚本中的变量是弱类型的变量,语言的运行时会隐式做数据类型转换。无须指定类型,默认均为字符型;参与运算会自动进行隐式类型转换,变量无须事先定义可直接调用。

变量的命令规则

1.  不能使程序中的保留字:例如if, for

2.  只能使用数字、字母及下划线,且不能以数字开头

3. 见名知义

4.  统一命名规则:驼峰命名法

1 for:错误
2 23var:错误
3 ip_w:正确
4 var:正确
5 _min:正确
6 someIp:正确

bash中变量的种类

根据变量的生效范围等标准:

本地变量:生效范围为当前shell进程;对当前shell之外的其它shell进程,包括当前shell的子shell进程均无效

环境变量:生效范围为当前shell进程及其子进程局部变量:生效范围为当前shell进程中某代码片断(通常指函数)

位置变量: $1, $2, ...来表示,用于让脚本在脚本代码中调用通过命令行传递给它的参数

特殊变量:

 $?, $0, $*, $@, $#,$$

 

在这些变量中,本地变量仅对当前shell有效,对子shell是没有效的。而环境变量对当前shell及其子shell都有效,我们可以用env查询所有的环境变量,用set查询本地变量和环境,我们有一点需要知道,在linux变量声明以后会一直存在,除非我们把他们给删除掉,删除变量我们可以用unset varname

 $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}

在前面我们已经说过如何查看我们的变量,但是,查看环境变量的命令还有几个,如:envprintenvexportdeclare –x,在bash中还有一些内建的环境变量

PATH:命令查找的路径

SHELL:我们使用的shell

USER:当前用户名

UID:当前用户UID

HOME:家目录

PWD:当前工作目录

SHLVL:当前所在的几级shell

LANG:使用的字符集

MAIL:邮箱路径

HOSTNAME:主机名

HISTSIZE:历史命令记录长度

_:上次执行的命令

 

[root@CT71 app]# env
XDG_SESSION_ID=612
HOSTNAME=CT71  -----------------------------------------------------------------------主机名
SELINUX_ROLE_REQUESTED=
TERM=xterm
SHELL=/bin/bash  ---------------------------------------------------------------------使用的shell
HISTSIZE=1000  -----------------------------------------------------------------------历史命令记录长度
SSH_CLIENT=192.168.111.1 52880 22
SELINUX_USE_CURRENT_RANGE=
SSH_TTY=/dev/pts/2
USER=root  ---------------------------------------------------------------------------当前用户名
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00
... ...
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=2134
[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="0"
declare -r H="2134"
declare -ir PPID="57929"
declare -r S
declare -r SHELLOPTS="braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor"
declare -ir UID="0"
[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 -- 清空所有位置变量

  1 #!/bin/bash
  2 
  3 echo "$1"
~                                                                                                    
~  
-------------------------------------------
[root@CT71 app]# chmod +x test.sh 
[root@CT71 app]# ll
total 4
-rwxr-xr-x. 1 root root 23 Aug  3 19:22 test.sh
[root@CT71 app]# ./test.sh Hello
Hello
  1 #!/bin/bash
  2 echo "filename :$(basename $0)"
~                                                                                                    
~                                                                                                    
~      
-----------------------------------------

[root@CT71 app]# ./test2.sh
filename :test2.sh

  1 #!/bin/bash     #tt1.sh   
  2 ./tt2.sh "$@"
~                                                                                                    
~                 
  1 #!/bin/bash    #tt2.sh    
  2 
  3 echo "$@"
~             
[root@CT71 app]# ./tt1.sh 1 2 3 4 5
1 2 3 4 5
---------------------------------------------------------------------
  1 #!/bin/bash     #tt1.sh   
  2 ./tt2.sh "$#"
~                                                                                                    
~                 
  1 #!/bin/bash    #tt2.sh    
  2 
  3 echo "$#"
~             
[root@CT71 app]# ./tt1.sh 1 2 3 4 5
1

由于我不是在PATH所在的路径下执行的脚本所以直接执行脚本是找不到的,必须要跟上确定的路径./tt2.sh就是在本目录下执行tt2.sh脚本

查询变量

本地变量的查询

   set (即查本地,也查环境)

[root@CT71 app]# set | grep -C 4 "^PWD"
PROMPT_COMMAND='printf " 33]0;%s@%s:%s 07" "${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=612
HOSTNAME=CT71
SELINUX_ROLE_REQUESTED=
TERM=xterm
SHELL=/bin/bash
HISTSIZE=1000
SSH_CLIENT=192.168.111.1 52880 22
SELINUX_USE_CURRENT_RANGE=
... ...

进程的退出状态与状态码

我们在系统中没执行一个命令都会开辟一个进程,配置一个PID,当程序运行结束后,即进程结束后,都会返回一个值给变量“?”,通过返回的值,我们就可以了解到这个进程执行的结果如何,在返回的中,0 代表执行成功,1-255代表着不同的失败$?变量保存着最近的命令执行后的状态。

除了程序自动的赋值外,我们也可以手动自定义程序退出的状态码,特别是在我们写脚本时,通过条件语句进行判断时,自定义的退出码就派上大用场。

自定义退出状态码:

   exit[n] n={1..255}

注意:脚本中一旦遇到exit命令,脚本会立即终止;终止退出状态取决于exit命令后面的数字

注意:如果未给脚本指定退出状态码,整个脚本的退出状态码取决于脚本中执行的最后一条命令的状态码

  1 #!/bin/bash
  2 
  3 echo "Myname is Tony!"
  4 
  5 exit 1
  6 
  7 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 $$
57933
[root@CT71 app]# echo $PPID
57929
[root@CT71 app]# pstree -p | grep -C 2 "bash"
           |                `-{rsyslogd}(2281)
           |-smartd(577)
           |-sshd(1401)---sshd(57929)---bash(57933)-+-grep(61485)
           |                                        `-pstree(61484)
           |-systemd-journal(367)
[root@CT71 app]# echo $SHLVL
1
[root@CT71 app]# ps -ef | grep "bash"
root        607      1  0 Jul31 ?        00:00:14 /bin/bash /usr/sbin/ksmtuned
root      57933  57929  0 14:09 pts/2    00:00:01 -bash
root      61495  57933  0 20:05 pts/2    00:00:00 grep --color=auto bash