龙空技术网

Linux之shell编程

bcdDG 225

前言:

此时我们对“c语言shell程序”都比较关注,姐妹们都需要学习一些“c语言shell程序”的相关资讯。那么小编在网摘上收集了一些关于“c语言shell程序””的相关文章,希望各位老铁们能喜欢,咱们快快来学习一下吧!

什么是shell

shell是用户与linux系统沟通的一个桥梁,用户想让Linux系统去做什么事情,就通过这个shell去执行对应的操作就行了。

shell编程是把之前在shell中执行的单个命令按照一定的逻辑和规则,组装到一个文件中,后面执行的时候就可以直接执行这个文件了,这个文件称之为shell脚本。

所以shell编程,就是要开发一个shell脚本。

第一个shell脚本

shell脚本的后缀倒没有那么严格的要求,只是建议以.sh结尾,这是一个约定,后期只要看到.sh结尾的文件就知道这个是shell脚本了。 脚本内部如何编写 shell脚本的第一行内容是: #!/bin/bash 这句话相当于是一个导包语句,将shell的执行环境引入进去了。 注意了,第一行的#号可不是注释,其它行的#号才是注释

创建第一个shell脚本,首先创建一个新目录存放shell脚本

[root@namenode ~]# mkdir shell[root@namenode ~]# cd shell/[root@namenode shell]#                                                                                                 [root@namenode shell]# vi hello.sh#!/bin/bash                                                                                                                 

下面就可以写shell命令了 先来一个hello world把,在这里加一个注释

[root@namenode shell]# vi hello.sh#!/bin/bash# first commandecho hello world!                                                                                                                        

保存文件,这样第一个shell脚本就写好了

执行shell脚本

下面 来执行一下这个shell脚本 执行shell脚本的标准写法 bash hello.sh bash:是shell的执行程序,然后在后面指定脚本名称

[root@namenode shell]# bash hello.sh hello world!                                                                                                                          

还有一种写法是sh hello.sh 这里不管是bash 还是sh 都是一样的, 可以来验证一下 bash对应的是/bin目录下面的bash文件

[root@namenode shell]# ll /bin/bash-rwxr-xr-x. 1 root root 964600 Aug  8  2019 /bin/bash                                                                                                        

sh是一个链接文件,指向的也是/bin目录下面的bash文件

[root@namenode shell]# ll /bin/shlrwxrwxrwx. 1 root root 4 Mar 28 20:54 /bin/sh -> bash                                                                                                                   

bash和sh在之前对应的是两种类型的shell,不过后来统一了, 在这也就不区分了,所以在shell脚本中的第一行引入/bin/bash,或者/bin/sh都是一样的。

注意了, 在看其它资料的时候,资料中一般都会说需要先给脚本添加执行权限,然后才能执行,为什么 在这里没有给脚本增加执行权限就能执行呢? 在这里可以看到这个脚本确实只有读写权限

[root@namenode shell]# lltotal 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

[root@namenode shell]# chmod u+x hello.sh [root@namenode shell]# lltotal 4-rwxr--r--. 1 root root 45 Apr  2 16:11 hello.sh                                                                                                      

添加完执行权限之后,再执行的时候就可以使用简化形式了 ./hello.sh 这里的.表示是当前目录,表示在当前目录下执行这个脚本

[root@namenode shell]# ./hello.sh hello world!                                                   

这里指定全路径也可以执行

[root@namenode shell]# /root/shell/hello.sh hello world!                                                                                                                             

能不能再简化一下,前面不要带任何路径信息呢?

[root@namenode shell]# hello.sh-bash: hello.sh: command not found                                                                                                            

这样直接执行却提示命令没找到?有没有感到疑惑? 在看一些其它资料或视频的时候应该看到过这样直接指定脚本执行也是可以的, 现在已经cd到这个文件所在的目录里面了,按理说是可以找到,那为什么会提示找不到呢?

注意了,在这 就详细分析一下,避免 在使用的时候一知半解,迷迷糊糊 主要原因是这样的,因为在这里 直接指定的文件名称,前面没有带任何路径信息,那么按照linux的查找规则,它会到PATH这个环境变量中指定的路径里面查找,这个时候PATH环境变量中都有哪些路径呢, 来看一下

[root@namenode shell]# echo $PATH/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin                                                                                                                                

所以说到这些路径里面去找肯定是找不到的,在这里 只需要在PATH中加一个.即可,.表示当前目录,这样在执行的时候会自动到当前目录查找。

下面 来修改一下这个PATH环境变量, 注意,在这 先直接修改,后面会详细讲解环境变量的相关内容 打开/etc/profile文件,在最后一行添加export PATH=.:$PATH,保存文件即可

[root@namenode shell]# vi /etc/profile......................export PATH=.:$PATH                                                                                                                          

然后执行source /etc/profile 重新加载环境变量配置文件,这样才会立刻生效

[root@namenode shell]# source /etc/profile                                                                                                         

此时再查看PATH变量的值,会发现里面包含了.

[root@namenode shell]# echo $PATH         .:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin                                                                                                                                

再重新执行 hello.sh ok 成功

[root@namenode shell]# hello.sh           hello world!                                                                             

最后再讲一个小命令,shell脚本的单步执行,可以方便脚本调试

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

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

shell中的变量

shell中的变量不需要声明,初始化也不需要指定类型,shell是一门弱类型的语言,JAVA则是强类型的语言,需要提前声明变量,并且指定变量类型。

shell中变量的命名要求: 只能使用数字、字母和下划线,且不能以数字开头

变量赋值是通过"="进行赋值,在变量、等号和值之间不能出现空格!

下面 来创建一些变量,执行之后提示-bash: name: command not found的都表示是错误的,执行成功的话是没有任何输出的,没有反馈就是最好的结果

[root@namenode shell]# name=zs[root@namenode shell]# name =zs-bash: name: command not found[root@namenode shell]# name= zs -bash: zs: command not found[root@namenode shell]# name2_=zs[root@namenode shell]# 2name_=zs-bash: 2name_=zs: command not found[root@namenode shell]# name2$=zs-bash: name2$=zs: command not found                                                                                                                            

打印变量的值,通过echo命令

[root@namenode shell]# echo $namezs[root@namenode shell]# echo ${name}zs                                                                                                                           

这两种形式都可以,一个是完整写法,一个是简化写法,

如果 想在变量的结果后面直接无缝拼接其它字符串,那就只能使用带花括号的形式

[root@namenode shell]# echo $namehehe[root@namenode shell]# echo ${name}hehezshehe                                                                                                                           

如果带空格的话就无所谓了

[root@namenode shell]# echo $name hehe zs hehe                                                   
变量的分类

shell中的变量可以分为四种,

本地变量环境变量位置变量特殊变量本地变量

本地变量的格式是VAR_NAME=VALUE, 就是 刚才在shell中那样直接定义的变量,这种变量一般用于在shell脚本中定义一些临时变量,只对当前shell进程有效,关闭shell进程之后就消失了,对当前shell进程的子进程和其它shell进程无效, 注意了, 在这开启一个shell的命令行窗口 就是开启了一个shell进程 克隆一个会话, 在这两个shell进程中执行echo $name 会发现在克隆的shell进程中获取不到name的值,表示本地变量对其它shell进程无效,

那这里面的对当前shell进程的子进程无效是怎么回事呢?

先执行pstree命令查看一下当前的进程树信息,但是会发现提示命名找不到

[root@namenode shell]# pstree-bash: pstree: command not found                                                                                                                                  

不要着急,找不到说明没有安装这个命令,只需要安装即可,在这里 可以使用yum快速在线安装,那

那 就使用yum在线安装一下

[root@namenode shell]# yum install -y psmiscLoaded plugins: fastestmirrorLoading mirror speeds from cached hostfile * base: mirrors.cn99.com * extras: mirrors.cn99.com * updates: mirrors.nju.edu.cnbase                                                    | 3.6 kB     00:00     extras                                                  | 2.9 kB     00:00     updates                                                 | 2.9 kB     00:00     Resolving Dependencies--> Running transaction check---> Package psmisc.x86_64 0:22.20-16.el7 will be installed--> Finished Dependency ResolutionDependencies Resolved=============================================================================== Package          Arch             Version                Repository      Size===============================================================================Installing: psmisc           x86_64           22.20-16.el7           base           141 kTransaction Summary===============================================================================Install  1 PackageTotal download size: 141 kInstalled size: 475 kDownloading packages:psmisc-22.20-16.el7.x86_64.rpm                            | 141 kB   00:00     Running transaction checkRunning transaction testTransaction test succeededRunning transaction  Installing : psmisc-22.20-16.el7.x86_64                                  1/1   Verifying  : psmisc-22.20-16.el7.x86_64                                  1/1 Installed:  psmisc.x86_64 0:22.20-16.el7                                                 Complete!                                                                                                      

再执行pstree

[root@namenode shell]# pstreesystemd─┬─NetworkManager───2*[{NetworkManager}]        ├─VGAuthService        ├─agetty        ├─anacron        ├─auditd───{auditd}        ├─crond        ├─dbus-daemon───{dbus-daemon}        ├─lvmetad        ├─master─┬─pickup        │        └─qmgr        ├─polkitd───6*[{polkitd}]        ├─rsyslogd───2*[{rsyslogd}]        ├─sshd─┬─sshd───bash        │      └─sshd───bash───pstree        ├─systemd-journal        ├─systemd-logind        ├─systemd-udevd        ├─tuned───4*[{tuned}]        └─vmtoolsd───{vmtoolsd}                                                                                

接下来 来进入这个shell的子进程中,如何进入呢?很简单,直接执行bash即可

[root@namenode shell]# bash                                                                                                                  

然后再打印name变量的值,发现也是获取不到

[root@namenode shell]# echo $name                                                                                                                   

此时再执行pstree,验证一下当前所在的shell进程是否是之前shell的子进程

[root@namenode shell]# pstreesystemd─┬─NetworkManager───2*[{NetworkManager}]        ├─VGAuthService        ├─agetty        ├─auditd───{auditd}        ├─crond        ├─dbus-daemon───{dbus-daemon}        ├─lvmetad        ├─master─┬─pickup        │        └─qmgr        ├─polkitd───6*[{polkitd}]        ├─rsyslogd───2*[{rsyslogd}]        ├─sshd─┬─sshd───bash        │      └─sshd───bash───bash───pstree        ├─systemd-journal        ├─systemd-logind        ├─systemd-udevd        ├─tuned───4*[{tuned}]        └─vmtoolsd───{vmtoolsd}                                                                                                                          

最后执行exit退出子shell进程。

[root@namenode shell]# exitexit                                                                                                                 

本地变量的生效范围,如果 在一个脚本中定义了一个本地变量,那么这个本地变量就只在当前shell脚本中有效。

环境变量

shell中的环境变量,这里的环境变量类似于windows中的环境变量,例如在windows中设置JAVA_HOME环境变量

它的格式为:export VAR_NAME=VALUE 它的格式是在本地变量格式的基础上添加一个export参数 环境变量的这种格式主要用于设置临时环境变量,当你关闭当前shell进程之后环境变量就消失了,还有就是对子shell进程有效,对其它shell进程无效 注意了,环境变量的生效范围和本地变量是不一样的,环境变量对子shell进程是有效的。

来演示一下

[root@namenode shell]# export age=18[root@namenode shell]# echo $age18                                                                                                                                    [root@namenode shell]# bash[root@namenode shell]# echo $age18                                                                                                                                                                                   

执行exit回退到父shell进程

[root@namenode shell]# exitexit                                        

注意了,在实际工作中 设置环境变量一般都是需要让它永久生效,这种临时的并不适用,设置为永久 是把这个临时的设置添加到指定配置文件中,以后每次开启shell进程的时候,都会去加载那个指定的配置文件中的命令,这样就可以实现永久生效了 在这里 一般添加到/etc/profile文件中,这样可以保证对所有用户都生效

[root@namenode shell]# vi /etc/profile.................................export age=19                                                                                   

添加好了以后执行echo命令获取age的值

[root@namenode shell]# echo $age18                                                  

结果发现age的值是18.并不是 刚才在配置文件中定义的19,那也就意味着刚才的设置没有生效,为什么呢? 因为这个shell进程之前已经开启了,它在开启的时候会默认加载一次/etc/profile中的命令, 现在 想让它重新加载/etc/profile的话需要执行 source /etc/profile

[root@namenode shell]# source  /etc/profile[root@namenode shell]# echo $age           19                                                    

这样就可以立刻生效了,并且后期重新开启新的shell也会生效了, 注意,开启新的shell就不需要再执行source命令了。

用完以后 就把这个age变量去掉,这个是没有意义的,仅供测试时使用 后期 在工作中会在这个配置文件中添加JAVA以及其它大数据框架的环境变量

位置变量

接下来看一下位置变量 在进行shell编程的时候,有时候 想给shell脚本动态的传递一些参数,这个时候就需要用到位置变量,类似于$0 $1 $2这样的,$后面的数字理论上没有什么限制, 它的格式是:location.sh abc xyz

位置变量 相当于java中main函数的args参数,可以在shell脚本中动态获取外部参数

这样就可以根据外部传的参数动态执行不同的业务逻辑了。

创建一个脚本文件,location.sh 在里面打印一下这些位置变量看看到底是什么内容

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

执行脚本sh location.sh abc xyz

[root@namenode shell]# sh location.sh abc xyzlocation.shabcxyz                                                                                                   

结果发现 $0的值是这个脚本的名称 $1 是脚本后面的第一个参数 $2是脚本后面的第二个参数 $3为空,是因为脚本后面就只有两个参数 理论上来说,脚本后面有多少个参数,在脚本中就可以通过$和角标获取对应参数的值。 多个参数中间使用空格分隔。

特殊变量

shell中的特殊变量,针对特殊变量 主要学习下面列出来的两个 第一个特殊变量是$? 它表示是上一条命令的返回状态码,状态码在0~255之间 如果命令执行成功,这个返回状态码是0,如果失败,则是在1~255之间,不同的状态码代表着不同的错误信息,也就是说,正确的道路只有一条,失败的道路有很多。

[root@namenode shell]# lltotal 8-rwxr--r--. 1 root root 45 Apr  2 16:11 hello.sh-rw-r--r--. 1 root root 44 Apr  3 16:23 location.sh[root@namenode shell]# echo $?0[root@namenode shell]# lk-bash: lk: command not found[root@namenode shell]# echo $?127                                                                           

这里的127状态码表示是没有找到命令。 具体的状态码信息也可以在网上查到,搜索[linux $? 状态码]

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

这个状态码在工作中的应用场景是这样的, 有时候会根据上一条命令的执行结果来执行后面不同的业务逻辑

第二个特殊变量是$#,

它表示的是shell脚本所有参数的个数 先创建paramnum.sh

[root@namenode shell]# vi paramnum.sh#!/bin/bashecho $#                                                                                                                                                                                  

然后执行

[root@namenode shell]# sh paramnum.sh a b c3[root@namenode shell]# sh paramnum.sh a b c d4                                                                                                                                 

这个特殊变量的应用场景是这样的,假设 的脚本在运行的时候需要从外面动态获取三个参数,那么在执行脚本之前就需要先判断一下脚本后面有没有指定三个参数,如果就指定了1个参数,那这个脚本就没有必要执行了,直接停止就可以了,参数个数都不够,执行是没有意义的。

变量和引号的特殊使用单引号,’’:单引号不解析变量

[root@namenode shell]# name=jack[root@namenode shell]# echo '$name'$name                                                                                                                                   

双引号,"":双引号解析变量

[root@namenode shell]# name=jack   [root@namenode shell]# echo "$name"jack                                                                                                                                

反引号,在键盘左上角esc下面的那个键,在英文输入法模式下可以打出来

[root@namenode shell]# name=jack   [root@namenode shell]# echo `$name`-bash: jack: command not found                                                                                                              

反引号是执行并引用命令的执行结果,在这里反引号是获取到了name变量的值,然后去执行这个值,结果发现没有找到这个命令

如果 把name的值改为pwd,来看一下效果,这样就会执行pwd,并且把pwd执行的结果打印出来。

[root@namenode shell]# name=pwd[root@namenode shell]# echo `$name`/root/shell                                                                                                          

反引号还有另一种写法,$() 他们的效果一致,

[root@namenode shell]# echo $($name)/root/shell                                                                                                                 

要在变量的值外面套一层引号,该怎么写呢? echo "$name"是不行的,最终的值是不带引号的

[root@namenode shell]# echo "$name"pwd                                                                                                           

那我在外面套一层单引号呢?这样虽然值里面带双引号了,但是这个变量却没有解析

[root@namenode shell]# echo '"$name"'  "$name"                                                                                                              

先套一个单引号,再套一个双引号,这样就可以了。

[root@namenode shell]# echo "'$name'"'pwd'                                                                                                                                

什么时候需要在结果里面带引号呢?在脚本中动态拼接sql的时候会用到。

shell中的循环和判断for循环

shell中for循环的格式特点 第一种格式:和java中的for循环格式有点类似,但是也不一样

for((i=0;i<10;i++))do循环体...done                                                                                                                      

来演示一下,先创建for1.sh

[root@namenode shell]# vi for1.sh#!/bin/bashfor((i=0;i<10;i++))doecho $idone                                                                                                            

注意了,这里的do也可以和for写在一行,只是需要加一个分号;

[root@namenode shell]# vi for1.sh#!/bin/bashfor((i=0;i<10;i++));doecho $idone                                                                                                               

执行看结果

[root@namenode shell]# sh for1.sh 0123456789                                                                                                         

这一种格式适合用在迭代多次,步长一致的情况

第二种格式,这种格式针对没有规律的列表,或者是有限的几种情况进行迭代是比较方便的

for i in 1 2 3do循环体...done                                                                                                             

演示一下,

[root@namenode shell]# vi for2.sh#!/bin/bashfor i in 1 2 3doecho $idone                                                                                                               

执行,看结果

[root@namenode shell]# sh for2.sh 123                                                                                                            
while循环

while循环主要适用于循环次数未知,或不便于使用for直接生成较大列表时 while循环的格式为:

while 测试条件do循环体...done                                                                                                      

注意这里面的测试条件,测试条件为"真",则进入循环,测试条件为"假",则退出循环

测试条件支持两种格式 test EXPR 或者 [ EXPR ] ,第二种形式里面中括号和表达式之间的空格不能少 这个EXPR表达式里面写的就是具体的比较逻辑,shell中的比较有一些不同之处,针对整型数据和字符串数据是不一样的

整型测试:-gt(大于)、-lt(小于)、-ge(大于等于)、-le(小于等于)、-eq(等于)、-ne(不等于) 针对整型数据,需要使用-gt、-lt这样的写法,而不是大于号或小于号,这个需要注意一下

还有就是字符串数据,如果判断两个字符串相等,使用=号,这里的=号不是赋值的意思,

不等于就使用!=就可以了 字符串测试:=(等于)、!=(不等于)

下面来演示一下,创建 while1.sh,注意,这里面需要使用sleep实现休眠操作,否则程序会一直连续的打印内容

[root@namenode shell]# vi while1.sh#!/bin/bashwhile test 2 -gt 1doecho yessleep 1done                                                                                  

执行脚本,按ctrl+c可强制退出程序

[root@namenode shell]# sh while1.sh yesyesyes...                                                                                   

把测试条件修改一下,再执行就不会打印任何内容了,因为测试条件为false

[root@namenode shell]# vi while1.sh #!/bin/bashwhile test 2 -lt 1doecho yessleep 1done[root@namenode shell]# sh while1.sh                                                                                                                      

使用中括号看起来比较清晰 只是这种一定要注意,中括号和里面的表达式之间一定要有空格,否则就报错

[root@namenode shell]# cp while1.sh  while2.sh  [root@namenode shell]# vi while2.sh #!/bin/bashwhile [ 2 -gt 1 ]doecho yessleep 1done[root@namenode shell]# sh while2.sh yesyesyes...                                                                                  

针对字符串的测试

[root@namenode shell]# cp while2.sh  while3.sh[root@namenode shell]# vi while3.sh #!/bin/bashwhile [ "abc" = "abc" ]doecho yessleep 1done[root@namenode shell]# sh while3.sh yesyesyes...                                                                                            
if判断

if逻辑判断

if判断分为三种形式

单分支双分支多分支

单分支 先看一下单分支,它的格式是这样的

if 测试条件then    选择分支fi                                                                                                                                                                            

这里面也用到了测试条件,所以和while中的一致 来演示一下,创建 if1.sh 在这里面 可以动态获取一个参数,在测试条件中动态判断

[root@namenode shell]# vi if1.sh #!/bin/bashflag=$1if [ $flag -eq 1 ]thenecho onefi                                                                                                       

执行脚本

[root@namenode shell]# sh if1.sh 1one[root@namenode shell]# sh if1.shif1.sh: line 3: [: -eq: unary operator expected                                                                                                              

在这里发现,如果脚本后面没有传参数的话,执行程序会抱错,错误信息看起来也不优雅,这说明 的程序不够健壮,所以可以进行优化 先判断脚本后面参数的个数,如果参数个数不够,直接退出就行,在这里使用exit可以退出程序,并且可以在程序后面返回一个状态码,这个状态码 就是 之前使用$?获取到的状态码,如果这个程序不传任何参数,就会执行exit 100,结束程序,并且返回状态码100,如下

[root@namenode shell]# vi if1.sh #!/bin/bashif [ $# -lt 1 ]thenecho "not found param"exit 100fiflag=$1if [ $flag -eq 1 ]thenecho "one"fi[root@namenode shell]# sh if1.sh not found param[root@namenode shell]# echo $?100                                     

针对这个脚本,按照正常的执行逻辑是这样的,如果传递的参数不匹配,则没有任何输出

[root@namenode shell]# sh if1.sh 1one[root@namenode shell]# sh if1.sh 2                                                                                                                

这样也不太友好,能不能在执行错误的数据时提示用户呢?

当然可以,这样就需要使用到if的双分支了 格式如下:

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

复制一个脚本,进行修改

[root@namenode shell]# cp if1.sh  if2.sh[root@namenode shell]# vi if2.sh #!/bin/bashif [ $# -lt 1 ]then  echo "not found param"  exit 100fiflag=$1if [ $flag -eq 1 ]then  echo "one"else  echo "not support"fi                                                

执行脚本

[root@namenode shell]# sh if2.sh 1one[root@namenode shell]# sh if2.sh 2not support                                                                                                                

现在只支持针对数字1的翻译,如果想多支持几个数字的翻译呢? 这样就需要使用if的多分支条件了 格式如下:

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

复制一个脚本,进行修改

[root@namenode shell]# cp if2.sh  if3.sh[root@namenode shell]# vi if3.sh #!/bin/bashif [ $# -lt 1 ]then  echo "not found param"  exit 100fiflag=$1if [ $flag -eq 1 ]then  echo "one"elif [ $flag -eq 2 ]then  echo "two"elif [ $flag -eq 3 ]then  echo "three"else  echo "not support"fi                                                                                                                 

执行脚本

[root@namenode shell]# sh if3.sh 1one[root@namenode shell]# sh if3.sh 2two[root@namenode shell]# sh if3.sh 3three[root@namenode shell]# sh if3.sh 4not support                                                                                                                  
Linux中的定时器crontab

想象一个场景,每天凌晨1点登录服务器执行一个数据处理的脚本, 这个事情完全没有必要让 人工去做,针对这种周期性需要被执行的命令完全可以选择使用定时器定时调度执行。

crontab类似于java中的timer定时器的 它可以作用于周期性被执行的命令:

crontab在使用只需要配置一条命令即可,连代码都不需要写 crontab的格式是这样的:* * * * * user-name command

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

这条配置需要添加到crontab服务对应的文件中,在配置之前,需要先确认crontab的服务是否正常 查看crontab服务状态:systemctl status crond

[root@namenode shell]# systemctl status crond● crond.service - Command Scheduler   Loaded: loaded (/usr/lib/systemd/system/crond.service; enabled; vendor preset: enabled)   Active: active (running) since Fri 2020-04-03 22:16:18 CST; 1min 53s ago Main PID: 3583 (crond)   CGroup: /system.slice/crond.service           └─3583 /usr/sbin/crond -nApr 03 22:16:18 namenode systemd[1]: Started Command Scheduler.Apr 03 22:16:18 namenode crond[3583]: (CRON) INFO (RANDOM_DELAY will be sc...)Apr 03 22:16:18 namenode crond[3583]: (CRON) INFO (running with inotify su...)Apr 03 22:16:18 namenode crond[3583]: (CRON) INFO (@reboot jobs will be ru...)Hint: Some lines were ellipsized, use -l to show in full.                                                                                                                                      

看到里面的active说明这个服务是启动的,如果服务没有启动可以使用systemctl start crond 来启动,如果想要停止 可以使用systemctl stop crond

确认这个服务是正掌上的, 就可以操作这个服务对应的配置文件了,/etc/crontab 可以先打开看一下这个配置文件

[root@namenode shell]# vi /etc/crontab          SHELL=/bin/bashPATH=/sbin:/bin:/usr/sbin:/usr/binMAILTO=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                                                                                                                 

从这个配置文件里面 也可以看到 前面分析的crontab的格式

下面 就来配置一个。 假设 有一个需求,每隔1分钟打印一次当前时间,时间格式为年月日 时分秒 这个需求需要写到脚本中,然后在crontab中直接调用脚本即可。 只需要在脚本中实现打印当前时间的操作即可,每隔1分钟执行一次这个操作让crontab实现即可 创建脚本文件 vi showTime.sh

[root@namenode shell]# vi showTime.sh #!/bin/bashshowTime=`date "+%Y-%m-%d %H:%M:%S"`echo $showTime                                                                                                                   

然后在/etc/crontab文件中配置 每1分钟执行一次, 是最简单的写法,前面都是号就行,表示都匹配 最终的效果就是这样的 ` * * * * root sh /root/shell/showTime.sh` 注意:这里建议指定脚本的全路径,这样不容易出问题,还有就是执行命令在这里写好了以后建议拿出来单独执行一下,确认能不能正常执行,这样可以避免出现一些低级别的问题

[root@namenode ~]# sh /root/shell/showTime.sh2026-04-06 21:07:21                                                                                                              

这样验证脚本可以正常执行以后就可以保存配置文件了,但是还有一个问题 现在这种情况脚本执行之后的结果 是没有保存的,如果让crontab定时去调度执行, 压根就看不到执行的结果信息,所以需要把脚本执行的结果重定向到一个文件中, 需要使用追加重定向 * * * * * root sh /root/shell/showTime.sh >> /root/shell/showTime.log

保存配置文件即可,等待执行。 来看查看一下结果文件,确认一下是否正常执行,可以使用tail -f 监控一会

[root@namenode shell]# tail -f /root/shell/showTime.log 2026-04-06 21:14:012026-04-06 21:15:012026-04-06 21:16:01......                                                            

通过这个文件中的信息可以看出来脚本是每隔1分钟被调度一次。 注意了,这里所说的每1分钟执行一次, 会在每1分钟的第1秒开始执行

如果 执行的脚本确实不会产生任何输出信息,那么 如何确认脚本是否被成功调度了呢? 这个时候可以通过查看crontab的日志来确认 crontab的日志在/var/log/cron文件中,使用tail -f命令实时监控

[root@namenode shell]# tail -f /var/log/cron.........Apr  6 21:14:01 namenode CROND[1577]: (root) CMD (sh /root/shell/showTime.sh >> /root/shell/showTime.log)Apr  6 21:15:01 namenode CROND[1584]: (root) CMD (sh /root/shell/showTime.sh >> /root/shell/showTime.log)Apr  6 21:16:01 namenode CROND[1591]: (root) CMD (sh /root/shell/showTime.sh >> /root/shell/showTime.log)Apr  6 21:17:01 namenode CROND[1597]: (root) CMD (sh /root/shell/showTime.sh >> /root/shell/showTime.log)Apr  6 21:18:01 namenode CROND[1603]: (root) CMD (sh /root/shell/showTime.sh >> /root/shell/showTime.log)                                                                                                                                            

查看这个日志文件的内容可以发现 添加的定时任务确实被成功调度了,每调度一次都会记录一条日志数据,便于 后期排查问题。

这样就成功完成了 的第一个定时任务,如果这个任务暂时不想调度了,想临时停止一段时间,可以修改配置文件,在这一行配置前面加上#号就可以了,这样这一行配置就被注释了,后期想使用的时候把#号去掉就可以了。 #* * * * * root sh /root/shell/showTime.sh >> /root/shell/showTime.log

(1)设置自动上传日志文件

mkdir data{20221201}

mkdir data{20221202}

(2)执行hadoop jar 包程序

hadoop jar

(3)sqoop数据导出操作

标签: #c语言shell程序