Shell 学习笔记
Shell
学习目的:
1.看懂Shell程序
2.编写简单Shell程序管理集群、提高开发效率
Shell概述
外层应用程序通过Shell命令行解释器,调用操作系统的内核。
Shell易编写、易调试、灵活性强。
Shell解析器
Linux提供的Shell解析器有
[ranan@hadoop100 ~]$ sudo cat /etc/shells
/bin/sh
/bin/bash
/usr/bin/sh
/usr/bin/bash
其中sh与bash的关系,sh调用仍然是bash。
sh(Bourne shell)的增强版bash(Bourne Again SHell)
CentOs默认的解析器是bash
[ranan@hadoop100 ~]$ echo $SHELL
/bin/bash
Shell脚本入门
脚本格式
脚本以#!/bin/bash
开头 指定bash解析器
HelloWorld
需求:创建一个shell脚本,输出HelloWorld
1.创建HelloWorld.sh
[ranan@hadoop100 datas]$ touch HelloWorld.sh
[ranan@hadoop100 datas]$ vim HelloWorld.sh
2.编写HelloWorld.sh
#!/bin/bash
echo "HelloWorld"
3.执行HelloWorld.sh
方式一:本质是bash解析器帮你执行脚本,所以脚本本身不需要执行权限
[ranan@hadoop100 datas]$ sh HelloWorld.sh
HelloWorld
[ranan@hadoop100 datas]$ bash HelloWorld.sh
HelloWorld
方式二:本质是脚本自己需要执行,所以需要执行权限
多命令脚本
需求:脚本batch.sh 在/home/ranan/datas下创建banzhang.txt,banzhang.txt中增加'my name is ranan'
1.创建batch.sh
[ranan@hadoop100 datas]$ touch batch.sh
[ranan@hadoop100 datas]$ vim batch.sh
2.编写batch.sh
#!/bin/bash
cd /home/ranan/datas
touch banzhang.txt
echo "my name is ranan" >> banzhang.txt
3.执行batch.sh
Shell中的变量
系统变量
常见的系统变量:$PWD $HOME $SHELL $USER 等
家目录
[ranan@hadoop100 datas]$ echo $HOME
/home/ranan
默认shell解析器
[ranan@hadoop100 datas]$ echo $SHELL
/bin/bash
当前用户
[ranan@hadoop100 datas]$ echo $USER
ranan
当前路径
[ranan@hadoop100 datas]$ echo $PWD
/home/ranan/datas
自定义变量
基本语法
定义变量:变量=值 等号两边不能留有空格
撤销变量:unset 变量
变量使用:echo $变量 取值才加$
声明静态变量: readonly 变量=值。不能unset
[ranan@hadoop100 datas]$ A=1
[ranan@hadoop100 datas]$ echo $A
1
[ranan@hadoop100 datas]$ unset A
变量定义规则
1、变量名称可以由字母,数字和下划线组成,不能以数字开头,环境变量名建议大写
2.等号两侧不能有空格
3.在bash中,变量默认类型都是字符串类型,无法直接进行数值运算
[ranan@hadoop100 datas]$ C=1+1
[ranan@hadoop100 datas]$ echo $C
1+1
4.变量的值如果有空格,需要使用双引号或单引号括起来
[ranan@hadoop100 datas]$ D="my name"
[ranan@hadoop100 datas]$ echo $D
my name
5.可把变量提升为全局变量,可供其他shell程序使用
语法:export 变量
[ranan@hadoop100 datas]$ export A
特殊变量$n
功能描述
n为数字 $0代表该脚本名称,$1-$9代表第一个到第九个参数,第十个以上的参数需要用大括号括住${10}
案例
输出脚本名,第一个参数和第二个参数
[ranan@hadoop100 datas]$ touch parameter.sh
[ranan@hadoop100 datas]$ vim parameter.sh
[ranan@hadoop100 datas]$ cat parameter.sh
#!/bin/bash
echo "$0 $1 $2"
[ranan@hadoop100 datas]$ bash parameter.sh
parameter.sh
[ranan@hadoop100 datas]$ bash parameter.sh myname ranan
parameter.sh myname ranan
[ranan@hadoop100 datas]$
$# 输入参数的个数
功能描述
获取所有输入参数个数,常用于循环
案例
[ranan@hadoop100 datas]$ vim parameter.sh
[ranan@hadoop100 datas]$ cat parameter.sh
#!/bin/bash
echo $#
[ranan@hadoop100 datas]$ bash parameter.sh myname is ranan
3
$* 和 $@ 所有的参数
- $* 代表命令行中所有的参数,把所有参数看成一个整体
- $@ 也代表命令行中所有的参数,不过把每个参数区分对待
[ranan@hadoop100 datas]$ vim parameter.sh
[ranan@hadoop100 datas]$ cat parameter.sh
#!/bin/bash
echo $*
echo $@
[ranan@hadoop100 datas]$ bash parameter.sh my name is ranan
my name is ranan
my name is ranan
$? 最后一次执行命令的状态
最后一次执行命令的状态
0:上一条命令正确执行
非0:上一条命令执行不正确
[ranan@hadoop100 datas]$ bash HelloWorld.sh
HelloWorld
[ranan@hadoop100 datas]$ echo $?
0
[ranan@hadoop100 datas]$ echo$?
bash: echo0: 未找到命令...
相似命令是: 'echo'
[ranan@hadoop100 datas]$ echo $?
127
运算符
$((运算式)) 或 $[运算式]
expr +,-,*,/,% 加减乘除取余
expr运算符间要有空格
$[运算式]常用
案例
1.计算3+2
[ranan@hadoop100 datas]$ expr 2+3
2+3
[ranan@hadoop100 datas]$ expr 2 +3
expr: syntax error: unexpected argument “+3”
[ranan@hadoop100 datas]$ expr 2 + 3
5
2.计算(2+3)*4
方式1``代表括号
[ranan@hadoop100 datas]$ expr `expr 2 + 3` \* 4
20
方式2
[ranan@hadoop100 datas]$ echo $[(2+3)*4]
20
条件判断
基本语法
[ condition ]
注意
1.condition前后要有空格
2.条件非空返回true
常用判断条件
两个整数之间比较
= 字符串比较
符号 | 描述 |
---|---|
-lt | (less than)小于 |
-le | (less equal) 小于等于 |
-eq | (equal)等于 |
-gt | (greater than) 大于 |
-ge | (greater equal) 大于等于 |
-ne | (not equal) 不等于 |
按照文件权限比较
-r 有读的权限
-w 有写的权限
-x 有执行的权限(execute)
文件类型判断
-f 文件存在并且是一个常规文件(file)
-e 文件存在(existence)
-d 文件存在并是一个目录(directory)
多条件判断
$$ 逻辑与
|| 逻辑或
案例
判断23是否大于2
[ranan@hadoop100 datas]$ [ 23 -gt 2 ]
[ranan@hadoop100 datas]$ echo $?
0
判断helloworld.sh是否有写入权限
[ranan@hadoop100 datas]$ [ -w hellowrld.sh ]
[ranan@hadoop100 datas]$ echo $?
1
判断目录中文件是否存在
[ranan@hadoop100 datas]$ [ -e /home/ranan/datas ]
[ranan@hadoop100 datas]$ echo $?
0
流程控制
if条件判断
基本语法
写法1
if [空格 条件判断式 空格];then
程序
fi
写法2
if[空格 条件判断式 空格]
then
程序
fi
案例
[ranan@hadoop100 datas]$ cat if.sh
#!/bin/bash
if [ $1 -eq 1 ]
then
echo "班长真帅"
elif [ $1 -eq 2 ]
then
echo "班长真丑"
fi
[ranan@hadoop100 datas]$ bash if.sh 2
班长真丑
case语句
基本语法
case 变量名 in
"值1")
如果变量值等于值1执行程序1
;;
"值2")
如果变量值等于值2执行程序2
;;
*)
如果都不是,执行这里的代码块
;;
esac
案例
[ranan@hadoop100 datas]$ cat case.sh
#!/bin/bash
case $1 in
1)
echo "班长"
;;
2)
echo "学习委员"
;;
3)
echo "体育委员"
;;
esac
[ranan@hadoop100 datas]$ bash case.sh 2
学习委员
for循环
基本语法
写法1
for((初始值;循环控制条件;变量变化))
do
程序
done
写法2
for 变量 in 值1 值2 值3
do
程序
done
案例
写法1
[ranan@hadoop100 datas]$ cat for.sh
#!/bin/bash
s=0
for((i=1;i<=100;i++))
do
s=$[$s+$i]
done
echo $s
[ranan@hadoop100 datas]$ bash for.sh
5050
写法2
[ranan@hadoop100 datas]$ cat for2.sh
#!/bin/bash
for i in $*
do
echo $i
done
[ranan@hadoop100 datas]$ bash for2.sh 1 2
1
2
区分$*与$@
加了引号,$*会被看成一个整体
[ranan@hadoop100 datas]$ cat for2.sh
#!/bin/bash
for i in "$*"
do
echo $i
done
for i in "$@"
do
echo $i
done
[ranan@hadoop100 datas]$ bash for2.sh 1 2
1 2
1
2
while循环
基本语法
while [ 条件判断式 ]
do
程序
done
案例
[ranan@hadoop100 datas]$ cat while.sh
#!/bin/bash
s=0
i=1
while [ $i -le 100 ]
do
s=$[$s + $i]
i=$[$i + 1]
done
echo $s
[ranan@hadoop100 datas]$ bash while.sh
5050
read读取控制台输入
基本语法
read 常用选项 参数
常用选项
-p 指定读取值时的提示符
-t 指定读取值时等待的时间(秒)
参数
变量:指定读取值的变量名
案例
提示7秒内,读取控制台输入的名称
[ranan@hadoop100 datas]$ cat red.sh
#!/bin/bash
read -t 7 -p "在7s内请输入你的名字" NAME
echo $NAME
[ranan@hadoop100 datas]$ bash red.sh
在7s内请输入你的名字ranan
ranan
函数
系统函数
basename
基本语法
basename [string / path] [suffix]
说明
basename命令会删掉所有的路径前缀包括最后一个‘/’字符,然后将文件名称以字符串形式展现出来
suffix表示后缀,如果suffix被指定了,basename会删除string/path中的后缀。
获取文件的名称
案例
[ranan@hadoop100 datas] basename /home/linux/banzhang.txt
banzhang.txt
[ranan@hadoop100 datas]$ basename /home/linux/banzhang.txt .txt
banzhang
dirname
基本语法
dirname 文件的绝对路径
描述
从给定的包含绝对路径的文件名中去除文件名(非目录的部分),然后返回剩下的路径(目录的部分)
获取文件所在的路径(不包含文件本身)
案例
[ranan@hadoop100 datas]$ dirname /home/linux/banzhang.txt
/home/linux
自定义函数
基本语法
[ function ] 函数名[()]
{
Action:
[return int;] 一般不采用
}
funname
说明
1.必须在调用函数之前声明函数,shell逐行执行,不会先编译。
2.函数返回值只能通过$?获取,将以最后一条命令的运行结果,作为返回值。可以显示添加return 数值(0-255),和以前的返回值意思不一样,返回的是运行结果状态。
案例
1.计算输入两个参数的值
[ranan@hadoop100 datas]$ cat sum.sh
#!/bin/bash
function sum(){
s=0;
s=$[$1 + $2]
echo $s
}
read -p "input your param1:" P1
read -p "input your param2:" P2
sum $P1 $P2
[ranan@hadoop100 datas]$ bash sum.sh
input your param1:1
input your param2:2
3
Shell工具
cut剪切
基本语法
cut [选项参数] filename
说明
cut命令从文件的每一行剪切字节,字符和字段并将这些字节,字符和字段输出
选项参数
-f 列号,提取第几列
-d 分隔符,原文件按照指定分隔符分隔列
案例
切割cut.txt第一列
切割cut.txt第二列和第三列
[ranan@hadoop100 datas]$ cat cut.txt
dong shen
guan zhen
wo wo
lai lai 两个空格
le le 两个空格
[ranan@hadoop100 datas]$ cut -d " " -f 1 cut.txt
dong
guan
wo
lai
le
[ranan@hadoop100 datas]$ cut -d " " -f 2,3 cut.txt
shen
zhen
wo
lai
le
2.获取guan
[ranan@hadoop100 datas]$ cat cut.txt | grep guan
guan zhen
[ranan@hadoop100 datas]$ cat cut.txt | grep guan | cut -d " " -f 1
guan
3.PATH变量第二个:开始后的所有路径
3- 表示第三列及以后
[ranan@hadoop100 datas]$ echo $PATH | cut -d ":" -f 3-
/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin
sed流编辑器
基本语法
sed [选项参数] ‘命令’ filename
说明
sed是一种流编辑器,它一次处理一行内容,处理时,把当前处理的行存储在临时缓冲区中,成为“模式空间”,接着sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕,接着处理下一行,这样不断重复,知道文件末尾,文件内容并没有改变。除非你使用重定向存储输出
常用选项
-e 适用于多条指令,每条指令前面加-e
命令说明
行号a 内容 新增
行号d/ 或者 /内容/d 删除
s 查找并替换
案例
1.在空格行(5行)后增加shang hai字符
[ranan@hadoop100 datas]$ cat cut.txt
dong shen
guan zhen
wo wo
lai lai
le le
[ranan@hadoop100 datas]$ sed "5a shang hai" cut.txt
dong shen
guan zhen
wo wo
lai lai
shang hai
le le
2.每一行的后新增一行,新增行内容哦为!
[ranan@hadoop100 datas]$ sed "a !" cut.txt
dong shen
!
guan zhen
!
wo wo
!
lai lai
!
!
le le
!
3.删除wo这一行
# 方式1
[ranan@hadoop100 datas]$ sed "3d" cut.txt
dong shen
guan zhen
lai lai
le le
# 方式二
[ranan@hadoop100 datas]$ sed "/wo/d" cut.txt
dong shen
guan zhen
lai lai
le le
[ranan@ha
4.将wo替换成ni g全局替换,不加只替换一个
# 替换一个
[ranan@hadoop100 datas]$ sed "s/wo/ni/" cut.txt
dong shen
guan zhen
ni wo
lai lai
le le
# 全局替换
[ranan@hadoop100 datas]$ sed "s/wo/ni/g" cut.txt
dong shen
guan zhen
ni ni
lai lai
le le
5.删除第二行并将wo换成ni
两条指令了,需要使用-e
[ranan@hadoop100 datas]$ sed -e "2d" -e "s/wo/ni/g" cut.txt
dong shen
ni ni
lai lai
le le
awk
语法
awk [选项参数] 'pattern1 {action1} pattern2{action2}..' filename
pattern:表示awk在数据中查找的内容,就是匹配模式
action:在找到匹配内容时执行的一系列命令
说明
awk 一个强大文件分析工具,把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行分析处理
常用选项
-F 指定输入文件分隔符
-v 赋值一个用户定义变量
内置变量
FILENAME 文件名
NR 已读的记录数,当前行数
NF 切割后,列的个数
$NF 最后一个域,最后一列
案例
数据文件
1.搜索passwd文件以root关键字开头的所有行,并输出该行的第1,7列,以逗号输出
第一列可以用$1或$0表示
[ranan@hadoop100 datas]$ awk -F : '/^root/{print $1","$7}' passwd
2.显示第1,7列,以逗号分割,且在开头添加列名user,最后一行添加"ranan,"
[ranan@hadoop100 datas]$ awk -F : 'BEGIN{print "user,"} /^root/{print $1","$7} END{print "ranan,"}' passwd
3.用户id(第三列)增加数值1并输出
这里变量的使用不用加$
[ranan@hadoop100 datas]$ awk -F : -v i=1 '{print $3+i}' passwd
[ranan@hadoop100 datas]$ awk -F : '{print $3+1}' passwd
4.统计passwd文件名,每行的行号,每行的列数
awk -F '{print FILENAME "," NR "," NF}' passwd
5.查询sed.txt中空行所在的行号
awk -F '/^$/{print NR}' sed.txt中
sort排序
基本语法
sort [选项] [参数]
说明
sort 命令是在Linux里非常有用,它将文件进行排序,并将排序结果标准输出
常见选项
参数 | 描述 |
---|---|
-n | 依照数值大小排序 |
-r | 以相反的顺序排序 |
-t | 设置排序时使用的分隔字符 |
-k | 指定需要排序的列 |
案例
以打到小的顺序排序第二列
[ranan@hadoop100 datas]$ cat sort
bb:40:5.4
cc:50:6.6
dd:10:1.6
ee:20:2
[ranan@hadoop100 datas]$ sort -t : -nrk 2 sort
cc:50:6.6
bb:40:5.4
ee:20:2
dd:10:1.6
面试题
问题1:使用Linux命令查询file中空行所在的行号
空行:/^$/
awk '/^$/{print NR}' file
问题2:有文件chengji.txt如下
张三 40
李四 50
王五 60
用Linux命令计算第二列的和并输出
cat chengji.txt | awk -F " " '{sum+=$2} END{print sum}'
问题3:Shell脚本里如何检查一个文件是否存在,如果不存在该如何处理
#!/bin/bash
if [ -f file.txt ]
then
echo "文件存在"
elif
echo"文件不存在"
fi
问题4:用shell写一个脚本,对test.txt文本中无序的一列数字排序
9
8
7
6
4
5
10
2
sort -n test.txt
问题5:请用shell脚本查找当前文件夹(/home)下所有文本内容中包含'shen'的文件名称
[ranan@hadoop100 datas]$ grep -r "shen" /home
/home/ranan/datas/o d:dong shen
/home/ranan/datas/abc:shen
写法1
[ranan@hadoop100 datas]$ grep -r "shen" /home | cut -d : -f 1
/home/ranan/datas/o d
/home/ranan/datas/abc
写法2
[ranan@hadoop100 datas]$ grep -r "shen" /home | awk -F : '{print $1}'
/home/ranan/datas/o d
/home/ranan/datas/abc