开机流程:
1、读BIOS,加载 CMOS 的信息,进行硬件的检测,硬件驱动等等,通过 MBR(MBR.png,有每个系统的启动扇区)加载系统内核(/boot 文件)。
2、内核执行init 程序,而 init 会取得 run-level 信息。
3、init 执行/etc/rc.d/rc.sysinit  准备软件执行环境,如网络,时区等。
4、init 执行run-level 的各个服务启动
5、init 执行 /etc/rc.d/rc.local 档案  (凡是需要随系统自动启动的服务、就可以都塞到/etc/rc.d/rc.local)
6、init 执行终端机的 login 程序,最后就等待用户登入

附:run-level 信息

0 - halt (系统直接关机) 
1 - single user mode (单人维护模式,用在系统出问题时的维护)
2 - Multi-user, without NFS (类似底下的 runlevel 3,但无 NFS 服务)
3 - Full multi-user mode (完整的有网络功能的纯文本模式)
4 - unused (系统保留功能)
5 - X11 (与 runlevel 3 类似,但加载使用 X Window)
6 - reboot (重新启动)
不要把设置为 0,4,6 不然就是关机,重启。
保存在 /etc/inittab  文件中,格式:
id:3:initdefault:


login shell 和 no login shell

1、login shell 要登录
2、no-login shell 没有用户登录(使用x-window 时常见)
3、在登录下再运行bash 时,就进入到一个子进程,这时也是no login shell,执行exit 退出到父进程。
示例:在~/.bashrc  添加 export test='test', 运行bash 后,可以看到设置了这个环境变量。
这两种取得bash,读取的配置文件不一致:
login shell:
1、/etc/profile
2、~/.bash_profile 或者 ~/.bash_login 或者 ~/.profile   只会读聚上面三个其中的一个,而读取的顺序则是依照上面的顺序。个人的相关配置就可以写在这时。
no login shell:
仅会读取: ~/.bashrc


指令搜索顺序
1、以相对或者绝对路径执行。如 ./shell.sh   /home/jamin/bin/xxx.sh
2、别名; 如:ll  命令
3、bash 内建的指令
4、PATH
附:type 命令可以查看命令是什么命令。
[jamin@localhost ~]$ type ll
ll is aliased to `ls -l --color=auto'
file:表示外部命令,alias:为命令别名所设置的名称,builtin:为bash内置命令


内建命令,外部命令

当执行外部命令时,会创建出一个子进程。内建命令不需要用子进程来执行(已经和shell 编译在一起了,不需要外部程序文件来运行)。
注:
1、type 可以查看命令是内建命令,还是外部命令。
2、命令有多种实现方式。请用type -a 查看。如:
[jamin@localhost ~]$ type -a echo
echo is a shell builtin
echo is /bin/echo
如果要使用外部命令,直接用全路径即可
2、which 只显示外部命令


执行shell 方式
1、source  
2、./test.sh  /home/jamin/test.sh
3、sh xx.sh

第 2,3 两种方法是一致的,执行时会在当前进程下创建一个子进程执行,执行完成后不退出父进程,对父进程的环境不会有影响。
第1 种方法是在当前进程中进行的。对父进程环境有影响。
示例:test.sh
#!/bin/bash
test='test'
echo test
export test
使用第一种方式执行后,在当前进程下多了一个环境变量 test ,使用第2,3 种方式执行时,就没有,因为环境变量(一般变量)只会从父进程传到子进程,不会从子进程传到父进程。

注:启动时用户默认的shell 是放在在/etc/passwd  文件中的


变量定义
示例:$test="test" 
1、变量名和值用等号连接,等号两边不能有空格
2、值有空格,要用''  或者 ""  
'' 内的特殊字符为一般文本,如:echo '$PATH' 打印:$PATH
"" 内的特殊字符为原有的属性。如: echo "$PATH" 打印 PATH 属性的值
3、可以使用转义字符(\) ,可以把 空格、Enter、$、\ 变成一般字符。test="a b" 可以写成test=a\ b
4、`` 或者 $()  由内部指令提供信息。
$test=`cat /etc/passwd`
5、使用变量成为环境变量:
$export test
6、取消变量
$unset test

declare 定义变量
示例:declare -i sum
        -a :将后面名variable 定义为数组(array)类型
        -i   : 定义为整数数字(integer)类型
        -x   :用法与export一样,将后面的变量编程环境变量。+x 取消环境变量
        -r    :将变量设置成 readonly类型,也不能unset


shell 编写

test,[ ] , [[ ]],(())判断

文件
示例:test -e  file_name
-e 文件是否存在
-f 文件存在且为文件
-d 文件存在且为目录
数值
test n1 -eq n2
-eq   equal
-ne   not equal
-gt   great than
-lt   less than
-ge   great than or equal
-le   less than or equal
字符串
test -z str    字符串是否为0,如果是空串(未定义,或者是"")返回true
test -n str    字符串是否为非0
test str1 = str2   相等
test str1 != str2  不相等
多重判断
-a   and   示例: test  -z str1 -a str1 = str2
-o   or
!    非

双方括号;处理正则匹配的

示例:值以a 开始

$ [[ "abc" == a* ]] && echo 'y'
y

双括号 (()) 参考:

if...then
示例:经常在执行脚本的时候会有让输入 y/n,输入y 继续执行,输入n 终止。
#!/bin/bash
read -p "plase input y/n :" yn
if [ "$yn" == "Y" -o "$yn" == "y" ];then
    echo "continue"
elif [ "$yn" == "N" -o "$yn" == "n" ];then
    echo "termination"
else
    echo "param is error"
fi
注意:
1、[ ] 符号和里面内容之间要有空格
2、"$yn" 变量要使用双引号,处理变量有空格的问题
3、then 可以换行,换行后 ; 可以不用写
4、#!/bin/bash 指定使用那一个shell,类似执行:/bin/bash ./sh01.sh(有默认的shell)

case....esac

示例:在执行脚本时可以遇到参数是start,stop,restart 的服务启动脚本。
 [jamin@localhost ~]$ cat case.sh 
 #!/bin/bash
 c=$1
 case $c in
 "start")
     echo "start serve"
     ;;
 "stop")
     echo "stop serve"
     ;;
 "restart")
     echo "restart serve"
     ;;
 *)
     echo "Usage $0 {start|stop|restart}"
     ;;
 esac


function

示例:把上面的case 转化成function 调用
 #!/bin/bash
 c=$1

 function start(){
     #这个 $1 和上面那个$1 不是一个东西,这个$1 是调用这个function 传递的参数
     echo $1   
 }
 function stop(){
     echo "stop serve"
 }
 function restart(){
     echo "restart serve"
 }
 case $c in
 "start")
     start "start serve"
     ;;
 "stop")
     stop
     ;;
 "restart")
     restart
     ;;
 *)
     echo "Usage $0 {start|stop|restart}"
     ;;
 esac

函数总结:

1、必须在调用函数地方之前,声明函数,shell脚本是逐行运行。
2、可以带function function_name(){} 定义,也可以直接function_name(){} 定义,不带任何参数。
3、参数返回(函数执行返回的状态码),可以显示加:return 返回,如果不加,将以最后一条命令运行结果,作为返回值(每一个命令执行完成后都有一个返回值0 表示成功)。 return后跟数值n(0-255,如果超出255,会减去256 的位数,返回值一定小于256)
4、函数返回值,只能通过$? 系统变量获得。查看下面示例

#!/bin/bash
 sum(){
     return $(($1+$2))
 }
 total=$(sum 1 2)
 echo $?
 echo $total


total 是没有值的,? 是3

5、定义函数可以与系统命令相同,说明shell搜索命令时候,首先会在当前的shell文件定义好的地方查找,找到直接执行。
6、如果需要传出其它类型函数值,可以在函数调用之前,定义变量(这个就是全局变量)。在函数内部就可以直接修改,然后在执行函数就可以读出修改过的值。
7、函数定义的变量默认是global的,如果需要定义自己变量,可以在函数中定义:local 变量=值 ,这时变量就是内部变量,它的修改,不会影响函数外部相同变量的值 。
示例:

while循环:
while [条件]
do
    ###
done
条件成立时执行,不成立时跳出循环。
示例:计算1...10 的数值的和
#!/bin/bash
declare -i n=1
declare -i sum=0
while [ $n -le 10 ]
do
    sum=$(($sum+$n))
    n=$n+1
done
echo 'sum:' $sum

#!/bin/bash
 declare l="a"
 declare -i n=100
 fun(){
     local l="bbbb"
     g='ggggg'
     n=n+1
 }
 fun
 echo $l
 echo $n
 echo $g
 结果:
 a
 102
 ggggg


until循环:当条件不成立时执行,刚好和while 相反

until [ 条件 ]
do
    ###
done
示例:计算1...10 的数值的和

#!/bin/bash
 declare -i n=1
 declare -i sum=0
 until [ $n -gt 10 ]
 do
     sum=$(($sum+$n))
     n=$n+1
 done
 echo 'sum:' $sum


注意:while 是 -le(<=) until 是 -gt (>)


for  固定循环

for var in c1 c2 c3
 do
     ###
 done
 示例:计算1...10 的和
 #!/bin/bash
 declare -i n=1
 declare -i sum=0
 for n in `seq 1 10`
 do
    sum=$(($sum+$n))
 done
 echo "sum:" $sum


注:

1、file_list=`ls /home/jamin`  也可以用到for 循环中。
2、while until for 中使用  break continue 控制循环。
示例:如上面的for 循环中如果数字是5,就不加入到和中:
if [ $n -eq 5 ];then
echo '5 is skiped'
continue
fi

break n   n默认为1,为当前循环。
跳出外部循环
示例

for n in list
 do
     for i in list1
do
  if ...;then
     break 2       # 跳出外部循环
  fi
done
 done



continue 和break 类似,通过指定n 确定继续执行哪一级的循环

3、可以把循环的输出重定向到文件。

示例(for,其它循环也适用):把for 循环内的输出内容重定向到文件

n=1
 sum=0
 for n in `seq 1 10`
 do
    echo "num is $n"
    if [ $n -eq 5 ];then
         echo '5 is skip'
         continue 
    fi
    sum=$(($sum+$n))
 done > ./loop.log
 echo "sum:" $sum

for 遍历变量

特殊字符处理:要用引号、双引号、转义字符\ 进行转义

for var in "this's" test
 do
     echo $var
 down

 for var in this\'s test
 ....
 ....



注意:for 不会把一个值两边的 " 当成值的一部分

设置分割符
是按照环境变量IFS的值分割的,IFS默认值为:空格|制表符|换行符
可以设置IFS 变量,修改默认分割符。


示例遍历文件
 last 命令输出内容如下(只取了一行):
 jamin    pts/0        192.168.28.1     Mon May 15 12:25   still logged in   
 ...
 ...如果用for 来遍历last 的标准输出文件
 #!/bin/bash
 list=`last`
 for n in $list
 do
     echo $n
 done


 输出为每一行按照按照空格分割后的每一个值。如下:
 jamin
 pts/0
 192.168.28.1
 Mon
 May
 15
 12:25
 still
 logged
 in   
 ....

 如果要按照行输出,就要修改IFS 的值:
 示例:一行一行遍历last 的标准输出:#!/bin/bash
 list=`last`
 IFS=$'\n'
 for n in $list
 do
     echo $n
 done

 注意:在使用过程中,可能在一个地方设置了IFS 变量,在别的地方要忽略这个设置。一般用法如下:
 IFS.OLD=$IFS
 IFS=$'\n':;"  #比如说,设置了 换行 :   ;   "  4个为分割符
 #使用新的IFS,使用完后,要设置成原来的IFS变量
 IFS=$IFS.OLD

shell 的跟踪和debug
$sh [-nvx] xx.sh
-n :不要执行 script,仅显示语法的问题;
-v :再执行 sccript 前,先将 scripts 的所有内容输出到屏幕上;
-x :将使用到的 script 内容显示到屏幕上!


包管理方式:rpm srpm  yum。这里只介绍rpm

系统代表   软件管理    使用命令        在线升级
red hat    rpm         rpm ,rpmbuild   yum
ubuntu     dpkg        dpkg            apt(apt-get) 


rpm: 即red hat package manager
把要装的软件先编译,并且打包成RPM 机制的包装档案,通过这个包装档案里面的数据库记录,记录这个包装档案安装时必要的软件属性。当安装这个档案时,RPM 会先按照档案的数据库记录查询Linux 主机是否具备相应的依赖软件。安装后,把此档案的信息写入Linux RPM 的数据库中,以便将来的查询、验证、更新等等。(如 maven)
问题:
1、rpm 安装的环境必须要和编译打包的环境一致或者相当。(主要是cpu 和 依赖的软件)
2、软件环境需要满足rpm 安装的依赖
3、反安装时,最底层的软件不可移除


SRPM:
由于上面的问题,就要使用rpm 包的源码,即SRPM ,即 source rpm,RPM 包的源码,通常是xx.src.rpm 命名。
源码包中也包含了该软件所依赖的软件信息及所有rpm包的数据,同时也提供了参数配置文件(configure 和 makefile)。
可以通过修改参数配置文件,编译生成适合我们机器环境的rpm包。
安装SRPM 步骤:
1、先将该软件以rpm 管理的方式编译,生成rpm 档案
2、然后使用编译生成的rpm 包进行安装
注:rpm 包命名:mysql-community-client-5.7.18-1.el6.x86_64.rpm   包括 软件名,版本,打包信息,适用cpu


rpm 优点:
1、RPM 内含已经编译过的程序与配置文件等数据,可以让用户克除重新编译的困扰;
2、RPM 在被安装之前,会先检查系统的硬盘容量、操作系统版本等,可避克档案被错误的安装;
3、RPM 档案本身提供软件版本信息、相依属性软件名称、软件用途说明、软件所含档案等信息,便于了解软件;
4、RPM 管理的方式使用数据库记录 RPM 档案的相关参数,便于升级、移除、查询与验证。


为了解决RPM 软件依赖的关系,在打包时就把软件信息一起打包如软件的版本、依赖的软件、档案记录等。在Linux 上也建立一个rpm 数据库记录机器上安装的rpm 软件信息。如此在安装rpm 时,rpm 会去检查是否已经安装了相关依赖的软件。yum就是克服rpm 软件相互依赖的工具。

yum
centos 将打包的rpm 放到yum 服务器,然后分析rpm 依赖性问题并且将软件信息记录下来(就是软件的head信息),并生成rpm 的依赖列表。
当使用yum 安装时,yum 先把到服务器上下载依赖清单列表,并和本地已经安装的相比较,如果没有安装则yum 直接安装别的依赖。
当客户端有安装、更新的需求时, yum 会向服务器要求清单的更新,等到清单更新到本机的 /var/cache/yum 里面后, 等一下更新时
就会用这个清单与本机的 RPM 数据库进行比较,这样就知道该下载什么软件。接下来 yum 会跑到容器朋务器 (yum server) 下载所需要的软件,然后再透过 RPM 的机制开始安装。

rpm 命令:
rpm -ivh xxx.rpm 
-i :install 的意思
-v :察看安装信息
-h :显示安装进度
安装软件的相关信息被写入 /var/lib/rpm/ 目录下的数据库文件中了。

安装多个
$rpm -i a.rpm b.rpm
安装网上的rpm
$rpm -i http://xxxxxx.rpm

升级
rpm -[UF]vh xxx.rpm 
U:软件即使没有安装过,则系统将予以直接安装; 若后面接的软件有安装过旧版,则系统自动更新至新版。
F:软件没有被安装则不会被安装,只有已经被安装的软件才会升级。

查询
rpm 在查询的时候其实是在查询/var/lib/rpm/ 这个目录下的数据库档案。也可以查询没有安装的rpm 档案信息。

查询已经安装的软件
$rpm -qa openssl  列出openssl 软件信息
$rpm -qa 列出安装的所有软件
-qi  列出软件信息
-ql  列出软件所有的文件的完整文件名
-qf  file_name  查询这个文件属于那个软件
-qR  列出软件的依赖软件(Required)
-qp[ilR] 查询未安装软件的信息(p 是package )
注:还有别的选项没有列举完

rpm 卸载软件
$rpm -e openssl
注: 可能由于依赖关系不能卸载软件,卸载软件的过程一定要是从上层往下层卸载。如:a -依赖-> b -依赖-> c 如果要卸载a 时,就要卸载c时,就要先卸载a,再卸载b,最后卸载c

重建数据库
$rpm --rebuilddb 

rpm 验证与数字签名,查看软件有没有被修改过。(可以查询相关信息)


yum
示例:

$ yum list openssl
 Loaded plugins: fastestmirror
 Loading mirror speeds from cached hostfile
  * base: mirrors.aliyun.com
  * extras: mirrors.aliyun.com
  * updates: mirrors.aliyun.com
 Installed Packages
 openssl.x86_64                                               1.0.1e-48.el6                                                @anaconda-CentOS-201605220104.x86_64/6.8
 Available Packages
 openssl.i686                                                 1.0.1e-57.el6                                                base                                    
 openssl.x86_64                                               1.0.1e-57.el6                                                base

上面 Installed Packages 说明是已经安装的版本


yum
查询
yum list  列出目前 yum 所管理的所有的软件名称和版本
yum info  和上面类似,不过有软件的信息
yum provides  file_name   文件属于那一个软件

安装:
$yum install xxx -y 
$yum update  xxx  要整个系统都升级,就直接 update 即可

移除:
$yum  remove xxx   同rpm,先解决属性相依的问题