shell脚本编写遇到的问题
0 背景
工作中需要修补数据,大概半年的数据;跑数据是scala脚本+python脚本,如果手动补充数据,需要运行180次…
于是,shell脚本搞起来…
1 规划思路
此处省略100字;最后的思路:
首先传日期参数,分为开始+结束;毕竟补充数据是一个费时间的活,跑一天的数据就要很久,180天,不拆分开,要爆炸的
其次是利用循环,每天跑一次scala脚本+python脚本
同时需要传递一些基本参数,比如路径
shell脚本中涉及相关操作
2.0 指定格式!(很重要)
在创建shell脚本文件时,必须在文件的第一行指定要使用的shell.其格式为:
#!/bin/bash
参见<Linux命令行与shell脚本编程大全>11.2节
井号("#")用作注释行
2.1 传参数
sh x.sh 20200601 20200631
是我希望实现的在linux或者git上运行shell脚本的形式;这里的20200601是start_day,20200631是end_day
那么我就需要利用这两个参数作为我的起始终止日期
bash shell会将一些称为位置参数( positional parameter)的特殊变量分配给输入到命令行中的
所有参数.这也包括shell所执行的脚本名称.位置参数变量是标准的数字: $0是程序名, $1是第
一个参数, $2是第二个参数,依次类推,直到第九个参数$9.
参见<Linux命令行与shell脚本编程大全>14.1节
sday=$1
eday=$2
注意这里的sday和eday,是我自己定义的用户变量.
shell脚本还允许在脚本中定义和使用自己的变量.定义变量允许临时存储数
据并在整个脚本中使用,从而使shell脚本看起来更像一个真正的计算机程序.
2.2 print参数
你可能想要添加自己的文本消息来告诉脚本用户脚本正在做什么.
换句话,就是你想打印一下结果,print一下;
可以通过echo命令来实现这一点.如果在echo命令后面加上了一个字符串,该命令就能显示出这个文本字符串.
echo $sday
echo $eday
有同学要问了,这里的$又是啥
2.3赋值
shell脚本中最有用的特性之一就是可以从命令输出中提取信息,并将其赋给变量.把输出赋
给变量之后,就可以随意在脚本中使用了.
$()格式是命令替换的一种,允许你将shell命令的输出赋给变量.
以上参见<Linux命令行与shell脚本编程大全> 11.4节
这里已经实现了基本功能
#!/bin/sh
#每天调度IO13接口
#sh x.sh 20200601, 20200631;需要按照月份来调度
sday=$1
eday=$2
echo $sday
echo $eday
jar_path="XXX"
2.4循环
shell脚本也具备结构化命令,比如 if&else,for,while 循环等,逻辑完全一样
这里使用for循环
bash shell中for命令的基本格式.
for var in list
do
commands
done
注意事项
01:commands部分需要缩进
02:在list参数中,你需要提供迭代中要用到的一系列值;比如python里面,for i in range(10); for each in []; for i in "zhangsan"等;
var好说,关键是list.python里面可以充当list的变量是很多的.
目前我了解的,也是从<Linux命令行与shell脚本编程大全>13.1节了解的如下
第一种
for test in Alabama Alaska Arizona Arkansas California Colorado
do
echo The next state is $test
done
这里,直接用a b c的形式,充当list;注意,空格,而不是逗号,充当间隔符号
当然,这里的var也可以用"$var"来书写
第二种
书中还提到了复杂值,比如dont’t know 中的’号等,暂且不提
第三种,变量
list="Alabama Alaska Arizona Arkansas Colorado"
for state in $list
do
echo "Have you ever visited $state?"
done
这种其实也比较常见
第四种,从命令读取值
file="states"
for state in $(cat $file)
do
echo "Visit beautiful $state"
done
用了cat命令来输出文件states的内容;简单的脚本一般用不到
但是这里的都不是我想要的,因为我想传递一个sday和eday,剩下的是range范围,因此需要用其他的方式来循环
第五种,C语言形式
<Linux命令行与shell脚本编程大全>13.2节 C 语言的 for 命令
以下是bash中C语言风格的for循环的基本格式.
for (i = 0; i < 10; i++)
{
printf("The next number is %d\n", i);
}
以下例子是在bash shell程序中使用C语言风格的for命令.
$ cat test8
#!/bin/bash
# testing the C-style for loop
for (( i=1; i <= 10; i++ ))
do
echo "The next number is $i"
done
还可以使用多个变量
#!/bin/bash
# multiple variables
for (( a=1, b=10; a <= 10; a++, b-- ))
do
echo "$a - $b"
done
这里不赘述了
截止这里可以得到
for (( c = $sday; c <= $eday; c++))
do
echo $c
done
2.5 调用spark和python脚本
在shell里面调用python脚本以及传参数,都很简单
python xx.py ${c}
注意这里的{$c}是for循环的c
至于spark-shell调用的scala脚本,因为需要传参数进去,所以麻烦一些
spark-shell --jars xxx.jar -i <( echo 'val mday = "'$c'"'; cat xxx.scala)
参考链接:https://www.bbsmax.com/A/QV5ZjeYw5y/
注意,这里的-i <( echo ‘val mday = "’$c’"’; cat xxx.scala)是需要利用spark-shell运行的内容;
这里首先运行一个echo,从而把想要的参数传进去;这样脚本里面就可以调用这个mday了
如果有同学有其他传参方式,麻烦评论区评论,大家相互学习~
3 未曾设想的bug
3.1 脚本格式问题
linux shell脚本无法执行,报错syntax error near unexpected token ‘$’\r’'解决方法
脚本是在win10+sublime编辑;传到服务器上,运行的时候,报错
脚本检查了没有错误的,为什么会有这个提示呢。
使用vi 命令打开检查下脚本
vi xxx.sh
还是没什么问题呢
这个脚本是从txt文件中粘贴出来的,会不会是格式的问题
于是抱着这个问题查找的态度。我们再次执行下vim命令,不过需要加参数了
vim -b XXX.sh
果然如此,在复制进来后,怎么每行后面都多了"^M"
这里我们来进行快速处理
sed -i 's/\r//g' xxx.sh
就可以了
参考链接https://blog.csdn.net/xzm5708796/article/details/88344074
类似的问题还有Shell脚本$’\r’: command not found问题
3.2 语法错误,syntax error: operand expected
运行的时候,报错语法问题
a.sh: line 12: ((: c = : syntax error: operand expected (error token is "= ")
但是我已经check过了
最后同事告诉我
在开头加上一句
set +o posix
经过查询,是shell脚本的格式要求…
4,最后的脚本
#!/bin/sh
#每天调度IO13接口
#sh x.sh 20200601, 20200631;需要按照月份来调度
set +o posix
sday=$1
eday=$2
echo $sday
echo $eday
jar_path="/target"
for (( c = $sday; c <= $eday; c++))
do
echo $c
spark-shell --jars aaa.jar -i <( echo 'val mday = '$c; cat bbb.scala)
python ccc.py ${c}
sleep 10s
done
完结撒花~
参考
参考书籍:<Linux命令行与shell脚本编程大全>
参考链接:
[1]: https://www.bbsmax.com/A/QV5ZjeYw5y/
[2]: https://blog.csdn.net/xzm5708796/article/details/88344074
[3]: https://mermaidjs.github.io/
[4]: http://adrai.github.io/flowchart.js/