大数据开发工程师-第一周 第4章 Linux试炼之配置与shell实战


第一周 第4章 Linux试炼之配置与shell实战

linux高级配置

给linux设置静态ip地址

1
2
3
4
5
6
7
8
9
10
一个简单的方法:
1.在虚拟机和主机互通的条件下
2.如果之前设置的vmnet8是自动获取,可以根据cmd里的vmnet8来设置ip,网关,掩码;如果之前已经是设置的固定信息那就不管
3.修改虚拟机文件/etc/sysconfig/network-scripts/ifcfg-ens33
dhcp修改为static
onboot的值修改为yes
尾外加:
IPADDR="根据虚拟机ipaddr 或 ipconfig获得的值来设置"
GATEWAY="根据vmnet8的值来设置"
ENS1="与上一个相同"
1
2
3
4
修改好以后还有最重要的一步,重启网卡。如果结果显示的是OK,就说明是没有问题的。

[root@localhost ~]# service network restart
Restarting network (via systemctl): [ OK ]

Linux起名字(hostname)

1
2
3
4
5
  那针对linux机器也是一样的,ip不好记,所以针对每一台linux机器还有一个主机名,hostname,我们可以给hostname设置一个通俗易懂、方便记忆的名字。
针对hostname的设置分为两种:
一种是临时设置,立刻生效,但是机器重启之后就失效了。
还有一种是永久设置,但需要重启之后才生效。
所以在实际工作中这两个要结合起来使用,临时+永久设置就可以实现立刻生效、永久有效。
1
2
3
4
5
hostname //获取主机名

hostname bigdata01 //设置临时名

设置/etc/hostname文件 // 永久修改

Linux的金钟罩铁布衫(防火墙)

1
2
  我们在学习阶段,建议关闭防火墙,因为在后面我们会使用到多台机器,如果不关闭防火墙,会遇到机器之间无法通信的场景,比较麻烦,在实际工作中这块工作是由运维负责管理的,我们不需要关注这块。
注意:在实际工作中一般是不需要关闭防火墙的,大家可千万别到时候,上去就把防火墙给关闭了,那样的话针对线上的服务器是有很大安全风险的,我们现在学习阶段是使用的自己本地搭建的虚拟机,不会出现任何安全风险,你们现在遇到的风险都是来源于你们自己。
1
2
3
4
针对防火墙的关闭也分为两种方式,临时关闭和永久关闭,
临时关闭的特性是立刻生效,重启失效
永久关闭的特性是重启生效,永久有效
那在这里使用的时候还是要结合这两种方式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
centos7:
首先实现临时关闭
systemctl stop firewalld
执行临时关闭以后可以通过status确认当前防火墙的状态
systemctl status firewalld

然后再实现永久关闭,防止重启后生效
systemctl disable firewalld
关闭以后我们可以通过这个list-unit-files来确认一下是否从开机启动项中关闭了
systemctl list-unit-files | grep firewalld
firewalld.service disabled


centos6:
首先实现临时关闭
service iptables stop
然后再实现永久关闭,防止重启后生效
chkconfig iptables off

linux之shell编程

什么是shell

1
2
 shell编程其实就是把之前在shell中执行的单个命令按照一定的逻辑和规则,组装到一个文件中,后面执行的时候就可以直接执行这个文件了,这个文件我们称之为shell脚本。
所以shell编程,最终其实就是要开发一个shell脚本。

我的第一个shell脚本

1
2
3
4
5
  shell脚本的后缀倒没有那么严格的要求,只是建议大家以.sh结尾,这算是一个约定,大家都遵守这个约定,后期只要看到.sh结尾的文件就知道这个是shell脚本了。
shell脚本的第一行内容是: #!/bin/bash

这句话相当于是一个导包语句,将shell的执行环境引入进去了。
注意了,第一行的#号可不是注释,其它行的#号才是注释
1
2
3
4
>>> vi hello.sh
#!/bin/bash
# first command
echo hello world!

执行我的shell脚本

1
2
3
4
5
6
7
8
9
10

>>> bash hello.sh
hello world!
还有一种写法是sh hello.sh


其实这里不管是bash 还是sh 都是一样的
bash对应的是/bin目录下面的bash文件

sh是一个链接文件,指向的也是/bin目录下面的bash文件
1
其实bash和sh在之前对应的是两种类型的shell,不过后来统一了,我们在这也就不区分了,所以在shell脚本中的第一行引入/bin/bash,或者/bin/sh都是一样的,这块大家知道就行了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
注意了,大家在看其它资料的时候,资料中一般都会说需要先给脚本添加执行权限,然后才能执行,为什么我们在这里没有给脚本增加执行权限就能执行呢?

在这里可以看到这个脚本确实只有读写权限
[root@bigdata01 shell]# ll
total 4
-rw-r--r--. 1 root root 45 Apr 2 16:11 hello.sh

主要原因是这样的,我们现在执行的时候前面指定bash或者sh,表示把hello.sh这个脚本中的内容作为参数直接传给了bash或者sh命令来执行,所以这个脚本有没有执行权限都无所谓了。
那下面我们就来给这个脚本添加执行权限
chmod u+x hello.sh

添加完执行权限之后,再执行的时候就可以使用简化形式了

./hello.sh
这里的.表示是当前目录,表示在当前目录下执行这个脚本

这里指定全路径也可以执行
[root@bigdata01 shell]# /root/shell/hello.sh

[root@bigdata01 shell]# hello.sh
-bash: hello.sh: command not found
这样直接执行却提示命令没找到?有没有感到疑惑?
1
2
3
4
  主要原因是这样的,因为在这里我们直接指定的文件名称,前面没有带任何路径信息,那么按照linux的查找规则,它会到PATH这个环境变量中指定的路径里面查找,这个时候PATH环境变量中都有哪些路径呢,我们来看一下
[root@bigdata01 shell]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
所以说到这些路径里面去找肯定是找不到的,那怎么办呢?如果大家在windows中配置过JAVA的PATH环境变量的话就比较容易理解了,在这里我们只需要在PATH中加一个.即可,.表示当前目录,这样在执行的时候会自动到当前目录查找。
1
2
3
4
5
6
7
8
打开/etc/profile文件,在最后一行添加export PATH=.:$PATH,保存文件即可
vi /etc/profile
........
.......
.......
export PATH=.:$PATH

然后执行source /etc/profile 重新加载环境变量配置文件,这样才会立刻生效
1
2
3
4
5
6
7
最后再讲一个小命令,shell脚本的单步执行,可以方便脚本调试

[root@bigdata01 shell]# bash -x hello.sh
+ echo hello 'world!'
hello world!

+号开头的内容表示是脚本中将要执行的命令,下面的内容是执行的结果,这样如果脚本中的命令比较多的话,看起来是比较清晰的。

shell中的变量

1
学习任何编程语言都需要先学习变量,shell也不例外,但是要注意,shell中的变量不需要声明,初始化也不需要指定类型,shell是一门弱类型的语言,JAVA则是强类型的语言,需要提前声明变量,并且指定变量类型。
1
2
3
  shell中变量的命名要求:
只能使用数字、字母和下划线,且不能以数字开头
变量赋值是通过"="进行赋值,在变量、等号和值之间不能出现空格!
1
创建一些变量,执行之后提示-bash: name: command not found的都表示是错误的,执行成功的话是没有任何输出的,没有反馈就是最好的结果
1
2
3
4
5
6
打印变量的值,通过echo命令
[root@bigdata01 shell]# echo $name
zs
[root@bigdata01 shell]# echo ${name}
zs
这两种形式都可以,一个是完整写法,一个是简化写法
1
2
3
4
5
6
7
8
9
10
11
有什么区别吗?
如果我们想在变量的结果后面直接无缝拼接其它字符串,那就只能使用带花括号的形式
[root@bigdata01 shell]# echo $namehehe

[root@bigdata01 shell]# echo ${name}hehe
zshehe


如果带空格的话就无所谓了
[root@bigdata01 shell]# echo $name hehe
zs hehe

变量的分类

1
2
3
4
5
6
shell中的变量可以分为四种:

本地变量
环境变量
位置变量
特殊变量
本地变量
1
2
3
本地变量的格式是VAR_NAME=VALUE

这种变量一般用于在shell脚本中定义一些临时变量,只对当前shell进程有效,关闭shell进程之后就消失了,对当前shell进程的子进程和其它shell进程无效,
1
2
3
4
5
6
当前shell的子进程进入方法:
直接bash

退出exit

可以用pstree查看,但用不来
环境变量
1
2
3
4
5
它的格式为:export VAR_NAME=VALUE

它的格式是在本地变量格式的基础上添加一个export参数
环境变量的这种格式主要用于设置临时环境变量,当你关闭当前shell进程之后环境变量就消失了,还有就是对子shell进程有效,对其它shell进程无效
注意了,环境变量的生效范围和本地变量是不一样的,环境变量对子shell进程是有效的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  注意了,在实际工作中我们设置环境变量一般都是需要让它永久生效,这种临时的并不适用,如何设置为永久的呢?
其实就是把这个临时的设置添加到指定配置文件中,以后每次开启shell进程的时候,都会去加载那个指定的配置文件中的命令,这样就可以实现永久生效了

在这里我们一般添加到/etc/profile文件中,这样可以保证对所有用户都生效

>>> vim /etc/profile
.
.
.
.
export az=4

设置完后,当前shell窗口需要执行 source /etc/profile
其它新打开的shell不需要
位置变量
1
2
3
在进行shell编程的时候,有时候我们想给shell脚本动态的传递一些参数,这个时候就需要用到位置变量,类似于$0 $1 $2这样的,$后面的数字理论上没有什么限制,

它的格式是:location.sh abc xyz
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
创建一个脚本文件,location.sh 在里面打印一下这些位置变量看看到底是什么内容

[root@bigdata01 shell]# vi location.sh
#!/bin/bash
echo $0
echo $1
echo $2
echo $3

执行脚本sh location.sh abc xyz
[root@bigdata01 shell]# sh location.sh abc xyz
location.sh
abc
xyz

结果发现 $0的值是这个脚本的名称
$1 是脚本后面的第一个参数
$2是脚本后面的第二个参数
$3为空,是因为脚本后面就只有两个参数
理论上来说,脚本后面有多少个参数,在脚本中就可以通过$和角标获取对应参数的值。
多个参数中间使用空格分隔。
特殊变量
1
最后来看一下shell中的特殊变量,针对特殊变量我们主要学习下面列出来的两个
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
首先是$?
它表示是上一条命令的返回状态码,状态码在0~255之间
如果命令执行成功,这个返回状态码是0,如果失败,则是在1~255之间,不同的状态码代表着不同的错误信息,也就是说,正确的道路只有一条,失败的道路有很多。

>>> echo $?


状态码 描述
0 命令成功结束
1 通用未知错误  
2 误用Shell命令
126 命令不可执行
127 没找到命令
128 无效退出参数
128+x Linux信号x的严重错误
130 命令通过Ctrl+C控制码越界
255 退出码越界

这个状态码在工作中的应用场景是这样的,我们有时候会根据上一条命令的执行结果来执行后面不同的业务逻辑
1
2
3
4
5
6
7
8
9
10
11
12
13
14
第二个特殊变量是$#,它表示的是shell脚本所有参数的个数

我们来演示一下,先创建paramnum.sh

[root@bigdata01 shell]# vi paramnum.sh
#!/bin/bash
echo $#
然后执行

[root@bigdata01 shell]# sh paramnum.sh a b c
3
[root@bigdata01 shell]# sh paramnum.sh a b c d
4
这个特殊变量的应用场景是这样的,假设我们的脚本在运行的时候需要从外面动态获取三个参数,那么在执行脚本之前就需要先判断一下脚本后面有没有指定三个参数,如果就指定了1个参数,那这个脚本就没有必要执行了,直接停止就可以了,参数个数都不够,执行是没有意义的。
变量和引号的特殊使用
1
2
3
4
5
  前面我们学习了shell中的变量,那针对变量和引号在工作中有一些特殊的使用场景
单引号 首先是单引号不解析变量
>>> name=jack
>>> echo '$name'
'$name'
1
2
3
4
双引号解析变量
>>> name=jack
>>> echo ''$name''
jack
1
2
3
4
5
6
7
8
反引号   执行并引用命令的执行结果
>>> name=pwd
>>> echo `$name`
/root/shell

反引号还有另一种写法,$() 他们的效果一致
[root@bigdata01 shell]# echo $($name)
/root/shell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  最后还有一个大招 大家注意一下
有时候我们想在变量的值外面套一层引号,该怎么写呢?
echo "$name"是不行的,最终的值是不带引号的

[root@bigdata01 shell]# echo "$name"
pwd
那我在外面套一层单引号呢?这样虽然值里面带双引号了,但是这个变量却没有解析

[root@bigdata01 shell]# echo '"$name"'
"$name"
还能怎么办呢?
看一下这个骚操作,先套一个单引号,再套一个双引号,这样就可以了。

[root@bigdata01 shell]# echo "'$name'"
'pwd'
什么时候需要在结果里面带引号呢?在后面课程中我们在脚本中动态拼接sql的时候会用到。

linux shell 字符串中指定字符替换

1
2
3
4
5
echo ${string/23/bb}  //abc1bb42341 替换一次  

echo ${string//23/bb} //abc1bb4bb41 双斜杠替换所有匹配
2. echo ${string/#abc/bb} //bb12342341 #以什么开头来匹配,根php中的^有点像
3. echo ${string/%41/bb} //abc123423bb %以什么结尾来匹配,根php中的$有点像

shell中的循环和判断

for循环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
第一种格式:和java中的for循环格式有点类似,但是也不一样
for((i=0;i<10;i++))
do
循环体...
done

[root@bigdata01 shell]# vi for1.sh
#!/bin/bash
for((i=0;i<10;i++))
do
echo $i
done

注意了,这里的do也可以和for写在一行,只是需要加一个分号;
[root@bigdata01 shell]# vi for1.sh
#!/bin/bash
for((i=0;i<10;i++));do
echo $i
done

[root@bigdata01 shell]# sh for1.sh
0
1
2
3
4
5
6
7
8
9
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
这一种格式适合用在迭代多次,步长一致的情况

接下来看第二种格式,这种格式针对没有规律的列表,或者是有限的几种情况进行迭代是比较方便的
for i in 1 2 3
do
循环体...
done
演示一下,

[root@bigdata01 shell]# vi for2.sh
#!/bin/bash
for i in 1 2 3
do
echo $i
done
执行,看结果

[root@bigdata01 shell]# sh for2.sh
1
2
3

while循环

1
2
3
4
5
6
7
8
  while循环主要适用于循环次数未知,或不便于使用for直接生成较大列表时
while循环的格式为:
while 测试条件
do
循环体...
done
注意这里面的测试条件,测试条件为"真",则进入循环,测试条件为"假",则退出循环
那这个测试条件该如何定义呢?
1
2
3
4
5
6
7
8
9
10
  test EXPR 或者 [ EXPR ] ,第二种形式里面中括号和表达式之间的空格不能少
这个EXPR表达式里面写的就是具体的比较逻辑,shell中的比较有一些不同之处,针对整型数据和字符串数据是不一样的,来看一下

整型测试:-gt(大于)、-lt(小于)、-ge(大于等于)、-le(小于等于)、-eq(等于)、-ne(不等于)

针对整型数据,需要使用-gt、-lt这样的写法,而不是大于号或小于号,这个需要注意一下
还有就是字符串数据,如果判断两个字符串相等,使用=号,这里的=号不是赋值的意思,不等于就使用!=就可以了
字符串测试:=(等于)、!=(不等于)

下面来演示一下,创建 while1.sh,注意,这里面需要使用sleep实现休眠操作,否则程序会一直连续的打印内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@bigdata01 shell]# vi while1.sh
#!/bin/bash
while test 2 -gt 1
do
echo yes
sleep 1
done
执行脚本,按ctrl+c可强制退出程序

[root@bigdata01 shell]# sh while1.sh
yes
yes
yes
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
中括号这种,看起来比较清晰
只是这种一定要注意,中括号和里面的表达式之间一定要有空格,否则就报错
[root@bigdata01 shell]# cp while1.sh while2.sh
[root@bigdata01 shell]# vi while2.sh
#!/bin/bash
while [ 2 -gt 1 ]
do
echo yes
sleep 1
done
[root@bigdata01 shell]# sh while2.sh
yes
yes
yes
...

if判断

1
2
3
4
5
if判断分为三种形式

单分支
双分支
多分支
单分支
1
2
3
4
5
6
单分支
先看一下单分支,它的格式是这样的
if 测试条件
then
选择分支
fi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@bigdata01 shell]# vi if1.sh 
#!/bin/bash
flag=$1
if [ $flag -eq 1 ]
then
echo one
fi
执行脚本

[root@bigdata01 shell]# sh if1.sh 1
one
[root@bigdata01 shell]# sh if1.sh
if1.sh: line 3: [: -eq: unary operator expected
在这里发现,如果脚本后面没有传参数的话,执行程序会抱错
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
改进
[root@bigdata01 shell]# vi if1.sh
#!/bin/bash
if [ $# -lt 1 ] #判断脚本后面参数的个数
then
echo "not found param"
exit 100 # 这个状态码其实就是我们之前使用$?获取到的状态码,如果这个程
#序不传任何参数,就会执行exit 100,结束程序,并且返回状态码100
fi

flag=$1
if [ $flag -eq 1 ]
then
echo "one"
fi

[root@bigdata01 shell]# sh if1.sh
not found param
[root@bigdata01 shell]# echo $?
100
双分支
1
2
3
4
5
6
7
格式如下:
if 测试条件
then
选择分支1
else
选择分支2
fi
多分支
1
2
3
4
5
6
7
8
9
10
11
12
格式如下:

if 测试条件1
then
选择分支1
elif 测试条件2
then
选择分支2
...
else
选择分支n
fi

shell扩展

shell后台运行

1
2
3
4
5
6
  在实际工作中会遇到这种情况,针对带有while无限循环的shell脚本,我们希望它能够一直运行,不影响我在这个窗口执行其它操作

但是现在它会一直占用这个shell窗口,我们称这个脚本现在是在前台执行,不想让它一直占用shell窗口的话,需要把它放到后台执行,如何放到后台呢?很简单,在脚本后面添加一个&即可

[root@bigdata01 shell]# sh while2.sh &
[1]2228
1
但是当我们把这个窗口关闭以后会发现之前放到后台运行的shell脚本也停止了,我们是希望这个脚本能够一直在后台运行的
1
2
3
  如何保证关闭shell窗口而不影响放到后台的shell脚本执行呢?
也很简单,在命令前面加上nohup 即可
原理就是,默认情况下,当我们关闭shell窗口时,shell窗口会向之前通过它启动的所有shell脚本发送停止信号,当我们加上nohup之后,就会阻断这个停止信号的发送,所以已经放到后台的shell脚本就不会停止了。
1
2
3
4
5
6
[root@bigdata01 shell]# nohup sh while2.sh &
[1]2326
nohup: ignoring input and appending output to ‘nohup.out’
注意:使用nohup之后,脚本输出的信息默认都会存储到当前目录下的一个nohup.out日志文件中,后期想要排查脚本的执行情况的话就可以看这个日志文件。

此时如果想要停止这个shell脚本的话就只能使用kill了

标准输出、标准错误输出、和重定向的用法

1
2
标准输出:表示是命令或者程序输出的正常信息
标准错误输出:表示是命令或者程序输出的错误信息
1
2
标准输出可以使用文件描述符1来表示,标准错误输出可以使用文件描述符2来表示
针对标准输出和标准错误输出,可以使用重定向操作将这些输出信息保存到文件中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
演示一下重定向 >,这里的1表示把标准输出重定向到文件中
[root@bigdata01 shell]# ll 1> a.txt
[root@bigdata01 shell]# more a.txt
total 52
-rw-r--r--. 1 root root 0 Apr 3 21:39 a.txt
-rw-r--r--. 1 root root 48 Apr 3 17:32 for1.sh
-rw-r--r--. 1 root root 43 Apr 3 17:40 for2.sh
-rwxr--r--. 1 root root 45 Apr 2 16:11 hello.sh
-rw-r--r--. 1 root root 121 Apr 3 18:30 if1.sh
-rw-r--r--. 1 root root 147 Apr 3 18:30 if2.sh
-rw-r--r--. 1 root root 227 Apr 3 18:34 if3.sh
-rw-r--r--. 1 root root 44 Apr 3 16:23 location.sh
-rw-------. 1 root root 4692 Apr 3 21:11 nohup.out
-rw-r--r--. 1 root root 20 Apr 3 16:48 paramnum.sh
-rw-r--r--. 1 root root 56 Apr 3 17:59 while1.sh
-rw-r--r--. 1 root root 55 Apr 3 18:01 while2.sh
-rw-r--r--. 1 root root 61 Apr 3 18:03 while3.sh
1
重复执行此命令会发现文件内的内容没有变化,这是因为 > 会覆盖掉之前的内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
如果想要追加的话需要使用 >>

[root@bigdata01 shell]# ll 1>> a.txt
[root@bigdata01 shell]# more a.txt
total 52
-rw-r--r--. 1 root root 0 Apr 3 21:39 a.txt
-rw-r--r--. 1 root root 48 Apr 3 17:32 for1.sh
-rw-r--r--. 1 root root 43 Apr 3 17:40 for2.sh
-rwxr--r--. 1 root root 45 Apr 2 16:11 hello.sh
-rw-r--r--. 1 root root 121 Apr 3 18:30 if1.sh
-rw-r--r--. 1 root root 147 Apr 3 18:30 if2.sh
-rw-r--r--. 1 root root 227 Apr 3 18:34 if3.sh
-rw-r--r--. 1 root root 44 Apr 3 16:23 location.sh
-rw-------. 1 root root 4692 Apr 3 21:11 nohup.out
-rw-r--r--. 1 root root 20 Apr 3 16:48 paramnum.sh
-rw-r--r--. 1 root root 56 Apr 3 17:59 while1.sh
-rw-r--r--. 1 root root 55 Apr 3 18:01 while2.sh
-rw-r--r--. 1 root root 61 Apr 3 18:03 while3.sh
total 56
-rw-r--r--. 1 root root 671 Apr 3 21:39 a.txt
-rw-r--r--. 1 root root 48 Apr 3 17:32 for1.sh
-rw-r--r--. 1 root root 43 Apr 3 17:40 for2.sh
-rwxr--r--. 1 root root 45 Apr 2 16:11 hello.sh
-rw-r--r--. 1 root root 121 Apr 3 18:30 if1.sh
-rw-r--r--. 1 root root 147 Apr 3 18:30 if2.sh
-rw-r--r--. 1 root root 227 Apr 3 18:34 if3.sh
-rw-r--r--. 1 root root 44 Apr 3 16:23 location.sh
-rw-------. 1 root root 4692 Apr 3 21:11 nohup.out
-rw-r--r--. 1 root root 20 Apr 3 16:48 paramnum.sh
-rw-r--r--. 1 root root 56 Apr 3 17:59 while1.sh
-rw-r--r--. 1 root root 55 Apr 3 18:01 while2.sh
-rw-r--r--. 1 root root 61 Apr 3 18:03 while3.sh
1
注意,这里的1可以省略,因为默认情况下不写也是1
1
2
3
4
5
6
7
8
9
10
11
标准错误输出的用法和这个一样,标准错误输出需要使用2,使用1是无法把这个错误输出信息重定向到文件中的

下面这个写法是错误的。

[root@bigdata01 shell]# lk 1> b.txt
-bash: lk: command not found
正确的写法是这样的。

[root@bigdata01 shell]# lk 2> b.txt
[root@bigdata01 shell]# more b.txt
-bash: lk: command not found
1
#注意 1和2与>之间不能有空格
1
2
3
4
5
6
7
8
9
最后来看一个综合案例
nohup hello.sh >/dev/null 2>&1 &

我们来解释一下
nohup和&:可以让程序一直在后台运行
/dev/null:是linux中的黑洞,任何数据扔进去都找不到了
>/dev/null:把标准输出重定向到黑洞中,表示脚本的输出信息不需要存储
2>&1 :表示是把标准错误输出重定向到标准输出中
最终这条命令的意思就是把脚本放在后台一直运行,并且把脚本的所有输出都扔到黑洞里面

Linux中的定时器crontab

1
2
3
4
5
6
7
8
9
10
11
crontab的格式是这样的:* * * * * user-name command

*:分钟(0-59)
*:小时(0-23)
*:一个月中的第几天(1-31)
*:月份(1-12)
*:星期几(0-6) (星期天为0)
user-name:用户名,用哪个用户执行
command:具体需要指定的命令

这条配置需要添加到crontab服务对应的文件中,在配置之前,需要先确认crontab的服务是否正常
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
查看crontab服务状态:systemctl status crond
如果服务没有启动可以使用systemctl start crond 来启动
如果想要停止 可以使用systemctl stop crond

确认这个服务是ok的之后,我们就可以操作这个服务对应的配置文件了,/etc/crontab
可以先打开看一下这个配置文件
[root@bigdata01 shell]# vi /etc/crontab

SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root

# For details see man 4 crontabs

# Example of job definition:
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# | | | | |
# * * * * * user-name command to be executed
1
2
3
4
5
6
7
8
9
10
下面我们就来配置一个。
假设我们有一个需求,每隔1分钟打印一次当前时间,时间格式为年月日 时分秒
这个需求需要写到脚本中,然后在crontab中直接调用脚本即可。
其实我们只需要在脚本中实现打印当前时间的操作即可,每隔1分钟执行一次这个操作让crontab实现即可

创建脚本文件 vi showTime.sh
[root@bigdata01 shell]# vi showTime.sh
#!/bin/bash
showTime=`date "+%Y-%m-%d %H:%M:%S"` #有空格所以要加引号
echo $showTime
1
2
3
4
5
6
7
8
然后在/etc/crontab文件中配置
每1分钟执行一次,其实是最简单的写法,前面都是*号就行,表示都匹配
最终的效果就是这样的

* * * * * root sh /root/shell/showTime.sh


注意:这里建议指定脚本的全路径,这样不容易出问题,还有就是执行命令在这里写好了以后建议拿出来单独执行一下,确认能不能正常执行,这样可以避免出现一些低级别的问题
1
2
3
4
5
6
7
8
9
10
11
12
13
现在这种情况脚本执行之后的结果我们是没有保存的,如果让crontab定时去调度执行,我们压根就看不到执行的结果信息,所以需要把脚本执行的结果重定向到一个文件中,

需要使用追加重定向

* * * * * root sh /root/shell/showTime.sh >> /root/shell/showTime.log

保存配置文件即可,等待执行。
我们来看查看一下结果文件,确认一下是否正常执行,可以使用tail -f 监控一会
[root@bigdata01 shell]# tail -f /root/shell/showTime.log
2026-04-06 21:14:01
2026-04-06 21:15:01
2026-04-06 21:16:01
......
1
2
3
4
5
6
7
8
9
10
11
如果我们执行的脚本确实不会产生任何输出信息,那么我们如何确认脚本是否被成功调度了呢?
这个时候可以通过查看crontab的日志来确认
crontab的日志在/var/log/cron文件中,使用tail -f命令实时监控

[root@bigdata01 shell]# tail -f /var/log/cron
.........
Apr 6 21:14:01 bigdata01 CROND[1577]: (root) CMD (sh /root/shell/showTime.sh >> /root/shell/showTime.log)
Apr 6 21:15:01 bigdata01 CROND[1584]: (root) CMD (sh /root/shell/showTime.sh >> /root/shell/showTime.log)
Apr 6 21:16:01 bigdata01 CROND[1591]: (root) CMD (sh /root/shell/showTime.sh >> /root/shell/showTime.log)
Apr 6 21:17:01 bigdata01 CROND[1597]: (root) CMD (sh /root/shell/showTime.sh >> /root/shell/showTime.log)
Apr 6 21:18:01 bigdata01 CROND[1603]: (root) CMD (sh /root/shell/showTime.sh >> /root/shell/showTime.log)
1
2
3
4
5
6
7
8
9
10
11
如果这个任务暂时不想调度了,想临时停止一段时间,可以修改配置文件,在这一行配置前面加上#号就可以了,这样这一行配置就被注释了,后期想使用的时候把#号去掉就可以了。

下面大家思考一个问题,如果设置任务每7分钟执行一次,那么任务分别会在什么时间点执行?
任务会在我们配置好之后7分钟执行吗? 不会的,
注意了,crontab中任务是这样执行的,我们这里设置的7分钟执行一次,那么就会在每个小时的第0、7、14、21、28.....分钟执行,而不是根据你配置好的时候往后推,这个一定要注意了

我们来验证一下,修改配置文件

*/7 * * * * root sh /root/shell/showTime.sh >> /root/shell/showTime.log

还有就是这里的间隔时间是7分钟,7分钟无法被60整除,那执行到这个小时的最后一次以后会怎么办呢?它最后会在第56分钟执行一次,再往后的话继续往后面顺延7分钟吗?不是的,下一次执行就是下一个小时的0分开始执行了,所以针对这种除不尽的到下一小时就开始重新计算了,不累计。

crontab运维必会面试题


本文标题:大数据开发工程师-第一周 第4章 Linux试炼之配置与shell实战

文章作者:TTYONG

发布时间:2022年01月28日 - 11:01

最后更新:2023年03月15日 - 12:03

原始链接:http://tianyong.fun/%E5%A4%A7%E6%95%B0%E6%8D%AE%E5%BC%80%E5%8F%91%E5%B7%A5%E7%A8%8B%E5%B8%88-%E7%AC%AC%E4%B8%80%E5%91%A8%20%E7%AC%AC4%E7%AB%A0%20Linux%E8%AF%95%E7%82%BC%E4%B9%8B%E9%85%8D%E7%BD%AE%E4%B8%8Eshell%E5%AE%9E%E6%88%98.html

许可协议: 转载请保留原文链接及作者。

多少都是爱
0%