大数据学习笔记——Shell入门
参考教程
Shell概述
Shell解析器
- Linux提供的Shell解析器
1 | [cuper@iZe4h75o51zvd0Z ~]$ cat /etc/shells |
- bash和sh的关系
1 | [cuper@iZe4h75o51zvd0Z bin]$ ll | grep bash |
sh为bash的软链接,功能一样。
- CentOS默认的解析器
1 | [cuper@iZe4h75o51zvd0Z bin]$ echo $SHELL |
Shell脚本入门
脚本格式
脚本以#!/bin/bash
开头:指定解析器
Shell脚本注释即以”#“开头。
helloworld
创建脚本文件vim Helloworld.sh
:
1 | !/bin/bash |
保存后执行:
1 | bash Helloworld.sh |
以上三个命令效果相等,文件的绝对路径或相对路径均可。
注:./Helloworld.sh
需要当前用户有可执行的权限,需要给所有者添加才可执行:chmod u+x Helloworld.sh
第一、二个命令本质是bash解析器帮你执行脚本,所以脚本本身不需要执行权限;第三个命令本质是脚本需要自己执行,所以需要执行权限。
多命令处理
一行一命令即可:
1 | !/bin/bash |
脚本变量
系统变量
常用变量:
$HOME
:当前用户的家目录$PWD
:当前绝对路径$SHELL
:当前脚本使用的解析器$USER
:当前用户
查看系统变量的值:echo $变量名
($
为取后面变量名对应的值的意思)
显示当前Shell中所有变量:set
使用一个定义过的变量,只要在变量名前面加$
即可。
自定义变量
基本语法
- 定义变量:
变量=值
(不用$
) - 撤销变量:
unset 变量
(不用$
) - 声明静态变量:
readonly 变量=值
(注意:静态变量只能一次赋值,无法unset,不能更改内容,不能重设,只有当前shell注销后才失效)
变量定义规则
- 变量名称可以由字母、数字和下划线组成,但是不能以数字开头,环境变量名建议大写。
- 等号两侧不能有空格。
- 在bash中,变量默认类型都是字符串类型,无法直接进行数值运算。
- 变量的值如果有空格,需要使用双引号或单引号括起来。
全局变量
把变量提升为全局环境变量,可供其他Shell程序使用:export 变量名
特殊变量
$n
传递给脚本的第n个参数值,n为数字,$0
代表该脚本名称,$1
-$9
代表第一到第九个参数,十以上的参数需要用大括号包含(如${10}
),执行时输入的实参直接空格跟在脚本执行命令后面:
1 | ./xxx.sh $1的值 $2的值 ... |
$#
获取所有输入参数的个数,常用于循环,在脚本里直接调用$#
。
$*
代表命令行中所有的参数,把所有的参数看成一个整体
$@
代表命令行中所有的参数,把每个参数区分对待
$?
显示最后一次执行的命令的返回状态。如果这个变量的值为0,证明上一个命令正确执行;如果这个变量的值为非0(具体是哪个数,由命令自己来决定),则证明上一个命令执行不正确了。
运算符
两种语法:
$((运算式))
或$[运算式]
:作为变量expr + , - , \*, /, %
:分别为加,减,乘(需要转义),除,取余,直接运算在终端上,expr运算符间要有空格。
条件判断(测试表达式)
语法
[ condition ]
注意:condition前后要有空格,条件非空即为true,[ xxx ]返回true,[] 返回false。
常用判断条件
- 两个整数之间比较:
[ num1 -参数 num2 ]
=
字符串比较-lt
小于(less than)-le
小于等于(less equal)-eq
等于(equal)-gt
大于(greater than)-ge
大于等于(greater equal)-ne
不等于(Not equal)
- 按照文件权限进行判断:
[ -参数 文件 ]
-r
有读的权限(read)-w
有写的权限(write)-x
有执行的权限(execute)
- 按照文件类型进行判断:
[ -参数 文件 ]
-f
文件存在并且是一个常规的文件(file)-e
文件存在(existence)-d
文件存在并是一个目录(directory)
多条件判断
expression1 && expression2
:与条件,表示expression1为真时,才执行expression2
expression1 || expression2
: 或条件,表示expression1为假才执行expression2,若expression1为真则直接返回true
expression1 ; expression2
:不管expression1执行是否正确,expression2都会执行(可用于脚本里把多个命令写在同一行)
常用:[ condition ] && echo 1 || echo 0
三元判断式用于直接测试condition是否返回true。
流程控制
if 判断
语法:
1 | if [ 条件判断式 ];then |
或
1 | if [ 条件判断式 ] |
注:
[ 条件判断式 ]
中括号和条件判断式之间必须有空格- if后要有空格
case 语句
语法:
1 | case $变量名 in |
注:
- case行尾必须为单词
in
,每一个模式匹配必须以右括号)
结束。 - 双分号
;;
表示命令序列结束,相当于java中的break
。 - 最后的
*)
表示默认模式,相当于java中的default
。
for 循环
语法1:
1 | for (( 初始值;循环控制条件;变量变化 )) |
语法2:
1 | for 变量 in 值1 值2 值3… |
注:in
后面常用$*
或$@
,在不带双引号时两者等价,都以$1 $2 … $n
的形式输出所有参数。
若被双引号""
包含时:
"$*"
会将所有的参数作为一个整体,以"$1 $2 … $n"
的形式输出所有参数,若在for循环的in里,所有参数看成是一个整体,所以for循环只会循环一次;"$@"
会将各个参数分开,以"$1"
"$2"
…"$n"
的形式输出所有参数,若在for循环的in里,每个参数都看成是独立的,所以"$@"
中有几个参数,就会循环几次 。
while 循环
语法:
1 | while [ 条件判断式 ] |
注:
[ 条件判断式 ]
中括号和条件判断式之间必须有空格- while后要有空格
read读取控制台输入
语法:
1 | read (选项) (参数) |
选项:
-p:指定读取值时的提示符;
-t:指定读取值时等待的时间(秒)。
参数:
- 变量:指定读取值的变量名
函数
系统函数
basename
1 | basename [string或pathname] [suffix] |
功能:去掉文件名的路径和后缀,会删掉所有的前缀包括最后一个/
字符,然后将字符串显示出来,常用于从绝对路径里截取出文件名称。
选项:suffix为后缀名,如果suffix被指定了,basename会将pathname或string中的suffix同时去掉。
dirname
1 | dirname 文件绝对路径 |
功能:从给定的包含绝对路径的文件名中去除文件名(非目录的部分),然后返回剩下的路径(目录的部分)
自定义函数
实质:自定义一个终端命令
语法:
1 | [ function ] funname[()] #这一行中括号里的function和小括号()均意为可写可不写 |
注意:
- 必须在调用函数地方之前先声明函数,shell脚本是逐行运行,不会像其它语言一样先编译。
- 函数返回值只能通过系统变量
$?
获得,可以显示加return
返回;如果不加,将以最后一条命令运行结果,作为返回值。return
后跟数值n(0-255)。
Shell工具
cut
功能
cut的工作就是“剪”,具体的说就是在文件中负责剪切数据用的。cut命令从文件的每一行剪切字节、字符和字段并将这些字节、字符和字段输出。
语法
1 | cut [选项参数] filename |
参数
选项参数 | 功能 |
---|---|
-f | 列号,提取第几列 |
-d | 分隔符,按照指定分隔符分割列(默认值为制表符) |
案例
- 在以空格为分隔符的cut.txt文件中切割出在某一行第一列里的”guan”:
1
cat cut.txt | grep "guan" | cut -d " " -f 1
- 选取系统PATH变量值,第2个
:
开始后的所有路径:1
echo $PATH | cut -d : -f 2- #`n-`表示从第n列开始到最后的所有字符串,`-n`表示从字符串开始取到第n列,均包含第n列本身
- 切割ifconfig后打印的IP地址:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21[cuper@iZe4h75o51zvd0Z ~]$ ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.16.19.31 netmask 255.255.240.0 broadcast 172.16.31.255
inet6 fe80::216:3eff:fe12:e6ca prefixlen 64 scopeid 0x20<link>
ether 00:16:3e:12:e6:ca txqueuelen 1000 (Ethernet)
RX packets 9518632 bytes 4811078305 (4.4 GiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 9940677 bytes 4450481278 (4.1 GiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[cuper@iZe4h75o51zvd0Z ~]$ ifconfig eth0 | grep "inet " | cut -d 't' -f 2 | cut -d ' ' -f 2
172.16.19.31
sed
功能
sed是一种流编辑器,它一次处理一行内容。处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”,接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件末尾。文件内容并没有改变,除非使用重定向存储输出。
语法
1 | sed [选项参数] 'command' filename |
选项参数
选项参数 | 功能 |
---|---|
-e | 将下一个参数解释为一个sed指令,只有当命令行上给出多个sed指令时才需要使用-e选项 |
命令功能
命令 | 功能描述 |
---|---|
a | 新增,a的后面可以接字符串,在下一行出现 |
d | 删除 |
s | 查找并替换 |
命令的使用:'command'
= 'na xxxx'
表示在第n行下面加入xxxx内容。
案例
- 将’hello’这个单词插入到sed.txt第二行下,打印:
1 | sed '2a hello' sed.txt |
注意:文件并没有改变
- 删除sed.txt文件所有包含hello的行:
1 | sed '/wo/d' sed.txt |
- 将sed.txt文件中hello替换为hi:
1 | sed 's/hello/hi/g' sed.txt |
注意:g
表示global,全部替换
- 将sed.txt文件中的第二行删除并将hello替换为hi:
1 | sed -e '2d' -e 's/hello/hi/g' sed.txt |
awk
功能
一个强大的文本分析工具,把文件逐行地读入,以空格为默认分隔符将每行切片,切开的部分再进行分析处理。
语法
1 | awk [选项参数] 'pattern1{action1} pattern2{action2} ...' filename |
- pattern:表示
awk
在数据中查找的内容,就是匹配模式,若没有则表示全部匹配 - action:在找到匹配内容时所执行的一系列命令
选项参数
选项参数 | 功能 |
---|---|
-F | 指定输入文件的分隔符 |
-v | var=value,赋值一个用户定义变量,方便action调用 |
-f | 后接一个保存了awk程序的文件,代替在命令行指定awk程序 |
awk指令里的BEGIN块和END块
用法:
1 | pattern{action}=BEGIN/END{action} |
- BEGIN用于初始化FS变量(列分隔符),打印标题,或者初始化后需要在程序中调用的全局变量
- END用于执行最后的运算或者打印最终的输出结果
- END块和BEGIN不是必须的
awk的内置变量
变量 | 说明 |
---|---|
FILENAME | 文件名 |
NR | 已读的记录数 |
NF | 浏览记录的域的个数(即切割后列的个数) |
案例
- 搜索passwd文件以root关键字开头的所有行,并输出该行的第1列和第7列,中间以
,
号分割:
1 | awk -F : '/^root/{print $1","$7}' /etc/passwd #/^root/为匹配root开头的行 |
注意:只有匹配了pattern的行才会执行action,在awk中使用正则匹配,正则表达式必须要放在//
中
- 只显示/etc/passwd的第一列和第七列,以逗号分割,且在所有行前面添加列名”user,shell”,在最后一行添加”The End”:
1 | awk -F : 'BEGIN{print "user,shell"} {print $1","$7} END{print "The End."}' /etc/passwd |
- 将passwd文件中的用户id增加数值1并输出:
1 | awk -F : -v i=1 '{print $3+i}' /etc/passwd |
- 统计passwd文件名,每行的行号,每行的列数:
1 | awk -F : '{print FILENAME "," NR "," NF}' /etc/passwd |
- 切割IP
1 | [cuper@iZe4h75o51zvd0Z ~]$ ifconfig |
- 查询sed.txt中空行所在的行号:
1 | awk '/^$/{print NR}' sed.txt #^开头,$结尾,/^$/表示空行 |
sort
功能
将文件进行排序,并将排序结果标准输出。
语法
1 | sort (选项) (参数) |
选项
选项 | 说明 |
---|---|
-n | 依照数值的大小排序 |
-r | 以相反的顺序来排序 |
-t | 设置排序时所用的分隔字符 |
-k | 指定需要排序的列 |
参数
指定待排序的文件列表
案例
- 按照
:
分割后的第三列倒序排序passwd:
1 | sort -t : -nrk 3 /etc/passwd |
面试真题
京东
Q1.使用Linux命令查询file1中空行所在的行号:
1 | awk '/^$/{print NR}' sed.txt |
Q2.有文件chengji.txt内容如下:
张三 40
李四 50
王五 60
使用Linux命令计算第二列的和并输出:
1 | cat chengji.txt | awk -F " " '{sum+=$2} END{print sum}' |
搜狐&和讯网
Q.Shell脚本里如何检查一个文件是否存在?如果不存在该如何处理?
1 | !/bin/bash |
新浪
Q.用shell写一个脚本,对文本中无序的一列数字排序,并计算总和
1 | sort -n test.txt | awk '{a+=$0;print $0} END{print "SUM="a}' |
金和网络
Q.请用shell脚本写出查找当前文件夹(/home)下所有的文本文件内容中包含有字符”shen”的文件名称
1 | grep -r "shen" /home | cut -d ":" -f 1 #只用grep会包含":文件内容",需要cut一下 |