Shell脚本完全说明

1 什么是shell

        shell是一个命令解释器,位于操作系统的最外层,它负责和用户直接对话,不用户输入的内容解释给操作系统,操作系统处理完毕后,输出结果,输出到屏幕上。分为交互式的和非交互式的。输入命令,得到结果。就是交互式的,执行脚本就是非交互的。
总结:shell就像是一座桥梁,连通用户和操作系统。

2 什么是shell脚本

        把一个或多个linux命令组合起来放在一个程序文件中执行,这样的程序叫做shell脚本。严格来说把命令.变量和流程控制语句等结合在一起,就是shell脚本

2.1 如何写一个思路缜密的shell脚本

        要多去模拟操作,多去想想为什么

2.2 shell的特点

        linux中所有的配置文件.日志文件都是纯文本文件。而shell的特点就是善于处理纯文本的内容。

2.3 shell的分类

        bourne shell(包括 sh,ksh,bash) C shell(csh,tcsh)
        查看系统支持的sh类型:/etc/shells,常用的就是/bin/sh,/bin/bash,/sbin/nologin
        Linux主流的shell就是bash,它是bourne again shell的缩写,是由bonrne shell发展而来,它还包含了csh和ksh的特色。
        目前:通用的bourne shell 已经被bash shell取代

2.4 其他脚本语言

  1. php:主要用于web页面开发,适合wab前端展示
  2. perl:比shell强大,语法灵活,实现方式很多,不易读,其中mysql的HA就是由perl写的
  3. python:近几年很火的软件,不但可以开发前端,也可以开发后端,属于全能型语言

2.5 常用系统的默认shell

        Linux:bash
        solaris:bonrne sh
        AIX:ksh
        HP-unix:posix shell(sh)

2.6 修改用户默认的shell

        可以修改/etc/default/useradd文件的shell字段,更改新添加的用户。也可以直接修改/etc/passwd中的最后一个字段,直接修改某个用户的shell。

2.7 shell脚本的建立

        通过vim编辑器编写shell脚本 ,注意脚本的第一行 #!/bin/bash 表示来指定解释器

注意:python 程序开头 #!/usr/bin/env python因为Linux默认就是使用bash,所以使用bash的话,可以不用加,为了规范还是要添加。如果不指定解释器,就需要用bash test.sh来执行了。
注意:写脚本要写注释

2.8 shell脚本的执行

        当shell运行时,它会先查找系统环境变量ENV,该变量指定了环境文件(通常是.bashrc,.bash_profile,/etc/bashrc,/etc/profile等),然后从该环境变量文件开始执行脚本,当读取了ENV的文件后,shell会开始执行shell脚本中的内容。
注意:设置cron任务时,最好把系统变量在脚本中重新定义一遍
shell脚本的执行通常采用以下几种方式

  1. bash scripts-name 或 sh scripts-names (推荐)
  2. patch/scripts-name 或 ./scripts-names (需要脚本有执行权限)
  3. source scripts-name 或 . scripts-names (执行脚本的同时,使父shell继承子shell的变量)
  4. sh

注意:我们用户登录的时候会默认分配一个shell,这个shell就是父shell,而在这个shell中执行的shell脚本,就属于子shell,父shell是不能直接继承子shell的变量的,但子shell可以直接继承父shell的变量,如果想要父shell获取子shell中的变量,就需要使用source或者.来执行脚本了。(相当于php中的include)

3 shell脚本开发基本规范

  1. 脚本第一行指定解释器
#!/bin/bash或者#!/bin/sh
  1. 脚本开头加版权信息
#Date:
#Author: create by lixin
#Mail:
#Function:功能
  1. 脚本中不用中文注释
  2. 脚本使用.sh作为扩展名
  3. 写代码优秀习惯
    • 成对的符号尽量一次打出来,防止遗漏
    • [ a ]中括号两端要有空格,书写的时候就街上,[[ a ]]双中括号也是如此。
    • 流程控制语句一次书写完,在添加内容

4 shell变量基础及深入

4.1 什么是变量

        比如x=1,y=x+1,那么y等于2。x和y就是变量名,x变量的值是1,而y变量的值是x+1,等号在这里叫做赋值。
简单的说,变量就是用一个固定的字符串(也可能是字符数字等的组合),代替更多更复杂的内容,这个内容里可能还会包含变量.路径.字符串等其他的内容。
变量是暂时存数据的地方,这个存储的数据是存在于内存空间中的,通过调用变量的名字就可以取出变量对应的数据。

4.2 shell的变量特性

        bash shell中默认的情况下是不会区分变量的内容的类型,例如:整数.字符串.小数等。这一点和其他强类型语言是有区别的。如果需要指定shell变量内容类型,可以使用declare显示指定定义变量的类型(没这个需求)。

4.2.1 变量的类型

        变量可以分为:环境变量(全局变量)和普通变量(局部变量)。
        环境变量也成为全局变量,可以在创建他们的shell及其派生出来的任意子进程shell中使用,环境变量又可以分为自定义环境变量和bash内置的环境变量。
        普通变量也可成为局部变量,只能在创建他们的shll函数或shell脚本中使用。普通变量一般是由开发者在开发脚本程序时创建的。

4.2.2 环境变量

        环境变量一般用于定义shell的运行环境,保证shell命令的正确执行,shell通过环境变量来确定登录用户名.命令路径.终端类型.登录目录的等,所有的环境变量都是系统全局变量,可用于所有子进程中,这包括编辑器.shell脚本和各类应用(cron任务比较特殊需要注意)。
        环境变量可以在命令行中设置创建,但用户退出命令是这些变量值就会丢失,因此,如果希望永久保存环境变量,可以在用户家目录下.bash_profile或.bashrc文件或全部配置文件/etc/profile或/etc/bashrc文件或者/etc/profile.d/下定义,因为每次用户登录时这些变量的值都会被初始化一次。
        所有环境变量名字格式均为大写,环境变量用于用户进程程序前,都应该用export命令导出定义,例如:export KEY=1.
        环境变量可以在创建他们的shell和从该shell派生的任意子shell或进程中,他们通常被称为全局变量以区别局部变量。通常,环境变量应该大写。环境变量是已经用export内置命令导出的变量。
        有一些环境变量,比如HMOE.PATH.SHELL.UID.USER等,在用户登录之前就已经被/bin/login程序设置好了,通常环境变量定义并保存在用户家目录下的.bash_profile中。

4.2.2.1 定义全局变量格式

  1. export 变量名=value;
  2. 变量名=value;export 变量名
  3. declare -x 变量名=value
    注意:如果是java环境,最后再脚本里面再定义一遍java环境变量。

4.2.2.2 显示与取消环境变量

        通过echo或printf命令打印环境变量
例:

打印用户登录的目录: echo $HOME
打印用户的UID: printf $UID
使用env和set命令查看所有的环境变量
通过unset命令取消环境变量: unset NAME

4.2.2.3 环境变量小结

  1. 变量名通常要大写
  2. 可以在自身的shell以及子shell中使用
  3. 通过export来定义
  4. 查看使用echo $NAME
  5. 删除使用unset NAME
  6. 永久生效写入到用户环境变量文件,或者全局环境变量文件中。
  7. 写定时任务的时候,注意在脚本中添加环境变量(java)。

4.2.3 普通变量

        本地变量再用户当前的shell生存期的脚本中使用,例如,本地变量key的取值为123,这个值只在用户当前shell生存期中有意义。如果在shell中启动另一个进程或退出,本地变量key值将无效。

4.2.3.1 定义普通变量

定义普通变量的方法:

  1. 变量名=value
  2. 变量名=‘value’
  3. 变量名=“value”

其中,变量名一般是有字符,数字,下划线组成。可以字符或下划线开头,但是不能以数字开头。
变量的内容,可以用单引号或双引号引起来,或不加引号。三者的区别是;不加引号,不能输入不连续的值,只要变量连续,可以解释其中引用的其他变量。单引号和echo中的单引号相同,就是内部有变量则不会解释变量,双引号即如果定义的值中引用其他变量,则解释该变量,变量的值可以是不连续的。而反引号,一般用来解析命令,相当于$().

例子:
 a=192.168.1.2
 b='192.168.1.2-$a'
 c="192.168.1.2-$a"
 echo $a
 192.168.1.2
echo $b
       192.168.1.2-$a
echo $c
 192.168.1.2-192.168.1.2

a=192.168.1.2-$a
b='192.168.1.2-$a'
c="192.168.1.2-$a"
echo $a
       192.168.1.2-192.168.1.2
echo $b
       192.168.1.2-$a
echo $c
       192.168.1.2-192.168.1.2-192.168.1.2
注意:日常定义变量如果是纯数字的话可以不加引号,其他情况建议都使用双引号。
扩展:把命令的结果作为变量
变量名=`ls`或者 变量名=$(ls)

4.2.3.2 普通变量小结

  1. 连续的数字字符串可以不加引号
  2. 变量内容是命令的结果,定义时可以使用反引号或$().
  3. 若变量和其他字符连接的时候,就必须给变量加上大括号{}。_${key}keyname;

4.2.3.3 变量的高级应用

定义变量后可以直接在各个地方调用

key=init
grep $key /etc/iniitab
grep "$key" /etc/inittab
# 上面两个会过滤出/etc/inittab中包含init字符串的行
grep '$key' /etc/inittab
# 单引号,则会过滤出/etc/inittab中包含$key的行,同样适用于sed。

注意:awk中不同于grep和sed中
awk中的特殊用法1:

key=init
awk 'BEGIN{print "$key"}'
# awk中""是不解释变量的,和常规的相反,只有使用单引号才会解析。
awk 'BEGIN{print '$key'}'
# 不加引号,则不会输出

awk中的特殊用法2:

key='int'
awk 'BEGIN{print '$key'}'
# 这时也是不会输出内容的,需要在单引号外面再加一层双引号才可以
awk 'BEGIN{print "'$key'"}'

4.2.4 shell的特殊重要变量

4.2.4.1 位置变量

        KaTeX parse error: Expected group after '_' at position 2: 0_̲_ 获取当前执行的shell脚…n 获取当前执行的shell脚本的第n个参数的值,n=1…9,当n为0时表示脚本的文件名,如果n大于9,用大括号括起来${10}.例子:

# 创建测试文件:
[root@CentOS6 ~]# echo -n 'echo ' > test1.sh && echo \${1..15} >> test.sh
[root@CentOS6 ~]# cat test.sh
echo $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 $14 $15 $16
[root@CentOS6 ~]# bash test.sh {a..z}
a b c d e f g h i a0 a1 a2 a3 a4 a5 a6
# 由于变量超过了9个,所以从第10个变量开始要加大括号,不然shell认为$10,是$1的值和0组合在一起,所以才会显示a0
[root@CentOS6 ~]# cat test.sh
echo $1 $2 $3 $4 $5 $6 $7 $8 $9 ${10} ${11} ${12} ${13} ${14} ${15} ${16}
[root@CentOS6 ~]# bash test.sh {a..z}
a b c d e f g h i j k l m n o p
# $# 表示脚本传参的个数,脚本名称后面的参数的个数.
# $* 将命令行脚本所有参数视为单个字符串等同于"$1$2$3",$*要用双引号。
# $@ 将命令行脚本每个参数视为单独的字符串,等同于"$1","$2","$3",这是将参数传递给其他程序的最佳方式,因为他会保留所有内嵌在每个参数里的任何空白。
# 注意:上述区别仅限于添加双引号的时候,即"$*"和$"@"
例:
[root@CentOS6 scripts]# set -- a b c
[root@CentOS6 scripts]# for i in "$@" ;do echo $i; done;
a
b
c
[root@CentOS6 scripts]# for i in "$*" ;do echo $i; done;
a b c
[root@CentOS6 scripts]#

4.2.4.2 进程状态变量

        $? 查看上一个命令的执行结果。0表示成功,非0表示不成功。

错误代码返回值参考:
2:权限不够
1-125:表示运行失败(脚本命令.系统命令错误或参数传递错误)
126:找到该命令了,但无法执行
127:命令找不到
128:被强制中断了
注意:在shell脚本中一般用exit 数字,来把返回值传递给 ? 如 果 是 函 数 , 则 通 过 r e t u r n 数 字 , 返 回 返 回 值 给 ? 如果是函数,则通过return 数字,返回返回值给 ?return?
扩展:通过set命令进传参
http://httpd.blog.51cto.com/2561410/1175971

set -- 'i am' handsome boy 传递3个参数到shell
set -- 1 2 3
[root@CentOS6 ~]# echo $1 $2 $3
1 2 3
# $$ 显示当前进程的进程号
# $! 上一个进程的id号
cat pid.sh
echo $$ >/tmp/a.pid
sleep 300

sh pid.sh &
cat /tmp/a.pid

4.2.4.3 bash内置命令

        bash的内置命令,这些命令内置在bash中,没有绝对路径,需要时可以直接在shell脚本中调用 alias, bg, bind, break, builtin, caller, cd,command, compgen, complete, compopt, continue, declare, dirs,disown, echo, enable, eval, exec, exit, export, false, fc,fg, getopts, hash, help, history, jobs, kill, let, local,logout, mapfile, popd, printf, pushd, pwd, read, readonly,return, set, shift, shopt, source, suspend, test, times,trap, true, type, typeset, ulimit, umask, unalias, unset,wait

4.2.4.4 变量子串

        通过man bash找到Parameter Expansion来查看子串的全部用法
        ${#变量名}取变量的长度

[root@CentOS6 ~]# httpd="I am httpd"
[root@CentOS6 ~]# echo $httpd
I am httpd
[root@CentOS6 ~]# echo $httpd|wc -L
11
[root@CentOS6 ~]# echo ${#httpd}
11

        通过使用expr命令计算变量的长度

[root@CentOS6 ~]# expr length "$httpd"
11

# 计算I am good boy,welcome to myhome中字母小于5个的并打印
for i in I am good boy,welcome to myhome
do
[ ${#i} -lt 5 ] &&{
   
  echo "$i"
}
done

        ${变量:2}截取变量的第几个字符到最后

[root@CentOS6 ~]# httpd="I am httpd"
[root@CentOS6 ~]# echo ${httpd:2}
am httpd
[root@CentOS6 ~]# echo ${httpd:3}
m httpd

        ${#变量:n:m}从第n个字符开始截取m个

[root@CentOS6 ~]# echo ${httpd:2:2}
am

        ${变量#字符串}从开头开始匹配,删除最短匹配字符串的值

[root@CentOS6 scripts]# echo $LIXIN
123123123123123123123123456
[root@CentOS6 scripts]# echo ${LIXIN#1*3}
123123123123123123123456

        ${变量##字符串}从开头开始匹配,删除最长匹配字符串的值

[root@CentOS6 scripts]# echo ${LIXIN##1*3}
456
[root@CentOS6 scripts]# echo $LIXIN
i am good boy boy
[root@CentOS6 scripts]# echo ${LIXIN%b*y}
i am good boy
[root@CentOS6 scripts]# echo ${LIXIN%%b*y}
i am good
[root@CentOS6 scripts]#

小结:

  1. #是开头删除匹配最短
  2. ##是开头删除匹配最长
  3. %是结尾删除匹配最短
  4. %%是结尾删除匹配最长

        ${变量/字符串1/字符串2},从开头开始,把变量中的字符串1替换为字符串2.

[root@CentOS6 scripts]# LIXIN="i am good boy boy"
[root@CentOS6 scripts]# echo $LIXIN
i am good boy boy
[root@CentOS6 scripts]# echo ${LIXIN/boy/girl}
i am good girl boy
[root@CentOS6 scripts]# echo ${LIXIN//boy/girl}
i am good girl girl
两个斜线表示替换所有符合的字符串
[root@CentOS6 scripts]# echo ${LIXIN/#boy/girl}
i am good boy boy
#表示以boy开头的,替换为girl,由于变量LIXIN没有以boy开头,所以不会替换
[root@CentOS6 scripts]# echo ${LIXIN/%boy/girl}
i am good boy girl
[root@CentOS6 scripts]#

4.2.4.5 变量替换

${values:-word} 如果变量名称存在并且非null,则返回变量的值。否则返回word字符串,表示如果变量未定义,则返回默认值。

[root@CentOS6 scripts]# echo ${lixin:-test}
test
[root@CentOS6 scripts]# lixin=123
[root@CentOS6 scripts]# echo ${lixin:-test}
123
[root@CentOS6 scripts]# echo $lixin

${value:=word} 如果变量名存在且非null,则返回变量值。否则,设置这个变量为word,并返回其值

[root@CentOS6 scripts]# echo ${lixin:=test}
test
[root@CentOS6 scripts]# echo $lixin
test
[root@CentOS6 scripts]#

注意:-和=的区别是,-表示变量为空的时候返回的默认值,这个默认值并不会被赋予变量,所以echo变量的时候依旧为空,=表示如果变量为空,则把word赋予该变量。
扩展:这个冒号:也可以不加,功能和加上是相同的

[root@CentOS6 scripts]# unset LIXIN
[root@CentOS6 scripts]# echo ${LIXIN-test}
test
[root@CentOS6 scripts]# LIXIN=1
[root@CentOS6 scripts]# echo ${LIXIN-test}
1
[root@CentOS6 scripts]#
[root@CentOS6 scripts]# unset LIXIN
[root@CentOS6 scripts]# echo ${LIXIN=test}
test
[root@CentOS6 scripts]# echo $LIXIN
test
[root@CentOS6 scripts]#

4.2.4.6 变量的数值(整数)计算

变量的数值计算常见的有如下几个命令:(()),let,expr,bc(小数运算),${},其他都是整数。
常用运算符号:

  • ++,–:增加或减少,可以前置也可以放在末尾
  • +,-,*,/,%:分别对应加.减.乘,除,求余
  • <,<=,>,>=:分别对应小于,小于等于,大于,大于等于
  • ==,!=:等于,不等于
  • &&:逻辑和,即command1 && comand2 ,command1成功则执行command2。
  • ||:逻辑或,即command1 || comand2,command1不成功则执行command2。
  • =,+=,-=,=,/=,%=,赋值运算符,a+=1,表示a=a+1,a=1,表示a=a*1。

1.(())用法
如果要执行简单的整数就算,只需要将特定的算数表达式用$(())括起来即可。

[root@CentOS6 scripts]# echo $((1+2))
3
[root@CentOS6 scripts]# echo $(1+2)
-bash: 1+2: command not found

[root@CentOS6 scripts]#
[root@CentOS6 scripts]# ((a=1+2**3-4%3))
[root@CentOS6 scripts]# echo $a
8
[root@CentOS6 scripts]#
+=例子:
[root@CentOS6 scripts]# echo $a
8
[root@CentOS6 scripts]# echo $((a+=1))
9
[root@CentOS6 scripts]# echo $a
9
[root@CentOS6 scripts]# echo $((a-=1))
8
[root@CentOS6 scripts]# echo $a
8
[root@CentOS6 scripts]#
n++例子:
[root@CentOS6 scripts]# echo $a
8
[root@CentOS6 scripts]# echo $((a++))
8
[root@CentOS6 scripts]# echo $a
9
[root@CentOS6 scripts]# echo $((a--))
9
[root@CentOS6 scripts]# echo $a
8
[root@CentOS6 scripts

你可能感兴趣的:(Linux基础,Linux,Linux,shell,shell脚本,shell)