SHELL脚本编程基础

  • 编程基础
  • 脚本基本格式
  • 变量
  • 运算
  • 条件测试
  • 条件判断if
  • 条件判断case
  • 配置用户环境

1.编程基础

linux:Talk is cheap, show me the code(少说废话,拿你的脚本过来)
程序
    程序:算法+数据结构
    数据:是程序的核心 
    数据结构:数据在计算机中的类型和组织方式
    算法:处理数据的方式
程序编程风格:
    过程式:以指令为中心,数据服务于指令
    对象式:以数据为中心,指令服务于数据
shell程序:提供了编程能力,解释执行

2.程序的执行方式

计算机:运行二进制指令   
编程语言:人与计算机之间交互的语言  
低级编程语言:  
    机器:二进制的0和1的序列,称为机器指令。与自然语言差异太大,难懂、难写  
    汇编:用一些助记符号替代机器指令,称为汇编语言  
          如:ADD A,B 将寄存器A的数与寄存器B的数相加得到的数放到寄存器A中  
          汇编语言写好的程序需要汇编程序转换成机器指令  
          汇编语言稍微好理解,即机器指令对应的助记符,助记符更接近自然语言  
    高级编程语言:  
          编译:高级语言 --> 编译器 --> 执行  
                C,C++  
          解释:高级语言 -->执行 --> 解释器-->机器代码  
                shell,python,php,JavaScript,perl  

3.编程基本概念

编程逻辑处理方式:
    顺序执行
    循环执行
    选择执行
shell编程:过程式、解释执行
    编程语言的基本结构:
        各种系统命令的组合
        数据储存:变量、数组
        表达式:a+b
        语句:if

4.shell脚本基础

4.1 shell脚本

shell脚本:
    包含一些命令或声明,并符合一定格式的文本文件
格式要求:首行shebang机制
    #!/bin/bash
    #!/usr/bin/python
    #!/usr/bin/perl
shell脚本的用途有:
    自动化常用命令
    执行系统管理和故障排除
    创建简单的应用程序
    处理文本或文件

4.2 执行脚本的方法

    1. bash /data/scripts37/hello.sh 
    2. cat /data/scripts37/hello | bash

    3. /data/scripts37/hello.sh 加执行权限 chmod+x
       cd /data/scripts37/
       ./hello.sh

    4. vim /etc/profile.d/evn.sh 
        PATH=/data/scripts37/:$PATH 
  • 遇到的问题

    echo > hello.sh < #!/bin/bash
    > echo "hello word"
    > EOF
    echo 是标准输出 
    这段脚本的意思是将空文件输入到hello.sh 然后进行多行重定向
    
    cat > hello.sh < #!/bin/bash
    > echo "hello word"
    > EOF
    cat 是标准输入
    将多行重定向输入到hello.sh 

5 变量

变量:命令的内存空间
变量:变量类型
    作用:
        1.数据储存
        2.参与的运算
        3.表示的数据范围
    类型:
        字符
        数值:整型、浮点型

5.1 编译语言

静态编译语言:使用变量前,先声明变量类型,之后类型不能改变,在编译时检查,如:java,c 
动态编译语言:不用事先声明,可随时改变类型,如bash,Python
强类型语言:不同类型数据操作,必须经过强制转换成同一类型才能运算,如java,c#,python 
            如:以下python代码
                print('magedu'+10)  提示出错,不会自动转换类型
                print('magedu'+str(10))  结果为magedu10,需要显示转换类型
弱类型语言:语言的运行时会隐式做类型转换。无须事先定义可直接调用
            如:bash不支持浮点数,php,javascript

5.2 Shell中变量命名法则

Shell中变量命名法则:
    1.不能使用程序中保留字:例如if,for
    2.只能使用数字、字母及下划线,且不能以数字开头
    3.见名知义
    4.统一命令规则:驼峰命名法
Shell中命名建议规则:
    1.变量名大写
    2.局部变量小写
    3.函数名小写
    4.用英文名字,并体现出实际作用

5.3 bash中变量的种类

    根据变量的生效范围等标准划分下面变量类型
    局部变量:生效范围为当前shell进程;对当前shell之外的其它shell进程,包括当前shell的子shell进程均无效
    环境变量:生效范围为当前shell进程及其子进程 
    本地变量:生效范围为当前shell进程中某代码片段,通常指函数
    位置变量:$1,$2,...来表示,用于让脚本在脚本代码中调用通过命令行传递给他的参数
    特殊变量:$?,$0,$*,$@,$#,$$

5.4 局部变量

变量赋值:name='value'
可以使用引用value
    (1)可以是直接字串:name="root"
    (2)变量引用:name="$USER"
    (3)命令引用:name=`COMMAND`
                 name=$(COMMAND)
变量引用:${name}或者$name
    " " 弱引用,其中的变量引用会被替代为变量值
    ' ' 强引用,其中的变量引用不会被替换为变量值,而保持原字符串
显示已定义的所有变量:set
删除变量:unset name  

单引号、双引号、反向单引号的区别:

1.由单引号'',强引用,其中的变量会被替换未变量值
2.由双引号"",弱引用,其中的变量不会被替换未变量值,而保持原来字符串。
3.反向单引号``,括起来的字符被shell解释为命令行,在执行时,shell首先执行该命令,并以它的标准输出结果取代整个反括号(包括两个反引号)部分
将命令放到变量里
然后引用变量就可以执行   
例:CMD=hostname
    $CMD 
   #centos7.localdomain

如果不是命令
直接echo输出就行
例:NAME=adong
    echo $NAME
    adong

如果想要将一个带空格的字符串完整的赋值给变量,需要加双引号"",确保它是一个整体
例:NAME="wei xiao dong"
    echo $NAME
    wei xiao dong 

变量赋值不能加空格 

将文件内容赋值给变量,显示原文件,需要echo的时候加" "
例: FILE=`cat /etc/issue`

     echo "$FILE"
     \S
     Kernel \r on an \m
bash是后台命令
echo $BASHPID 可以查看bash进程编号
进程编号系统随机分配 

局部变量中,当前用的变量只对当前环境有效,开启子进程之后失效

5.5 环境变量

主要用来配置工作环境

变量声明、赋值:
    export name =VALUE 
    declare -x name =VALUE 

如果变量已经被定义过,可以直接用exprot声明
NAME=adong
echo $NAME
adong
export NAME

export NAME = wang 声明变量的同时赋值

环境变量具有继承性,可以将变量传给子进程,子子进程..
在子进程中可以更改变量,但是不可以传递给父进程
环境变量只需要声明一次,他的子进程,子子进程可以一直用,或者修改
只要定义一次环境变量,他将一直作为环境变量

echo $BASHPID 查看当前变量进程
echo $PPID    查看当前变量的父进程

变量引用:
    $name,${name} 

显示所有环境变量:
    env
    printenv
    export 
    declare -x

删除变量:
    unset name  (普通变量,环境变量都适用)
    子进程只能删除子进程以下的变量

- bash内建的环境变量  主要是做系统配置用(系统自带的)
    - PATH 
    - SHELL 
    - USER 
    - UID 
    - HOME 
    - PWD 
    - SHLVL      bash的嵌套深度
    - LANG       语言 
    - MAIL 
    - HOSTNAME 
    - HISTSIZE 
    - _ 下划线   记录了上一个命令的最后一个字符串

EDITOR  定义默认的编辑器 
将EDITOR作为环境变量写入/etc/profile.d/env.sh
crontab -e 定时任务 会开启子进程 
如果不将EDITOR作为环境变量,将对EDITOR无效

bash运行自动读取配置文件   /etc/profile.d/env.sh   

5.6 只读变量

只读变量(常量):只能声明,但不能修改和删除
    声明只读变量:
        readonly name:
        declare -r name 
    查看只读变量:
        readonly -p 
    exit 退出当前bash  只读变量失效

5.7 位置变量

用来表示变量所在的位置

在脚本代码中调用通过命令行传递给脚本的参数
    $1,$2,... ${10},$(11) 对应第1,第2等参数,shift[n]换位置
    $0 命令本身
    $* 传递给脚本的所有参数,全部参数合为一个字符串
    $@ 传递给脚本的所有参数,每个参数为独立字符串
    $# 传递给脚本的参数的个数
         注意:$@ $* 只在被双引号起来的时候才会有差异
    set -- 清空所有位置变量

5.7.1 特殊变量

echo $$            进程名称
2361
echo $BASHPID      当前所在进程 
2361 
echo $PPID         当前父进程 
2359 

5.8 退出状态

进程使用退出状态来报告成功或失败
0 代表成功,1-255代表失败
$?变量保存最近的命令退出状态
$?只看最后一条命令是否正确,最后一条命令正确返回0
例如:
    ping -c1 -W1 hostdown &> /dev/null
    echo $?

在脚本最后一行
exit  100(想要的返回值)
执行脚本 如果正确就会返回100

5.9退出状态码

    bash 自定义退出状态码
    exit[n]:自定义退出状态码 
    注意:脚本中一旦遇到exit命令,脚本会立即终止;终止退出状态取决于exit命令后面的数字
    注意:如果未给脚本指定退出状态码,整个脚本放人退出状态取决于脚本中执行的最后一条命令的状态码

6.0 算数运算

bash中的算数运算:help let
    +,-,*,/,%取模(取余),**(乘方),乘法符号有些场景中需要转义

    实现算数运算:
    (1)let var= 算术表达式
    (2)var=$[算术表达式]
    (3)var=$((算术表达式))
    (4)var=$(expr arg1 arg2 arg3 ...)
    (5)declare -i var =数值 
    (6)echo '算术表达式' | bc

bash有内建的随机数生成器变量:$RANDOM(0-32767)
    示例:生成字符颜色随机数
        echo $[$RANDOM%7+31] 
例:
    x=2 
    y=3

    let num=x*y
    echo $num
    6

    echo $[x**y]
    8

expr 专门做数字运算的外部命令
 expr 3 + 5 
 expr 3 \* 5

declare -i i=10
declare -i j=20
declare -i num=i+j
echo $num
30

练习:

编写脚本sumid.sh,计算/etc/passwd文件中的第1个用户和第10个用户的UID之和    
echo $[`head -1 /etc/passwd|cut -d: -f3`+`head /etc/passwd|tail -1|cut -d: -f3`]
简化:
    UID1=`head -1 /etc/passwd|cut -d: -f3`
    UID10=`head /etc/passwd|tail -n1|cut -d: -f3`
    echo $[UID1+UID10]

6.1 赋值

增强型赋值:
        +=,-=,*=,/=,%=
let varOPERvalue
        例如:let count+=3
        自加3后自附值
自增,自减:
        let var +=1
        let var ++
        let var -=1
        let var --

6.2 逻辑运算

true,false 
1真 ,0假
与                   
    1与1=1           12与8=8
    1与0=0           1100
    0与1=0           1000
    0与0=0           1000
与运算逻辑: 任何数和0相与,结果为0。任何数和1相与,保留原值

或
    1或1=1           12或8=12
    1或0=1           1100
    0或1=1           1000
    0或0=0           1100
或运算逻辑: 任何数有1,结果为1,两个数字都为0,结果为0  

非:!
    !1=0  !true 
    !0=1  !false 

6.3短路运算

短路与:CMD1 && CMD2
        如果与前的CMD1执行是假,总结果就是假,没有必要执行与后操作CMD2
        如果CMD1成功了,就可执行CMD2 
        如果CMD1失败了,就不执行CMD2

短路或: CMD1 || CMD2   
       如果CMD1成功(真)了,就不执行CMD2
       如果CMD1失败(假)了,就执行CND2

异或:^
    异或的两个值,相同为假,不同为真 
    0^0 = 假 0  (二进制)
    1^0 = 真 1

    12^8=4     
    1100       0100 4       0100 4   
    1000       1100 12      1000 8 
    0100       1000 8       1100 12

    两个数字异或得到的结果与任意一个结果再异或可以得到另一个数字

例:

x=12  y=8 
echo $[x^y]  ->4 

x=12;y=8;tmp=$x;x=$y;y=$tmp;echo x=$x,y=$y
x=12;y=8;x=$[x^y];y=$[x^y];x=$[x^y];echo x=$x y=$y

true && echo true || echo false     

6.4 条件测试

判断某需要是否满足,需要由测试机制来实现
专用的测试表达式需要由测试辅助完成测试过程
评估布尔声明,以便用在条件性执行中
        若真,则返回0
        若假,则返回1
测试命令:
        test EXPRESSION
        [ EXPRESSION ]
        [[ EXPRESSION ]]
        注意:EXPRESSION前后必须有空白字符

6.5 bash的数值测试

-v VAR
    变量VAR是否设置
数值测试:  [ 整数1 操作符 整数2 ]
    [ 1 -gt 10 ]     大于
    [ 1 -lt 10 ]     小于
    [ 1 -eq 10 ]     等于
    [ 1 -ne 10 ]     不等于
    [ 1 -ge 10 ]     大于等于
    [ 1 -le 10 ]     小于等于

6.6 bash的字符串测试

字符串测试:
        =   是否等于
        >   ascii码是否大于ascii码
        <   是否不等于
        =~  左侧字符串是否能够被右侧的PATTERN所匹配
                注意:此表达式一般用于[[ ]]中;扩展的正则表达式

        -z "STRING"  字符串是否为空,空为真,不空为假
        -n "STRING"  字符串是否不空,不空为真,空为假
    注意:用于字符串比较时的用到的操作数都应该使用双引号

    判断一个变量是否为空很关键
    VAR=100
    echo $VAR
    100

    [ "$VAR" ]
    echo $?
    0
    不空为真,才可执行其他操作
    unset VAR
    [ "$VAR" ]
    echo $?
    1
    空为假,不可执行其他操作
(list) list将在一个子bash中进行,变量赋值和内部命令,影响bash环境但是在命令结束之后不会保留下来(临时性的)
(umask 066;touch file) umask只影响创建的这个文件
( ) 会开启一个子bash
  • 面试题:
TITLE=ceo 
echo $TITLE 
eco
(echo $TITLE)
ceo
(echo $TITLE;TITLE=coo;echo $TITLE)
ceo 
coo 
echo $$TITLE 
ceo 
( )可以临时更改变量 

{} 不开启子进程
NAME=mage;echo $BASHPID; { echo $NAME;NAME=wang;echo $NAME;echo $BASHPID; };echo $NAME
10902
mage
wang
10902
wang
      bash pid不变
() 开启子进程
NAME=mage;echo $BASHPID;(echo $NAME;NAME=wang;echo $NAME;echo $BASHPID; );echo $NAME 
10902
mage
wang
11065
mage
    bash pid为子进程

NAME=mage;(echo $NAME;NAME=wang;echo $NAME);echo $NAME
mage
wang
mage

[[ ]]特点:

        支持正则表达式 和通配符 
        == , !=符号右侧可使用通配符,左侧变量名建议加""
        =~ 符号右侧可使用正则表达式,左侧变量名建议加""

    X=abc;[[ "$X" == ab* ]] && echo true  

    X=ac;[[ "$X" == ab ]] && echo true || echo false 
    左侧加双引号,右侧不加双引号->通配符不加双引号   
FILE=scripts.sh
[[ $FILE = ~ \.sh$ ]] && echo $FILE is script && [ ! -x $FILE ] && chmod +x $FILE 
判断文件是否是.sh文件 如果是是否有执行权限 如果没有,给文件赋予执行权限

$VAR=100
[[ "$VAR" =~ ^[:digit:]+$ ]] && echo $VAR is digit || echo $VAR is not digit 
判断变量VAR是否是数字

例:

x=20  
y=10
[$x -gt $y ] && echo "x > y"
[$x -lt $y ] || echo "x >= y"
[$x -lt $y ] && echo "x < y" || echo "x >= y"

7 Bash的文件测试

7.1存在性测试

    -a FILE:同-e 
    -e FILE:文件存在性测试,存在为真,否则为假
存在性及类别测试:
    -b FILE :是否存在且为块设备文件
    -c FILE:是否存在且为字符设备文件
    -d FILE:是否存在且为目录文件
    -f FILE:是否存在且为普通文件
    -h FILE 或 -L FILE:存在且为符号链接文件
    -p FILE:是否存在且为命名管道文件
    -S FILE:是否存在且为套接字文件

7.2 Bash的文件权限测试

文件权限测试:
    -r FILE:是否存在且可读 
    -w FILE: 是否存在且可写
    -x FILE: 是否存在且可执行
文件特殊权限测试:
    -u FILE:是否存在且拥有suid权限
    -g FILE:是否存在且拥有sgid权限
    -k FILE:是否存在且拥有sticky权限

7.3 Bash的文件属性测试

文件大小测试:
    -s FILE: 是否存在且非空
文件是否打开:
    -t fd: fd 文件描述符是否在某终端已经打开
    -N FILE:文件自从上一次被读取之后是否被修改过
    -O FILE:当前有效用户是否为文件属主
    -G FILE:当前有效用户是否为文件属组

7.4Bash的文件属性测试

双目测试:
    FILE1 -ef FILE2: FILE1是否是FILE2的硬链接
    FILE1 -nt FILE2: FILE1是否新于FILE2(mtime)
    FILE1 -ot FILE2: FILE1是否旧于FILE2

8 Bash的组合测试条件

第一种方式:
    [ EXPRESSION1 -a EXPRESSION2 ] 并且
    [ EXPRESSION1 -o EXPRESSION2 ] 或者
    [ ! EXPRESSION ] 取反
    -a 和 -o 需要使用测试命令进行,[[ ]] 不支持
第二种方式:
    COMMAND1 && COMMAND2 并且,短路与,代表条件性的AND THEN
    COMMAND1 || COMMAND2 或者,短路或,代表条件性的OR ELSE
    ! COMMAND 非
示例:
    [ -f “$FILE” ] && [[ “$FILE”=~ .*\.sh$ ]]

判断文件是否是普通文件并且有没有执行权限,如果没有,添加执行权限
FILE=$script38.sh
[-e $FILE -a ! -x $FILE ] && chmod +x $FILE 

9 条件性的执行操作符

示例:
    grep -q no_such_user /etc/passwd || echo 'No such user'
    No such user
    ping -c1 -W2 station1 &> /dev/null > && echo "station1 is up" > || (echo 'station1 is unreachable'; exit 1)
    station1 is up

    ping -cN ping的次数
         -W 超时时长

10 Bash的组合测试条件

示例:
    test "$A" = "$B" && echo "Strings are equal"
    test “$A”-eq “$B” && echo "Integers are equal“
    [ "$A" = "$B" ] && echo "Strings are equal"
    [ "$A" -eq "$B" ] && echo "Integers are equal“
    [ -f /bin/cat -a -x /bin/cat ] && cat /etc/fstab
    [ -z “$HOSTNAME” -o $HOSTNAME = "localhost.localdomain" ] && hostname www.magedu.com

    [$RANDOM%6 -eq 0] && rm -rf /* || echo "click"
判断合法ip
IP=1.2.3.4
[[ "$ip" =~ ^(([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]25[0-5])\.){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]25[0-5]) ]] &&  echo $ip is legal || echo $ip is illegal  

禁止用户登录:创建一个nologin文件
touch /etc/nologin

使用read命令来接受输入

使用read来把输入值分配给一个或多个shell变量
    常用参数:   
        -p 指定要显示的提示
        -s 静默输入,一般用于密码
        -n N 指定输入的字符长度N
        -d ‘字符’ 输入结束符
        -t N TIMEOUT为N秒
        read 从标准输入中读取值,给每个单词分配一个变量
        所有剩余单词都被分配给最后一个变量
        read -p “Enter a filename: “ FILE
read 可以给变量赋值 

read x y z <<< "aaa bbb ccc"
echo $x
aaa
echo $y
bbb
echo $z 
ccc

"|" 管道符的左边和右边都将开启一个独立的子进程
可以 sleep 1000 | sleep 1000 使用pstree -p 查看进程数 对比

echo mage 30 | read NAME AGE
echo $NAME
echo $AGE
不在同一个bash中,所以无法查看变量

echo mage 30 | { read NAME AGE; echo $NAME $AGE; }
mage 30 
使用"{}"使read 输入 和echo 输出在同一bash中,即可输出 
请输入你的年龄:
#!/bin/bash
read  -p "Please input your age : "

请输入你的密码:
read -sp "Please input your password: " PASS

echo $PASS
123456
鸡兔同笼:孙子算经
头=35
脚=94
鸡?
兔?

#!/bin/bash

read -p "Please input heads: " HEAD
read -p "Please input feet: "  FOOT
R=$[FOOT/2-HEAD]
C=$[HEAD-R]
echo "Chook: " $C
echo "Rabbit: " $R

条件选择if语句

选择执行: 
注意:if语句可嵌套 
单分支  
    if 判断条件;then   
        条件为真的分支代码  
    fi
条件成立就执行指令,不成立,条件为真的分支就不执行

双分支  
    if 判断条件; then   
        条件为真的分支代码  
    else   
        条件为假的分支代码  
    fi 
 条件判断如果成立,就执行第一个条件,如果不成立,就执行第二个判断

if语句

多分支 
    if 判断条件1; then  
        条件1为真的分支代码 
    elif 判断条件2; then  
        条件2为真的分支代码 
    elif 判断条件3; then  
        条件3为真的分支代码 
    else  
        以上条件都为假的分支代码 
    fi 

逐条件进行判断,第一次遇为“真”条件时,执行其分支,而后结束整个if语句 

if示例

判断IP是否合法:
read -p "Please input a ip address: " IP
if [[ "$IP" =~ ^(([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]25[0-5]\.){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]25[0-5])$ ]];then
    echo"$IP is legal"
else
    echo "$IP is illegal"
fi
判断Yes或No
read -p "Do you agree?(yes or no): " ANSWER
ANS=`echo $ANSWER |tr 'A-Z' 'a-z'`
if [ $ANS = "yes" -o $ANS= "y" ]; then
    echo YES
eilf [ $ANS = "no" -o $ANS = "N" ];then
    echo NO
else
    echo "INPUT FALFE!"
fi
根据命令的退出状态来执行命令  
if ping -c1 -W2 station1 &> /dev/null; then        
    echo 'Station1 is UP'  
elif  grep "station1" ~/maintenance.txt &> /dev/null;  then        
    echo 'Station1 is undergoing maintenance'  
else      
    echo 'Station1 is unexpectedly DOWN!'         
    exit 1   
fi 

条件判断:case语句

case 变量引用 in
PAT1)
    分支1
    ;;
PAT2)
    分支2
    ;;
...
*)
    默认分支
    ;;
esac 

case支持glob风格的通配符:
    *:任意长度字符
    ?:任意单个字符
    []:指定范围内的任意单个字符
    a|b:a或b

例:


 case是关键字 
 type case 

    case $NUM in 
    1|3|5)
        cmd1
        ;;
    2|4|6)
        cmd2
        ;;
    ...
    *)
        cmdN
        ;;
    esac 
判断yes or no 
read -p " Do you agree?(yes or no): " ANSWER
case $ANSWER in
[Yy][Ee][Ss]|[Yy])
    echo "YES"
[Nn][Oo]|[Nn])
    echo "NO"
*)
    echo NOT YES or NO
esac
判断执行哪个脚本
cat <
编写脚本createuesr.sh,实现如下功能:使用一个用户名作为参数,如果指定参数的用户存在,就显示其存在,否则添加之;显示添加的用户的id号等信息
#!/bin/bash
if [ -z "$1" ];then
    read -p "Please input a username: " USER
    if [ -z "$USER" ];then
        echo "INPUT FALSE"
        exit 10
    fi
else
    USER=$1
fi

if id $USER &> /dev/null ;then
    echo "$USER is exist"
    exit 20
else
    useradd $USER && echo "$USER is created"
    echo magedu |passwd --stdin $USER &> /dev/null && echo "$USER passwd magedu"
    passwd -e $USER
    echo userinfo `id $user`
fi

bash如何展开命令行

把命令行分成单个命令词 
展开别名 
展开大括号的声明({}) 
展开波浪符声明(~) 
命令替换$() 和 ``) 
再次把命令行分成命令词 
展开文件通配(*、?、[abc]等等) 
准备I/0重导向(<、>) 
运行命令 

防止扩展

反斜线(\)会使随后的字符按原意解释 
    echo Your cost: \$5.00   
    Your cost: $5.00 
加引号来防止扩展 
    • 单引号(’’)防止所有扩展 
    • 双引号(”“)也可防止扩展,但是以下情况例外: 
        $(美元符号) 变量扩展 
        ` ` (反引号)    命令替换 
        \(反斜线)      禁止单个字符扩展 
        !(叹号)        历史命令替换 

bash的配置文件

按生效范围划分,存在两类: 
    全局配置:  
        /etc/profile  
        /etc/profile.d/*.sh  
        /etc/bashrc
    个人配置:  
        ~/.bash_profile  
        ~/.bashrc 
使配置文件生效 . /etc/profile.d/env.sh
. 等价于 source  (引用系统配置时使用)
把后面跟的配置文件读入到当前bash中,在当前bash进行执行
bash执行,将运行子bash中  (执行脚本时使用)

shell登录两种方式

交互式登录:   
    (1)直接通过终端输入账号密码登录   
    (2)使用“su - UserName” 切换的用户  
执行顺序:/etc/profile --> /etc/profile.d/*.sh --> ~/.bash_profile --> ~/.bashrc --> /etc/bashrc 

非交互式登录:   
    (1)su UserName   
    (2)图形界面下打开的终端   
    (3)执行脚本   
    (4)任何其它的bash实例   
执行顺序: /etc/profile.d/*.sh --> /etc/bashrc -->~/.bashrc  

Profile类

按功能划分,存在两类:  
    profile类和bashrc类 
profile类:为交互式登录的shell提供配置  
    全局:/etc/profile, /etc/profile.d/*.sh  个人:~/.bash_profile  
    功用:  
        (1) 用于定义环境变量  
        (2) 运行命令或脚本 

Bashrc类

bashrc类:为非交互式和交互式登录的shell提供配置                      
       全局:/etc/bashrc  
    个人:~/.bashrc  
    功用:  
        (1) 定义命令别名和函数  
        (2) 定义本地变量 

编辑配置文件生效

修改profile和bashrc文件后需生效 
    两种方法:  
        1重新启动shell进程  
        2 . 或source  
        例:  
            . ~/.bashrc 

Bash 退出任务

保存在~/.bash_logout文件中(用户) 
在退出登录shell时运行 
用于 
    • 创建自动备份 
    • 清除临时文件 

set 命令

$-变量
    h:hashall,打开这个选项后,shell会将命令所在的路径hash下来,避免每次都要查询。通过set+h将h现象关闭

    i:interactive-comments,包含这个选项说明当前的shell是一个交互式的shell。所谓的交互式shell,在脚本中,I选项是关闭的

    m:monitor,打开监控模式,就可以通过Job control来控制进程的停止、继续。后台后者前台执行等

    B:braceexpand,大括号扩展

    H:history,H选项打开,可以展开历史列表中的命令,可以通过!感叹号来完成,例如"!!"返回上最近一个命令,"!h"返回第n个历史命令

脚本安全

set命令 
    -u 在扩展一个没有设置的变量时,显示错误信息
        等同set -o nounset 
    -e 如果一个命令返回一个非0退出状态值(失败)就退出
        等同set -o errexit 

    例:set -u 
        DIr=/data
        rm -rf $DIR/*.txt