学了还不会的学弱,想学懂的学霸,一小时全掌握Linux下shell编程工作、面试全没问题。
我们在有限的、有效的时间内,每天通过一个小时的学习,完全掌握Linux的shell编程
1 shell简介
在计算机科学中,Shell就是一个命令解释器。
shell是位于操作系统和应用程序之间,是他们二者最主要的接口,shell负责把应用程序的输入命令信息解释给操作系统,将操作系统指令处理后的结果解释给应用程序
一句话,shell就是在操作系统和应用程序之间的一个命令翻译工具。
1.1 shell的分类
基本上shell分两大类:图形界面shell和命令行shell
图形界面shell:图形界面shell就是我们常说的桌面
命令行式shell
windows系统: cmd.exe 命令提示字符
linux系统: sh / csh / ksh / bash / ...
我们常说的shell是命令行式的shell,在工作中常用的是linux系统下的bash。
https://baike.baidu.com/item/shell/99702
1.2 查看系统shell信息
查看当前系统的shell类型
echo $SHELL
查看当前系统环境支持的shell
[root@linux-node1 ~]# cat /etc/shells
/usr/bin/sh
/usr/bin/bash
/usr/sbin/nologi
1.3 shell 脚本
shell使用方式
手工方式:手工敲击键盘,在shell的命令行输入命令,按Enter后,执行通过键盘输入的命令,然后shell返回并显示命令执行的结果, 逐行输入命令、逐行进行确认执行
脚本方式: 就是说我们把手工执行的命令a,写到一个脚本文件b中,然后通过执行脚本b,达到执行命令a的效果.
shell脚本定义: 当可执行的Linux命令或语句不在命令行状态下执行,而是通过一个文件执行时,我们将这个文件为shell脚本。
1.4 shell脚本示例现在我们来使用脚本的方式来执行以下
创建临时shell脚本文件 itcast.sh, 注意以 .sh结尾、
1.5 shell与python在运维工作中的简单比较
习惯shell历史悠久,使用时间长,Python时间短执行方式shell命令------系统命令特点:命令简介,功能强大python命令-----模块------系统命令特点:可以编写复杂逻辑
shell脚本
shell脚本的本质是shell命令的有序集合
建立shell脚本的步骤:建立shell脚本,编写任意多行操作系统命令或shell命令,增加文件的执行权限,结束
shell变量
shell允许用户建立变量存储数据,但不支持数据类型。将任何赋给变量的值都解释为一串字符
shell有如下四种变量:用户自定义变量,位置变量,预定义变量,环境变量
用户自定义变量:
定义变量:COUNT=1
使用时前面加$:echo $COUNT
删除变量的赋值:unset COUNT
位置变量:
$0 与键入的命令行一样,包含脚本文件名
$1,$2...$9 分别包含第一个到第九个命令行参数
$# 包含命令行参数的个数
$@ 包含所有命令行参数:“$1,$2...$9 ”
$? 包含前一个命令的退出状态
$* 包含所有命令行参数:“$1,$2...$9 ”
$$ 包含正在执行进程的ID号
shell环境变量
CDPATH 用于cd命令的查找路径
HOME 用户主目录
PATH 路径
shell 程序和语句
shell程序由0到n条shell语句构成,shell语句包括三大类:功能性语句、结构性语句、说明性语句
说明性语句:以#开始的部分,不被解释执行
可以出现在程序的任意位置,可以单独一行,也可以接在执行语句的后面
功能性语句:任意操作系统命令、shell内部命令、自编程序、等
read 从标准输入读出一行,赋给后面的变量
read var #把读入的数据全部赋给var
read var1 var2 var3 #把读入一行的第一、二个词分别赋给var1、var2,其他的都赋给var3
如果执行read语句时标准输入无数据,则程序在此停留等候,直到数据到来或终止运行
expr 主要用于简单的整数运算,包括 + - * / % 等
反撇号用于引用命令的运行结果
test 用于测试三种对象:字符串、整数、文件属性
可用[ ]代替,注意左右都至少一个空格
如:test “$answer” = “yes” #变量answer的值是否为字符串yes
test $num -eq 18 #变量num的值是否为整数18
test -d tmp #测试tmp是否为一个目录名
结构性语句:条件测试语句、多路分支语句、循环语句、循环控制语句、后台执行语句
条件测试语句
if...then...else...fi
语法结构:
if 表达式
then
命令表1 #一条或者若干条命令
else
命令表2 #一条或者若干条命令
fi
如果表达式为真,执行命令表1,否则执行命令表2
例子;
if [ -f S1 ] #测试参数是否为文件
then
echo “File $1 exists”
fi
if [-d $HOME/$1] #测试参数是否为目录
then
echo “File $1 is a directory”
fi
多路分支语句
case...esac
语法结构:
case 字符串变量 in #case语句只能检测字符串变量
模式1)
命令表1
;;
模式2)
命令表2
;;
。。。。
*) # *表示其他所有
命令表n
;;
esac
例如:
case $1 in
file1)
echo “file1”
;;
file2)
echo “file2”
;;
*)
echo “others”
;;
esac
循环语句
for...do...done
当循环次数已知或者确定时,使用for循环语句来多次执行一条或一组命令,循环体由do和done来限定
for 变量名 in 单词表
do
命令表
done
说明:变量依次取单词表中的各个单词,每取依次单词,就执行一次循环体,循环次数为单词表中的单词个数,命令表中可以是一条或由分号隔开的多条命令
如果单词表是命令行上的所有位置参数时,可以省去 in 单词表
list=`ls`
for file in $list
do
if[ $1 = $file ]
then
echo “$file found”;
exit; #退出shell脚本
fi
done
while...do...done
语法结构:
while 命令或表达式
do
命令表
done
说明:while首先测试其后的命令或表达式的值,如果为真,就执行一次循环体中的命令,然后再测试该命令或表达式的值,执行循环体,知道为假,退出循环
until...do...done
语法结构:
until 命令或表达式
do
命令表
done
与上面的相反
循环控制语句:
break 和 continue
break n 跳出n层
continue 马上跳转到最近一层循环的下一轮循环
continue n 转到最近n层循环语句的下一轮循环上
shell函数
shell程序中,常把完成固定功能且多次使用的一组命令封装在一个函数中,每当要使用时,调用函数名即可
函数调用前必须先定义,即顺序上先定义函数,再调用
调用程序可以传递参数给函数,函数可以用return语句把运行结果返回调用程序
函数只在当前shell中起作用,不能输出到子shell中
shell函数定义格式
function funtion_name () #function可以省掉
{
...
}
函数调用方式
value_name = `function_name [arg1 arg2 ...]` #函数结果返回给变量
或
function_name [arg1 arg2 ...]
echo $? #获取函数返回的状态
函数变量的作用域
全局作用域:在脚本的其他地方都可以访问该变量
局部作用域:只能在声明的作用域内访问
局部变量的声明: Local variable_name = value
脚本调试:
跟踪脚本执行结果:
在希望开始调试的地方插入 set -x
在希望结束调试的地方插入 set +x
Bash shell结构
1:shbang行:脚本的第一行,告之内核用哪个shell解释shell脚本,由#!加shell的完整路径组成
2:注释:#后面的为注释,可以在一行后
3:shell通配符或元字符:shell中字符意义比较特殊,如* ? [] > < 2> >> |等,防止这些字符被解释,则必须引用他们
4:局部变量:局部变量作用域在本shell中
5:全局变量:又称为环境变量,由内置的export命令创建,作用域在本shell及子shell中
6:提取变量值:$
7:参数:可以从命令行传递参数给脚本
8:命令替换:`A` $(A) 结果可以赋给一个变量或代替所在位置
---------------------------------------------------------------------
正则表达式
正则表达式是一种字符模式,在查找过程中匹配指定的字符,可以用特殊的元字符来控制它们,正则表达式都被置于两个正斜杠//之间
元字符:表达的是不同于字符本身的含义
本书中的元字符有两类:shell元字符、正则表达式元字符,它们各司其职,shell元字符是由shell解析的,就是下面所讲的文件名置换;正则表达式元字符是由各种执行模式操作的程序来解析的,如vi、grep、sed、awk
---------------------------------------------------------------------
正则表达式元字符:
^ 行首定位
$ 行尾定位
. 匹配单个字符
* 匹配0或多个重复的位于*前的字符
[] 匹配指定组字符中的任意一个 ;如[LlT]
[-] 匹配指定范围内的字符 ;如[x-yA-Z0-8]
[^] 匹配不在指定组内的字符
[^ - ]跟上面的相反
转移跟在后面的字符 #转义元字符,使之不被解释
< 词首定位符 #定位以什么开头的词
> 词尾定位符 #定位以什么结尾的词
---------------------------------------------------------------------
grep 家族
grep家族由grep、egrep、fgrep组成
grep命令在文件中全局查找指定的正则表达式,并打印所有包含该表达式的行
一般格式:grep [选项] 基本正则表达式 [文件]
选项:-n 显示行号 -i 大小写不敏感 -w表达式作为词来查找,也就是不是一个词的一部分 -r 递归查找
基本正则表达式:可为字符串,如果为字符串,最好用“”如果是模式匹配,用‘’调用变量时,也应该使用“”
文件:可以为多个文件;如 A1 A2
常用举例子
grep -n “your” www #文件www中查找含有your单词的行,且输出行号
grep -nw “your” www #文件www中查找含以your做单词的行,且输出行号
grep -nr ‘[a-zA-Z0-9].you’ ./ #递归./ 中查找含有以a-z A-Z 0-9开始的单词的行,且输出行号
---------------------------------------------------------------------
find命令及xargs
find pathname -options [-print -exec -ok]
常用的options为name 此时记住要用引号将文件名模式引起来
find ./ “*org.txt” #在当前目录及子目录中寻找以org.txt结尾的文件
find 找到文件后可用xargs对其操作
find ./ “*org.txt” | xargs ls
find ./ “*org.txt” | xargs grep “device” #在结果中搜索device
---------------------------------------------------------------------
启动
系统启动后
->init->getty进程
->/bin/login 初始化环境,启动shell
->/bin/bash 执行/ect/profile,执行~/.bash_profile ~/.bash_login ~/.profile,执行~/.bashrc
->等待用户输入
---------------------------------------------------------------------
环境
一个进程的环境包括:变量等,它定义了可以从一个进程继承到下一个进程的特性
用户的shell配置定义在shell初始化文件中,bash shell有许多启动文件,这些文件可以执行source命令,对一个文件执行source命令会使得这个文件中的所有设置称为当前shell的一部分,也就是说不会创建子shell
登陆时,会执行~/.bash_profile文件执行source命令,如无,则source ~/.bash_login,若无,则source ~/.profile,这三个文件只能source一个,再source ~/.bashrc
~/.bashrc:包含特定的变量和别名,当一个新的bash shell启动或bash脚本启动时会自动执行source ~/.bashrc
在当前提示符下输入shell或bash启动的是子shell
/etc/bashrc:系统级的函数和别名可以在/etc/bashrc文件中设置,主提示符一般在这设置
~/.profile:是一个用户定义的初始化文件,它是被Bourne shell使用的,因此不能包括对bash shell的特定设置,运行bash时只有没找到其他文件时才source此文件,它允许用户定制和修改shell环境,也可以放应用程序的初始化
---------------------------------------------------------------------
source命令或dot命令(.) 和 ./命令
source命令式内置的bash命令,来自C shell
dot命令也就是. 来自Bourne shell
二者完全一样,都是一个脚本名作为参数,shell将在当前的shell环境中执行这个脚本,也就是不启动子shell,脚本中的设置的所有参数将成为当前shell环境的一部分。
./执行脚本时是创建子shell,脚本中的设置参数在脚本退出后就无效了。
例子:在家目录下的.bashrc中加入WANG=”ni hao”
然后. .bash.rc
此时执行内容为 echo “$WANG”的 脚本
如用 ./sh.sh 则无输出 #./执行时是在起一个子shell
如用source sh.sh或 . sh.sh则输出ni hao #source是在本shell中执行
---------------------------------------------------------------------
bash shell元字符(通配符)
按字面含义解释后面的那个字符
& 在后台处理的进程
; 分隔命令
$ 替换命令
* 匹配任意字符
? 匹配任意单个字符
[...] 匹配[]中的任意一个字符
[!...] 不匹配[]中!的任意一个字符
(cmds) 在子shell中执行命令
{cmds} 在当前shell中执行命令
---------------------------------------------------------------------
文件名置换
计算命令行时,shell会用元字符来缩写能够匹配某个特定字符组的文件名或路径名
将元字符展开为文件名或路径名的过程称为文件名替换或globbing
* 匹配文件(夹)名中的任意字符串
如:ls app*
cd cmdd*
? 匹配文件(夹)名中的任意一个字符
[...] 匹配[]中的任意一个字符
[!...] 不匹配[]中!的任意一个字符
如:ls [a-z]*.o #匹配以a-z开头的已.o结尾的文件
ls [!0-9]*.o #匹配以非0-9开头的已.o结尾的文件
---------------------------------------------------------------------
命令执行顺序
命令1 && 命令2 #命令1执行成功才会执行命令2
命令1 || 命令2 #命令1执行不成功才会执行命令2
用() 和 {}将命令结合在一起
---------------------------------------------------------------------
Bash shell变量
变量可分为两种:局部变量和环境变量
局部变量只在创建他们的shell中可用,环境变量作用域可以扩展到子shell中去
变量命名规则:可以是字母、0-9、下划线组成,必须以字母或下划线开头,其他字符都标志着变量名的终止,变量名大小写敏感
有两个内置命令可以用来创建变量,他们是declare、typset,其选项可以控制变量的设置方式,建议使用declare.
格式:declare [选项] 变量=值
选项:-x 将变量设置成环境变量
-r 将变量设置成只读变量
-a 将变量当一个数组
---------------------------------------------------------------------
创建局部变量
1:变量赋值:变量=值 #注意等号周围不能有任何空白字符,如果想赋空,可以在等号后跟上换行符
2:内置命令declare 变量=值 #注意等号周围不能有任何空白字符,如果想赋空,可以在等号后跟上换行符
例子:
设置:round=world 或 round=”world nice” #“”保护空白符
设置:declare round=world
输出:echo $round
设置:file.bak=”xxxx” 错,变量名中出现非法字符
local函数:函数内创建局部变量可以用local函数
---------------------------------------------------------------------
创建环境变量
环境变量,又被称为全局变量,作用域可以扩展到子shell中,通常环境变量用大写
环境变量是已经用export内置命令导出的变量,如果想设置环境变量,只需在设置变量时或赋值后使用export命令即可,declare 带-x也是设置环境变量
设置环境变量:
1:export 变量=值 #注意等号周围不能有任何空白字符,如果想赋空,可以在等号后跟上换行符
2:变量=值; export 变量 #注意等号周围不能有任何空白字符,如果想赋空,可以在等号后跟上换行符
3:declare -x 变量=值 #注意等号周围不能有任何空白字符,如果想赋空,可以在等号后跟上换行符
---------------------------------------------------------------------
设置只读变量
只读变量是不能被重新定义或复位的特殊变量,但是如果使用declare定义的变量,可以重定义,不能复位
设置:name=”TOM”
readonly name #设置只读
unset name #不能复位
name=Jem #不能重定义
设置:declare -r city=”shanghai”
unset city #不能复位
declare city=“beijin” #可以
---------------------------------------------------------------------
提取变量的值
在变量前加$
---------------------------------------------------------------------
复位变量
只要不被设置只读,局部变量和环境变量都可以用unset命令复位
格式:unset 变量名
---------------------------------------------------------------------
显示变量值
1:echo [选项] 变量 #echo将他的参数显示到标准输出上
选项:-e #允许解释转义字符,如echo -e “a” a转义为报警
如:echo The name is $NAME
echo -e “a” #报警