这篇文章主要通过工作中shell脚本案例,介绍shell脚本中常用知识点
下面的这个脚本表示使用sqoop把生产数据库mysql中的商户交易数据导入到hive数据库,且生产数据库中商户交易数据是分库分表存放的(10个库100个表中),分表分库原则根据商户F_merchant_id来分的,比如说一个商户号F_merchant_id='xxxxx855',可以看到商户号是倒数第三位是8,分库的时候会存放到第8个数据库中,最后两位数字是55,所以分表的时候会存放到第55张表中。所以对于商户号xxxxx855的所有交易数据会存放到第8个数据库,第55个表中。
#抽取从2019年1月4号到2019年2月10日的所有商户交易数据
begin_date="20190104" #定义开始时间变量
end_date="20190210" #定义结束时间变量
while [ "$begin_date" -le "$end_date" ] #$begin_date表示参数的引用
do
y=${begin_date:0:4}
m=${begin_date:4:2}
d=${begin_date:6:2}
echo "${y}-${m}"
begin_date=$(date -d "${begin_date}+1days" +%Y%m%d)
y1=${begin_date:0:4}
m1=${begin_date:4:2}
d1=${begin_date:6:2}
for ((db=0;db<=9;db=db+1)) #从0到9,每次加1,共迭代10次 循环10个库
do
for ((j=0;j<=99;j=j+10))
do
querystr=''
for((k=1;k<=10;k++))#一次union 10个表
do
tb1[$k]=$[(${j}+k-1)/10] #相除
tb2[$k]=$[(${j}+k-1)%10] #取余
table[$k]="select F_transaction_id,F_order_id,F_merchant_id from datafrog${db}.t_transaction_operation_by_merchant_${tb1[$k]}${tb2[$k]} where F_time>='${y}-${m}-${d}' AND F_time
if [ $k -gt 1 ]
then
querystr="${querystr} union all ${table[$k]} "
else
querystr="${table[$k]}"
fi
done
#下面的脚本大家不需要看,是为整体效果做的展示
sqoop import \
--connect "jdbc:mysql://192.XXX.XX.XX/datafrog?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&tinyInt1isBit=false" \
--driver com.mysql.jdbc.Driver \
--username datafrog \
--password www.datafrog.com \
--query \
"${querystr}" \
--fields-terminated-by '\t' \
--fetch-size 50000 \
--direct \
--append \
--target-dir /user/hadoop/sqoop/notcm/tran/$y$m$d \
-m 1
done
done
done
1.创建一个shell脚本
linux 系统中打开文本编辑器(可以使用 vi/vim命令来创建文件),新建一个文件 test.sh,扩展名为sh(sh代表shell)。输入一些代码,第一行一般是这样:
如下:
#!/bin/bash
echo "Hello World !"
2.给shell脚本赋权限
一般写好的shell脚本要先赋权限然才能后执行
chmod +x ./test.sh #使脚本具有执行权限
./test.sh #执行脚本
3.shell脚本中while循环使用
while 语句格式
while condition
do
command
done
while循环案例
#!/bin/bash
int=1
while(( $int<=5 ))
do
echo $int
let "int++"
done
运行脚本,输出:
1
2
3
4
5
使用中使用了 Bash let 命令,它用于执行一个或多个表达式,变量计算中不需要加上$来表示变量
4.shell脚本中for 循环使用
for 循环与其他编程语言类似,Shell支持for循环。for循环一般格式为:
for var in item1 item2 ... itemN
do
command1
command2
...
commandN
done
例如,顺序输出当前列表中的数字:
for loop in 1 2 3 4 5
do
echo "The value is: $loop"
done
输出结果:
The value is: 1
The value is: 2
The value is: 3
The value is: 4
The value is: 5
5.Shell脚本中字符串的拼接
如果想要在字符串变量后面拼接一个字符,可以用下面的方法:
value1=home
value2=${value1}"=" # 或者$value2=${value1}=
echo $value2
把要添加的字符串变量添加{}中,并且需要把$放到外面,上面的结果是:home=
还可以如下面的
[root@localhost sh]# var1=/etc/
[root@localhost sh]# var2=yum.repos.d/
[root@localhost sh]# var3=${var1}${var2}
[root@localhost sh]# echo $var3
/etc/yum.repos.d/
6.shell脚本中的关系运算符
-eq:等于 equal
-ne:不等于 not equal
-le:小于等于 less equal
-ge:大于等于 greater equal
-lt:小于 less than
-gt:大于 greater than
7.shell脚本中获取系统时间的方法
获取今天时期:$(date +%Y%m%d) 或 $(date +%F 或 $(date +%y%m%d)
获取昨天时期:$(date -d yesterday +%Y%m%d)
获取前天日期:$(date -d -2day +%Y%m%d)
获取10天前的日期:$(date -d -10day +%Y%m%d)
n天前的 $(date -d "n days ago" +%y%m%d)
明天:$(date -d tomorrow +%y%m%d)
给定的日期减一天
$(date -d "20150416 -1 days" +%Y%m%d)
给定的日期减去三天
$(date -d "20150416 -3 days" +%Y%m%d)
给定的日期加上三天
date -d "20150416 3 days" "+%Y%m%d"
7.shell脚本中字符串截取
可以使用这样的方法截取,表示从左边第几个字符开始以及字符的个数,用法为:start:len
例如:
str='http://www.
你的域名.com/cut-string.html'
echo ${str:0:5}
输出结果
结果是:http:
其中的 0 表示左边第一个字符开始,5 表示字符的总个数。
8.shell脚本中数组的使用
数组中可以存放多个值。Bash Shell 只支持一维数组(不支持多维数组),初始化时不需要定义数组大小,与大部分编程语言类似,数组元素的下标由0开始。
(1)创建数组
shell数组用括号来表示,元素用"空格"符号分割开,语法格式如下:
array_name=(value1 ... valuen)
实列
#!/bin/bash
my_array=(A B "C" D)
我们也可以使用下标来定义数组:
array_name[0]=value0
array_name[1]=value1
array_name[2]=value2
(2)读取数组
读取数组元素值的一般格式是:
${array_name[index]}
实例
#!/bin/bash
my_array=(A B "C" D)
echo "第一个元素为: ${my_array[0]}"
echo "第二个元素为: ${my_array[1]}"
echo "第三个元素为: ${my_array[2]}"
echo "第四个元素为: ${my_array[3]}"
执行脚本,输出结果如下所示:
$ chmod +x test.sh
$ ./test.sh
第一个元素为: A
第二个元素为: B
第三个元素为: C
第四个元素为: D
9.shell脚本中重定向
针对于上面提到的sqoop抽取数据的脚本,工作中是使用azkaban做任务调度。但是有时候做其他的定时任务也使用crontab做来任务调度
比如下面的数据蛙课程案例,每天定时发送邮件的定时任务
35 8 * * * /root/anaconda3/bin/python3.6 /root/project/datafrog/datafrog_adventure.py >/tmp/load.log 2>&1 #邮件发送by 数据蛙
这个里面就涉及到了shell脚本中的重定向,下面一起看看把
我们先来看下linux命令的执行过程
我们一起来看下,比如说一条linux命令
一开始可能需要给这个命令一个输入值,这个就叫标准输入(Standard input),简写stdin
,其中可以通过键盘或者是文件的形式给命令一个输入
接着就开始执行命令,命令执行成功,就会把成功的结果输出到屏幕上来,这个就叫标准输出(standard output),简写stout
若是命令行执行错误,就会把报错的结果输出到屏幕上来,这个就叫做标准错误(standard error),简写stderr
有时候我们在命令使用时,若不想命令的执行结果输出的屏幕,需要输入输出到制定文件或者设备,就需要使用输入、输出重定向。
先看下输出重定向的例子
#默认情况下,stdout和stderr默认输出到屏幕
[root@st ~]# ls ks.cfg wrongfile
ls: cannot access wrongfile: No such file or directory
ks.cfg
#标准输出重定向到stdout.txt文件中,错误输出默认到屏幕。1>与>等价
[root@st ~]# ls ks.cfg wrongfile >stdout.txt
ls: cannot access wrongfile: No such file or directory
[root@st ~]# cat stdout.txt
ks.cfg
#标准输出重定向到stdout.txt,错误输出到err.txt。也可以使用追加>>模式。
[root@st ~]# ls ks.cfg wrongfile >stdout.txt 2>err.txt
[root@st ~]# cat stdout.txt err.txt
ks.cfg
ls: cannot access wrongfile: No such file or directory
#将错误输出关闭,输出到null。同样也可以将stdout重定向到null或关闭
# &1代表标准输出,&2代表标准错误,&-代表关闭与它绑定的描述符
[root@st ~]# ls ks.cfg wrongfile 2>&-
ks.cfg
[root@st ~]# ls ks.cfg wrongfile 2>/dev/null
ks.cfg
#将错误输出传递给stdout,然后stdout重定向给xx.txt,也可以重定向给null。顺序为stderr的内容先到xx.txt,stdout后到。
[root@st ~]# ls ks.cfg wrongfile >xx.txt 2>&1
#将stdout和stderr重定向到null
[root@st ~]# ls ks.cfg wrongfile &>/dev/null
注意关于2>&1的理解
含义:将标准错误输出重定向到标准输出
符号>&是一个整体,不可分开,分开后就不是上述含义了。比如有些人可能会这么想:2是标准错误输入,1是标准输出,>是重定向符号,那么"将标准错误输出重定向到标准输出"是不是就应该写成"2>1"就行了?是这样吗?如果是尝试过,你就知道2>1的写法其实是将标准错误输出重定向到名为"1"的文件里去了
写成2&>1也是不可以的
输入重定向
#从stdin(键盘)获取数据,然后输出到catfile文件,按Ctrl+d结束
[root@st ~]# cat >catfile
this
is
catfile
[root@st ~]# cat catfile
this
is
catfile
#输入特定字符eof,自动结束stdin
[root@st ~]# cat >catfile <
> this
> is
> catfile
> eof
[root@st ~]# cat catfile
this
is
catfile
如果大家正在学习shell脚本使用的话,不防好好读下sqoop抽取数据的脚本,通过实际的案例学习,成长速度会更快些