小伙伴在《这些年我们一起搞过的持续集成~Jenkins+Perland Shell script》中详细介绍了优化后的job流,接下来总结一下在构建这一套job中遇到的Shell Script和Jenkins的问题。
1. 比较两个文件后有特殊字符< 会导致Jenkins job failure;
解决方法:过滤特殊字符<同时利用diff–b去除最后的错位行,更多diff使用请参考diff--help;
-------------1)
[annzan@vm10226address]$ diff current.txt base.txt
1,2d0
52c50 --- >davima -----------2) [annzan@vm10226address]$ diff -b current.txt base.txt 1,2d0 -------------3) [annzan@vm10226address]$ diff -b current.txt base.txt | grep "<"|sed 's/^/g' annzan wadexu 2. awk按分隔符分段输出,例如 echo $PROJECT_LIST|awk –F “,”‘{print $1}’ 。 将PROJECT_LIST遍历输出,需要参数化输出段数,$$id肯定是不行的; 解决方法: echo $PROJECT_LIST|awk -v id=$id -F”,” ‘{print$id}’ 这边之前也试过cut这个命令去分隔字符串, echo $PROJECT_LIST|cut -f $id -d “,” 但是这里有个问题,当PROJECT_LIST中没有,这个分隔符的时候,不论id是几结果都是本身。所以cut命令无法实现我们想要遍历所有project的初衷,除非强制PROJECT_LIST一定要有一个分隔符。 3. 用curl命令调用下一个job大大提高了我们job流程的灵活机动性,同时用data json将参数值也一起传递到下一个job,实现我们整个流程的参数化。 curl -X POST --user "jadmin:71103407"-s http://vm10686.global.test.net:8080/view/Template/job/Template_Service_Commit_Auto_Build/build --data json='{"parameter":[{"name":"PROJECT_NAME","value":"'$projectName'"},{"name":"PIPELINE_NUM","value":"'$BUILD_NUMBER'"}]}' 注意: value后面双引号里面直接加值,如果是参数的话,需要在参数名外面加单引号。 4. 这里着重讲一下我们遇到的天坑,单引号,双引号再顺便提一下反引号和反斜杠。[转自互联网] 1. 单引号( '' ) 5. 由单双引号引发的血案还有很多,比如下面遇到的中括号,if后面加中括号,注意加空格,可是结果却总是不对: 整了半天发现还是双引号的问题,字符串比较需要把$test放在双引号里,或者在外面再加一个中括号: 6. grep和egrep的使用区别 1) grep [option] pattern filename 注意: pattern如果是表达式或者超过两个单词的, 需要用引号引用. 可以是单引号也可双引号, 区别是单引号无法引用变量而双引号可以. 2) egrep= grep -E 可以使用基本的正则表达外, 还可以用扩展表达式. 注意区别. 具体使用请参考grep –help; egrep -- help 7. 当参数名是参数时,取值用eval。 例如configfile中每个定义两个project的GIT_PROJECT_NAME,用projectname作为前缀: PROA_GIT_PROJECT_NAME=git_proa PROB_GIT_PROJECT_NAME=git_prob 当用project name作为参数时,$($PROJECT_NAME_GIT_PROJECT_NAME)是没有这种写法的,正确取值如下: GIT_PROJECT_NAME=${PROJECT_NAME}"_GIT_PROJECT_NAME" GIT_PROJECT_NAME=$(eval echo\${$GIT_PROJECT_NAME}) 8. 大侠用perl语言写了打包安装等核心功能,需要执行这些脚本前,需要把脚本路径加到path里,要不然有核心代码也执行不了: 1) 把路径添到PATH路径里面 cd ${SCRIPTS_HOME} chmod 755 * export PATH=$PATH:`pwd` 2) 直接修改.bashrc文件 [annzan@vm10876 ~]$ vim .bashrc 文件被打开如下 9. 上面讲到.bashrc文件,就顺便记录一下.bashrc和.bash_profile文件的区别: /etc/profile: 此文件为系统的每个用户设置环境信息,当用户第一次登录时,该文件被执行。并从/etc/profile.d目录的配置文件中搜集shell的设置; 设置生效:可以重启生效,也可以使用命令:source 10. 小数之间的比较用bc, 不是整数比较,不可以简单的用大于小于来比较; if [ $(echo "$code_coverage_integer< $SONAR_MIN_COVERAGE" | bc) ] or if (( $(echo "$code_coverage_integer< $SONAR_MIN_COVERAGE" | bc) )) 注意 : 对于数据比较有以下两种格式: 以下是文件,字符串和算术比较运算符: 11. 换行问题; 1) 字符串换行: mail_body="Hi,${PROJECT_NAME}"" project member"$'\n'"Alerts" 2) echo写入文件换行: echo -e "exportCONFIG_TIME=${CURRENT_TIME}\n exportPROJECT_LIST=${PROJECT_LIST}\n exportSHARED_FOLDER=~/jenkins/common\n" > config.txt 12. 通过git commit hash来判断代码有没有更新,取当前commit hash与base hash对比,有不一样,打包安装,并把当前的commithash放入base文件;同理,取出当前所有的author list,与base list对比,取出代码修改的所有作者。 git log --max-count=1--pretty=format:"%H" > ${CURRENT_MD5_FILE} gitlog --pretty=format:"Author: %an" > ${CURRENT_AUTHOR_LIST} Refer to git log paras: https://www.kernel.org/pub/software/scm/git/docs/git-log.html 13. 从pom.xml 文件中取一指定节点的值: 例如 1)sed -n'/name/{s/.* 2)catpom.xml|sed -n '/name/p'|awk -F "[<>]" '{print $3}' 如果取的值是一个数字,例如 cat pom.xml | sed -n '/ num /p' | sed -r's/([^0-9]*([0-9]*)){1}.*/\2/' 但是当num显示的值为1,000时,就只能取到1 而 不是1,000。所以 还是上面两种方法比较奏效。 14. JSON对象取值,示例如下: JSON 对象: response='{"name"="annzan","value"="test"}' 用如下方法取值: function jsonValue(){ KEY=$1 VALUE=$2 awk -F"[,:}]" '{for(i=1;i<=NF;i++){if($i~/'$KEY'\042/){print $(i+1)}}}' | tr -d '"' | sed -n ${VALUE}p } 如果要取到name里的值annzan,调用jsonValue方法并输入相应的Key值: 15. 在linux系统中,可以使用mount命令挂载光盘镜像文件、移动硬盘、U盘以及Windows网络共享和UNIX NFS网络共享等,这里主要介绍一下Linux系统中NFS文件共享; 1) 首先要看一下需要被挂载盘的文件地址: df /mnt/ifs10001 2)在需要挂载的系统中创建相应文件夹:mkdir /mnt/ifs10001 3)实现挂载共享文件:mount -t nfs isiloncwy0001.transfer.test.net:/ifs/data/transfer/clients /mnt/ifs10001 具体可以参考http://www.jb51.net/os/RedHat/1109.html 16. Jenkins自身设定的按时启动job,时间是有延迟的,比如我设置为下午4点,可是却发现没有动静,后来发现每天都是4点15运行job。而且这个设置的时间是jenkins服务器的时间不是本机时间。设置格式如下: 例如设置每周一到周五,3点钟执行job。设置定时任务: H 3 * * 1-5 17. Jenkins中执行job前大都需要先export 环境变量,我们可以不需要手动写shell 脚本,可以在Jenkins Nodeconfig页面设置Node属性,如下图: 18. 除了在Node端设置环境变量,我们也可以在Jenkins系统设置进行全局设置,例如MAVEN_OPTS或者账号密码, $ENV{USERNAME}即为调用账号; 19. 因为我们现在用Git管理代码库,所以在Jenkins中要checkout代码,需要先设置git账号,把key配置在Jenkins的ManageCredentials中,如下图:
# grep Susan phonebook
Susan Goldberg 403-212-4921
Susan Topple 212-234-2343
如果我们想查找的是SusanGoldberg,不能直接使用grep Susan Goldberg phonebook命令,grep会把Goldberg和phonebook当作需要搜索的文件
# grep 'Susan Gold' phonebook
Susan Goldberg 403-212-4921
当shell碰到第一个单引号时,它忽略掉其后直到右引号的所有特殊字符
2. 双引号( " " )
双引号作用与单引号类似,区别在于它没有那么严格。单引号告诉shell忽略所有特殊字符,而双引号只要求忽略大多数,具体说,括在双引号中的四种特殊字符不被忽略:$,\,`,!,即双引号会解释字符串的特别意思,而单引号直接使用字符串.如果使用双引号将字符串赋给变量并反馈它,实际上与直接反馈变量并无差别。如果要查询包含空格的字符串,经常会用到双引号。
# x=*
# echo $x
hello.sh menus.sh misc.sh phonebook tshift.sh
# echo '$x'
$x
# echo "$x"
*
这个例子可以看出无引号、单引号和双引号之间的区别。在最后一种情况中,双引号告诉shell在引号内照样进行变量名替换,所以shell把$x替换为*,因为双引号中不做文件名替换,所以就把*作为要显示的值传递给echo。对于第一种情况需要进一步说明,shell在给变量赋值时不进行文件名替换(这从第三种情况中也能看出来),各步骤发生的精确次序如下: shell扫描命令行,把x的值设为星号*;
shell再次扫描命令行,碰到星号*,把它替换成当前目录下的文件清单;
shell启动执行echo命令,把文件清单作为参数传递给echo.
这个赋值的先后次序非常重要:shell先作变量替换,然后作文件名替换,最后把这行处理为参数
3. 反引号(``)
命令替换是指shell能够将一个命令的标准输出插在一个命令行中任何位置。shell中有两种方法作命令替换:把shell命令用反引号或者$(...)结构括起来,其中,$(...)格式受到POSIX标准支持,也利于嵌套。
# echo The date and time is `date`
The date and time is 三 6月 15 06:10:35CST 2005
# echo Your current working directory is $(pwd)
Your current working directory is/ home/annzan/test
4. 反斜杠backslash-escaped( \ )
反斜杠一般用作转义字符,或称逃脱字符,linux如果echo要让转义字符发生作用,就要使用-e选项,且转义字符要使用双引号
echo -e "\n"
反斜杠的另一种作用,就是当反斜杠用于一行的最后一个字符时,shell把行尾的反斜杠作为续行,这种结构在分几行输入长命令时经常使用。
扩展表达式:
+ 匹配一个或者多个先前的字符, 至少一个先前字符.
? 匹配0个或者多个先前字符.
a|b|c 匹配a或b或c
() 字符组, 如: love(able|ers) 匹配loveable或lovers.
(..)(..)\1\2 模板匹配. \1代表前面第一个模板, \2代第二个括弧里面的模板.
x{m,n} =x\{m,n\} x的字符数量在m到n个之间.
# .bashrc
# Source global definitions
if [ -f /etc/bashrc ]; then
. /etc/bashrc
fi
# User specific aliases and functions
export PATH=/home/annzan/bin:$PATH
-----增加自己的Path,在已有:$PATH的之前 保存并退出
[annzan@vm10876 ~]$ . .bashrc
.相当于source让修改生效
[annzan@vm10876 bin]$ echo $PATH
/home/annzan/bin:/usr/kerberos/bin:/usr/local/bin:/bin:/usr/bin
/etc/bashrc: 为每一个运行bashshell的用户执行此文件.当bashshell被打开时,该文件被读取;
~/.bash_profile:每个用户都可使用该文件输入专用于自己使用的shell信息,当用户登录时,该文件仅仅执行一次!默认情况下,他设置一些环境变量,执行用户的.bashrc文件;
~/.bashrc:该文件包含专用于你的bashshell的bash信息,当登录时以及每次打开新的shell时,该文件被读取;
~/.bash_logout:当每次退出系统(退出bashshell)时,执行该文件;
另外,/etc/profile中设定的变量(全局)的可以作用于任何用户,而~/.bashrc等中设定的变量(局部)只能继承/etc/profile中的变量,他们是"父子"关系。
~/.bash_profile 是交互式、login方式进入bash 运行的
~/.bashrc 是交互式non-login 方式进入bash 运行的
通常二者设置大致相同,所以通常前者会调用后者。