关于shell:shellshell-脚本快速入门

Shell 脚本编程1. 什么是 shell ?Computers understand the language of zeros and ones known as binary language. In the early days of computing, instructions were provided using binary language, which is difficult for all of us to read and write. Therefore, in an operating system there is a special program called the shell. The shell accepts human readable commands and translates them into something the kernel can read and process.shell 就是将人类可读的指令转换成计算机内核可能辨认并执行的程序。 ...

August 16, 2020 · 4 min · jiezi

关于shell:shell常见命令

cwd=$(dirname `readlink -f $0`)Get the current working directory.

August 11, 2020 · 1 min · jiezi

关于shell:好用的shell通配符

前言咱们在应用 shell 执行工作的过程中,经常会遇到须要解决一批数据的状况,如果咱们一个一个的传递参数就会十分的麻烦,这时候就须要用到 shell 的通配符性能了。例如rm *.txt能够删除当前目录下所有的 txt 文件。 性能shell 通配符起到的是拓展参数的性能,留神 shell 通配符是由 shell 解决的,而不是用到参数的命令或者语句解决的。 例如对于 rm *.txt,shell 在参数遇到通配符的时候,会把这个通配符当做门路或者文件的匹配模式去磁盘上搜寻所有的匹配项。 如果存在匹配,则把所有的匹配项替换到参数去,例如下面的命令最终的模式可能是 rm a.txt b.txt,rm命令拿到的是理论的文件列表,而不是*.txt。 如果不存在匹配或者无奈辨认该模式,则shell会将该通配符作为一个一般字符传递给命令,而后再由命令去解决。例如如果咱们目录下没有任何 txt 文件,执行下面的命令就会报错:no matches found: *.txt 跨目录匹配通配符只能匹配单层目录,如果要跨目录匹配,则要这样子写: rm */*.txt留神,下面的写法只能匹配一级子目录下的 txt 文件,没有方法匹配当前目录以及二级子目录下的文件 如果要匹配当前目录和一级子目录下的txt文件,则要用到多个通配符组合,例如如下命令 ls *{\/*,}.txt留神,以上命令在当前目录或者一级目录之一没有txt文件的时候,也会报错。 通配符shell 通配符看起来很像正则表达式,然而并不是正则表达式,它的性能比正则表达式要弱,只反对上面几种通配符模式。 *匹配 0 或多个字符 ?匹配任意一个字符 []匹配 [] 中的任意繁多字符,例如[abc]匹配a、b、c中的任何一个字符。[]反对范畴匹配,例如 [a-z]匹配所有小写字母。 {,}匹配{}中被,分隔的任意一个子字符串。例如{AA,BB,CC}.txt匹配到 AA.txt、BB.txt和CC.txt,{}也反对范畴匹配,例如{A..Z}匹配所有大写字母 {}和其余通配符不同的中央在于,即便没有匹配到数据,{}仍然会开展。例如 # 如果咱们目录下没有文件A,B,上面的命令会报错:no matches found: [AB]echo [A-B]# 上面的命令则会输入:A Becho {A-B}{}反对嵌套,因而能够组合成简单的模式。例如 echo {a{a..c},b{b..c}}#输入aa ab ac bb bc[!]和[^]匹配除了 [] 中的其余所有字符,也即不匹配[]中的所有字符。 ...

July 28, 2020 · 1 min · jiezi

Shell脚本结合Git实现增量项目部署

小Hub领读:脚本代码这么多,不是运维可能会真不会写哈哈。普通人用jenkins全量挺好的,然而代码过多时候就比拟麻烦,而且jenkins个别也要配合脚本应用更加合乎业务。 作者:CatalpaFlathttps://juejin.im/post/5cf0ed... 利用部署是开发、测试、上线必须面对的一个过程,尤其是微服务架构的呈现,运维部署从单体的部署逐步脱离出,并且越显简单。 然而,抛开多语言,多环境,集群,分布式的部署之外。就单单探讨增量部署和全量部署 1.增量和全量部署部署,除却我的项目初始化部署,最现实的状况即为:新版本更改哪些内容则更新哪些内容 1.1 增量部署1.1.1 增量部署简介增量部署个别指在每次部署过程中首先提取以后版本和行将部署版本之间的增量(包含代码、可执行文件或者配置等),并在部署过程中仅更新增量局部。 1.1.2 常见部署流程利用代码管理工具(SVN、GIT 等)提取两个版本之间的增量,并联合其余方面的增量变动。依照增量局部制订具体的部署形式,编写部署脚本,并筹备增量部署包(包含混同代码等)。散发和部署增量部署包到曾经运行上一版本的指标环境,实现零碎的版本升级。1.1.3 增量部署长处部署速度快。每次只对增量局部进行更新,缩短部署工夫缩小变动量。缩小对整个零碎的变动幅度,有些配置内容是不须要每次都更新迭代的进步安全性。因为每次支队增量进行更新,防止全副代码的泄露1.1.4 增量部署毛病增量部署 若存在其余外在部署环境依赖,则升高部署效率增量部署不像 部署环境多的状况下,对可重复性要求高增量部署对回滚操作变得不敌对1.2 如何抉择增量还是全量现有的自动化部署,大多数都 全量部署,但全量部署也有一些弊病。但能够通过一些策略进行筛选: 提前准全量部署的所有配置和资料(部署包,外在配置文件等)在进行部署,能够提高效率和速度应用灰度公布或负载平衡等办法升高全量部署对利用可用性的影响对于古代零碎中绝大部分状态无关的部署单元(利用、模块,微服务等),全量部署个别应是最优的抉择。而状态相干的部署单元(数据库等)则仍然适宜增量部署逻辑。 2.进入主题后面讲述了一些对于增量和全量部署的状况。接下来讲述如何通过 shell 脚本联合 Git Log 进行增量部署 2.1 前提环境Java 我的项目Maven 进行治理Git 作为代码仓库2.2 shell 脚本shell 老手,写得不够完满,轻喷。 2.2.1 整个 shell 脚本的模块Git 环境筹备Maven 对欲构建我的项目进行编译创立增量部署文件夹检索我的项目 target 目录通过 git diff 检索两次 commit 之间的差别,再通过检索将对应文件拷贝到 “增量文件夹” 中2.2.2 Git 环境筹备# git环境if [[ ! -d ".git" ]]; then ECHO error: please init Git Repository exit 1;fiif [[ ! -z ${branch} ]]; then git checkout ${branch}fi# 获取默认commit-hashif [[ -z "$begin_hash" ]] && [[ -z "$end_hash" ]] ; then for p in $(git log --pretty=oneline -2) ; do if [[ ${#p} -eq 40 ]]; then if [[ -z ${begin_hash} ]]; then begin_hash=${p} else end_hash=${p} break fi fi donefiis_begin_has=false# 是否以后最新commitif [[ $(git log --pretty=oneline -1) == *${begin_hash}* ]]; then is_begin_has=truefi# 非以后最新分支commit,回滚到原始版本,可能过后maven原始配置不反对compile或会呈现构建失败(如:应用本地仓/公有仓库等)if [[ ${is_begin_has} = false ]]; then project_path=$(pwd) project_name=${project_path##*/} cd .. build_project_name=${project_name}_build_temp_project if [[ ! -d ${build_project_name} ]]; then mkdir ${build_project_name} fi \cp -rf ${project_name}/. ${build_project_name} cd ${build_project_name} git reset --hard ${begin_hash}fi复制代码2.2.2.1 校验是否 git 仓库代码if [[ ! -d ".git" ]]; then ECHO error: please init Git Repository exit 1;fi复制代码2.2.2.2 查看是否须要切换分支if [[ ! -z ${branch} ]]; then git checkout ${branch}fi2.2.2.3 是否须要设置默认构建的 commit 值若执行构建时,没给增加 --begin_hash= 和 --end_hash= 进行赋值,则默认应用最新的两次 commit 来进行增量部署。 ...

July 13, 2020 · 3 min · jiezi

bash脚本通过git下拉项目对maven项目进行打包并启动

java我的项目尤其是通过maven打包的我的项目在部署上传的时候通常会遇到 打包->ssh上传->启动的麻烦。然而有时候认为我的项目小或者服务器限度没法做jenkins这类的自动化部署工具,所以就很麻烦。因而联合网上的和本人需要写了一个脚本,以实现在近程服务中只须要通过git来pull下代码后即可运行脚本执行打包部署我的项目工作,不便了很多。 首要工作当然是将我的项目pull进去 git pull其次就是执行脚本借鉴了网上的杀死过程脚本 #! /bin/bash# process-monitor.shprocess=$1ps x | grep $process | grep -v greppid = $(ps x | grep $process | grep -v grep | grep -v 'stop.sh' | awk '{print $1}')echo 敞开过程 $pidkill $pidsleep 5接下来就执行打包部署脚本#! /bin/bashmvn clean pakage -Dmaven.test.skipecho '打包胜利'\cp -rf xxxxxx/src/main/resources/application-* xxxxxx/config\cp -rf xxxxxx/target/XX.jar xxxxxx/xx.jarsh stop.sh xx.jarnohup java -Xmx128m -jar xxxxxx/xx.jar > xxxxxx/xx.log 2>&1 &echo '启动胜利'tail -f xxxxxx/xx.log还是比拟好了解的。玩个坑,看看前面可不可以做一个整合git的脚本而后再看看能不能主动或者定时工作比对git的commitId主动pull去部署

July 10, 2020 · 1 min · jiezi

1分钟系列教程Linux系统Shell脚本编写思路与过程

前段时间有小伙伴问我一些问题,涉及到shell脚本的编写问题,事后,我深入思考了下,实际生产环境的确也会经常用到,因此如何写这个脚本?它的思路在哪?带这个问题引入今天的文章,仅供参考,如有不完善的地方请多指导。 问题一: 编写脚本自动统计访问网站失败的IP地址 问题二: 编写脚本自动统计十分钟内访问网站的IP地址 征对这两个问题,我的解决思路如下: 第一个问题: 1)怎么才算访问网站失败? 大家都知道,我们也会经常打不开一网站,那么访问失败,网站日志肯定会有记录的,因此,可以通过查看日志中的状态码(如200、400、403)来判断用户的访问结果 2)获取IP地址 获取IP地址就很简单了,awk命令就是个不错的选择 第二个问题: 1)统计IP地址 同第一个问题一样,方法有很多,也非常简单 2)如何取得十分钟内的日志 115.59.74.25 - - [27/Feb/2017:22:54:43 +0800] "GET /Home/SaveData/index HTTP/1.0" 404 3537 "-" "-"115.59.74.25 - - [27/Feb/2017:22:54:44 +0800] "GET /Home/SaveData/index HTTP/1.0" 404 3537 "-" "-"通过上面的日志格式,可以看出日志中是带有时间点信息的,那么只需要将时间点信息找到即可解决 3)解决时间点的问题 可以通过awk的命令来获取某段时间内的信息 awk '$4 >="[27/Feb/2017:22:54:43" && $4 <="[27/Feb/2017:22:54:53'27/Feb/2017:22:54:53"' /wwwlogs/access.log**115.59.74.25 - - [27/Feb/2017:22:54:43 +0800] "GET /Home/SaveData/index HTTP/1.0" 404 3537 "-" "-"115.59.74.25 - - [27/Feb/2017:22:54:44 +0800] "GET /Home/SaveData/index HTTP/1.0" 404 3537 "-" "-"115.59.74.25 - - [27/Feb/2017:22:54:45 +0800] "GET /Home/SaveData/index HTTP/1.0" 404 3537 "-" "-"115.59.74.25 - - [27/Feb/2017:22:54:47 +0800] "GET /Home/SaveData/index HTTP/1.0" 404 3537 "-" "-"115.59.74.25 - - [27/Feb/2017:22:54:48 +0800] "GET /Home/SaveData/index HTTP/1.0" 404 3537 "-" "-"115.59.74.25 - - [27/Feb/2017:22:54:49 +0800] "GET /Home/SaveData/index HTTP/1.0" 404 3537 "-" "-"115.59.74.25 - - [27/Feb/2017:22:54:50 +0800] "GET /Home/SaveData/index HTTP/1.0" 404 3537 "-" "-"115.59.74.25 - - [27/Feb/2017:22:54:52 +0800] "GET /Home/SaveData/index HTTP/1.0" 404 3537 "-" "-"115.59.74.25 - - [27/Feb/2017:22:54:53 +0800] "GET /Home/SaveData/index HTTP/1.0" 404 3537 "-" "-"这样就可以将一段时间内的日志信息取出 ...

July 2, 2020 · 2 min · jiezi

在线正则表达式测试

在线正则表达式测试

June 30, 2020 · 1 min · jiezi

shell三种-for循环方式

shell三种 for循环方式

June 18, 2020 · 1 min · jiezi

touch-shell脚本并修改为777权限

mksh.sh#!/bin/bashfor i in "$@"do touch ${i} chmod 777 ${i} echo "#!/bin/bash">${i}donemkcpptest.sh#!/bin/bashfor i in "$@"do touch ${i} echo '#include<iostream>#include<ctime>using namespace std;int main(int argc, char** argv){ return 0;}'>${i}done#创建cppF=time;./mkcpptest.sh ${cppF}.cpp &&vi ${cppF}.cpp;g++ -g ${cppF}.cpp -o ${cppF}.out#不创建cppF=time;vi ${cppF}.cpp;g++ -g ${cppF}.cpp -o ${cppF}.out

June 16, 2020 · 1 min · jiezi

shell语法

1.if 判断 if 后要有空格 if [ 条件判断式 ];then 程序fi或者if [ 条件判断式 ] then 程序fi2.case 语句 case 行尾必须为单词"in" case $变量值 in "值1") 如果变量值等于值1,则执行程序1 ;; "值2") 如果变量值等于值2,则执行程序2 ;; *) 如果变量值等于值2,则执行程序2 ;;esac3.for 循环 for(( 初始值;循环控制条件;变量变化 )) do 程序 done 语法2:for 变量 in 值1 值2 值3... do 程序 done 4.while 循环 while [ 条件判断式 ] do 程序 down5.读取控制台输入 read(选项)(参数)-p // 指定读取时的提示符;-t // 指定读取时等待的时间(秒)参数: 变量:指定读取时的变量名6.系统函数 // 会删除所有的前缀,包括最后一个('/')字符,然后将字符串显示出来basename /home/www/hellow.txt // hellow.txt//从包含绝对路径的文件名中,去除文件名,返回剩余的路径部分dirname /home/www/hellow.txt // /home/www6.自定义函数 ...

June 10, 2020 · 1 min · jiezi

Shell基础

cat /etc/shells // 多种解释器echo $SHELL // 默认解释器1.脚本格式脚本以#!/bin/bash 开头(指定解释器) 2.脚本执行 bash|sh hellowWorld.sh // bash或sh来执行./helloWorld.sh // 脚本需要执行权限3.多命令处理 touch bash.sh // 先创建一个脚本文件// 在脚本文件中写入如下代码#!/bin/bashcd /hometouch hi.txtecho "hahaha" >> hi.txtbash bash.sh // 执行脚本文件一、shell中的变量1.系统变量 echo $HOME // 当前用户家目录echo $PWD // 当前目录echo $SHELL // 默认解释器echo $USER // 当前用户2.自定义变量变量默认类型是字符串类型,无法直接进行数值运算变量值有空格,要用双引号或单引号括起来 A=2 // 等号两边没有空格unset A // 撤销变量readonly B=3 // 静态变量,不能unsetD="aa aavv ddd"export 变量名 // 将变量提升为全局环境变量,可供其他shell程序使用3.特殊变量$n(n为数字,$0代表该脚本名称,$1-$9代表第一到第9个参数,十以上参数需要用大括号,如${10}) sh hello.sh xx mmecho "$0 $1 $2" // 输出hello.sh xx mm$#(获取所有输入参数的个数,常用于循环) ...

June 10, 2020 · 1 min · jiezi

马哥教育学习笔记shell入门到精通第五讲

1、位置变量位置变量指的是脚本(或者函数)后跟的第n个参数。我们这里暂时先讨论脚本传参的用法。 位置变量需要使用到形如 $1、$2、$3、$4、$5、$6。其中$1表示第一个参数,$2表示第二个参数,依次往后类推即可,我们来看看使用效果。 1.1、简单的脚本参数传递先写个简单的脚本 [root@localhost ~]# cat test.sh #!/bin/bashecho "第一个参数:$1"echo "第二个参数:$2"echo "第三个参数:$3"我们写了这样的一个脚本,一共是传入三个参数,然后在脚本里面分别引用三个参数的值,现在来执行一下。 注意先赋予x权限 [root@localhost ~]# ./test.sh 11 22 33第一个参数:11第二个参数:22第三个参数:33我们使用 ./ 执行的时候,分别在脚本后面传入11、22、33这三个数值,然后在脚本内部我们已经提前定义好了引用变量,那么在执行的时候就可以把三个参数的值打印出来。 1.2、位置变量控制使用shift关键字可以实现对位置变量的控制,比如我们写个脚本 [root@localhost ~]# cat test.sh #!/bin/bashecho "第一个参数:$1"shiftecho "第二个参数:$2"echo "第三个参数:$3"现在来执行一下,这次我们传入四个参数 [root@localhost ~]# ./test.sh 11 22 33 44第一个参数:11第二个参数:33第三个参数:44喔?我们发现打印的结果中,第二个参数居然是33,然而我们传参的时候的22这个参数并没有引用到,这就是shift的作用,每执行依次shift命令,位置变量个数就会减一,而变量值则提前一位。 当然也可以设置移动n位,我们不必写上n个shift命令,而直接使用shift n即可,比如: [root@localhost ~]# cat test.sh #!/bin/bashshift 3echo "第一个参数:$1"echo "第二个参数:$2"echo "第三个参数:$3"再来执行一下 [root@localhost ~]# ./test.sh 11 22 33 44 55 66第一个参数:44第二个参数:55第三个参数:66使用shift n,那么位置变量向前移动n位,因此我们的结果是从第四个参数开始引用的,大家都学会了嘛? 1.3、注意事项当然小伙伴可能会问 $0 表示什么呢?我们来执行一下看看,还是先写个脚本 [root@localhost ~]# cat test.sh #!/bin/bashecho "第0个参数:$0"echo "第一个参数:$1"echo "第二个参数:$2"echo "第三个参数:$3"执行一下看看 ...

June 3, 2020 · 1 min · jiezi

使用shell脚本查询服务器的CPU内存磁盘分区的使用率

前言:本文将编写一个shell脚本来查询Linux服务器的CPU、内存、磁盘分区的使用率;shell脚本其实就是由基本的shell命令组合成的,所以在编写shell脚本时,需要对常用的命令要知道,如果不是很清楚的话,可以参考这篇文章:Linux学习一:常用的基础Linux命令 。脚本:#!/bin/bash#计算cpu使用率, -n number:指定在结束前应该产生的最大迭代次数或帧数,一般迭代次数越大,获取到的cpu使用率越准确; 本脚本中是迭代了5次,"-n5" cpu=`top -b -n5 | fgrep "Cpu(s)" | tail -1 | awk -F'id,' '{split($1, vs, ","); v=vs[length(vs)]; sub(/\s+/, "", v);sub(/\s+/, "", v); printf "%d", 100-v;}'`echo $cpu'%' #统计内存使用率mem_used_persent=`free -m | awk -F '[ :]+' 'NR==2{printf "%d", ($3)/$2*100}'`# -e参数是使 "\n"换行符生效进行输出换行的echo -e $mem_used_persent'%\n' #统计分区使用情况,df -P参数可以防止打印输出的内容换行df -THP | awk -F '[ ]+' 'NR!=1{print $1","$6}'运行:编写好脚本后运行,会等到如下的输出结果: 12%37%/dev/mapper/vg_minghui-lv_root,25%tmpfs,1%/dev/sda1,10%/dev/sr0,100% 前两行的内容:12% : cpu的使用率 ; 37% : 内存的使用率; 后面四行的内容:每个磁盘分区的使用率,磁盘分区名称和其使用率之间用英文逗号隔开。 提示:在脚本编写好,且运行前,可以先使用命令 bash -n .sh 判断下脚本是否存在语法错误,如果存在语法错误的话,再使用命令 bash -x .sh 一步步执行脚本看下到底哪个地方存在语法错误。❤不要忘记留下你学习的足迹 [点赞 + 收藏 + 评论]嘿嘿ヾ一切看文章不点赞都是“耍流氓”,嘿嘿ヾ(◍°∇°◍)ノ゙!开个玩笑,动一动你的小手,点赞就完事了,你每个人出一份力量(点赞 + 评论)就会让更多的学习者加入进来!非常感谢! ̄ ̄=

May 28, 2020 · 1 min · jiezi

前端技术之命令模块及其执行方法

一、创建一个命令模块1、package.json { "name": "@uad/nat-cli", "version": "0.0.2", "description": "Demo", "main": "index.js", "bin": { "artisan": "./src/artisan.js" }, "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "repository": { "type": "git" }, "keywords": [ "CLI" ], "author": "chunrong.liu", "license": "ISC", "dependencies": { "shelljs": "^0.8.3", "yargs": "^13.2.4" }}2、src/artisan.js #!/usr/bin/env noderequire('shelljs/global');var argv = require('yargs').option('n', {alias : 'name',demand: true,default: 'tom',describe: 'your name',type: 'string'}).usage('Usage: hello [options]').example('hello -n tom', 'say hello to Tom').help('h').alias('h', 'help').epilog('Copyright 2019').command("morning", "good morning", function (yargs) {echo("Good Morning");var argv = yargs.reset().option("m", {alias: "message",description: "provide any sentence"}).help("h").alias("h", "help").argv;echo(argv.m);}).argv;console.log('hello ', argv.n);console.log(argv._);二、使用方法1、将命令模块通过npm link进行全局注册后,即可在命令行窗口直接使用该命令2、在其它模块中的package.json中引用命令模块,并增加scripts ...

November 4, 2019 · 1 min · jiezi

shell-脚本学习答疑

继上篇 shell 入门文章, 该篇文章会列举出我在学习 shell 的过程中, 遇到的一些疑问, 然后自己查资料以后的解答. 如何运行 shell 脚本回顾例子: [root@host shell]# vim start[root@host shell]# cat start#!/bin/bashecho 'hello'[root@host shell]# chmod 755 start[root@host shell]# ./starthello[root@host shell]#执行时, 为什么要加 ./ ?这要从系统的 $PATH 变量说起, 当我们执行例如 ls, pwd 等指令时, linux 并不会在整个系统翻箱倒柜搜索 ls, pwd 程序, 而是会从 $PATH 变量定义的目录列表下查找, 如果找不到, 就会报 command not found 的错误.因为我们的脚本不在 $PATH 变量目录列表下, 所以需要加上 ./ 指示该应用程序处于当前目录下.另外, 如果我们不想加 ./, 可以将该目录作为系统搜寻指令的其中一个目录: [root@host shell]# vim ~/.bash_profile# 修改 .bash_profile, 添加你的脚本目录.# $PATH 变量定义中, 多个目录用冒号 : 分隔export PATH="$PATH":~/shell# 让 shell 重新读取配置文件[root@host shell]# source ~/.bash_profile[root@host shell]# starthello第一行 #!/bin/bash 有什么作用 ?告诉操作系统用什么解释器执行该脚本 ...

November 2, 2019 · 3 min · jiezi

Linux-系统资源查看walker

OS 版本lsb_release -auname -acat /proc/version系统资源概览top内存free -hcat /proc/meminfo磁盘# 磁盘容量及分区状况(不能查看未挂载分区)df -Th# 磁盘容量及分区状况(可以查看未挂载分区)sudo fdisk -lsudo lsblk -f# /lib 目录大小du -sh /lib # /lib 子目录大小du -sh /lib/*CPU#查看CPU信息cat /proc/cpuinfo# 查看CPU型号cat /proc/cpuinfo | grep name | cut -f2 -d: | uniq -c# 总核数 = 物理CPU个数 X 每颗物理CPU的核数 # 总逻辑CPU数 = 物理CPU个数 X 每颗物理CPU的核数 X 超线程数# 查看物理CPU个数cat /proc/cpuinfo| grep "physical id"| sort| uniq| wc -l# 查看每个物理CPU中core的个数(即核数)cat /proc/cpuinfo| grep "cpu cores"| uniq# 查看逻辑CPU的个数cat /proc/cpuinfo| grep "processor"| wc -l本文出自 walker snapshot

October 17, 2019 · 1 min · jiezi

关于-SUID-SGID-和-Stickywalker

SUIDSet-user IdentificationSUID 属性只能运用在可执行文件上,当用户执行该执行文件时,会临时拥有该可执行文件所有者的权限。示例# 查找具有 SUID 的文件root@qhost:/home/walker# sudo find / -perm /4000walker@qhost:~$ ll /bin/su -rwsr-xr-x 1 root root 40128 May 17 2017 /bin/su*walker@qhost:~$ ll /usr/bin/sudo-rwsr-xr-x 1 root root 136808 Jul 4 2017 /usr/bin/sudo*walker@qhost:~$ ll /usr/bin/passwd -rwsr-xr-x 1 root root 54256 May 17 2017 /usr/bin/passwd*walker@qhost:~$ stat --format=%a /usr/bin/passwd4755SGIDSet-group identificationSGID 属性可以应用在目录或可执行文件上。当SGID属性应用在目录上时,该目录中所有建立的文件或子目录的拥有组都会是该目录的拥有组。示例# 查找具有 SGID 的目录或文件root@qhost:/home/walker# sudo find / -perm /2000# 目录root@qhost:/home/walker# ll -d /var/cache/mandrwxr-sr-x 28 man root 4096 Oct 11 06:25 /var/cache/man/# 可执行文件walker@qhost:~$ ll -H /usr/bin/write -rwxr-sr-x 1 root tty 14752 Mar 1 2016 /usr/bin/write*Stickysticky Bit,saved-text bit,粘着位/粘滞位,也被称作防删除位。Sticky 属性只能应用在目录,当目录拥有 Sticky 属性所有在该目录中的文件或子目录无论是什么权限只有文件或子目录所有者和root用户能删除。示例# 查找具有 sticky 的目录root@qhost:/home/walker# sudo find / -perm /1000walker@qhost:~$ ll -d /tmpdrwxrwxrwt 14 root root 4096 Oct 11 09:53 /tmp/本文出自 walker snapshot

October 17, 2019 · 1 min · jiezi

linux中root用户也没法用rm删除文件的原因

微信公众号:51码农网专业编程问答社区www.51manong.com将文件通过命令chattr命令+i属性,就可以防止文件被修改、重命令、删除。 通过lsattr查看该文件的属性 [root@ky35z root]# lsattr B.file ----i--------e-- B.file发现文件具有i属性。在执行下面的删除。会发现报错。 [root@ky35z root]# chmod 777 B.file [root@ky35z root]# ls -lrt B.file -rwxrwxrwx 1 root root 717 Oct 5 23:05 B.file[root@ky35z root]# chattr +i B.file[root@ky35z root]# rm -rf B.file rm: cannot remove ‘B.file’: Operation not permitted只有超级用户可以对这个属性进行修改的。需要移除这个属性,执行 [root@ky35z root]# chattr -i B.file

October 17, 2019 · 1 min · jiezi

linux中删除空目录的命令rmdir

微信公众号:51码农网专业编程问答社区www.51manong.comrmdir用来删除空目录,只有当目录为空时才会删除目录。这样我们就不需要提前检查目录是否为空。目录存在文件就会报错以下的信息。 [root@ky35z 51mn]# mkdir mnmkdir: cannot create directory ‘mn’: File exists

October 16, 2019 · 1 min · jiezi

linux按照节点号删除乱码文件

微信公众号:51码农网专业编程问答社区www.51manong.com首先通过 ls -i找到该乱码文件的节点号 ls -i假如该文件的节点号为1445331,执行如下命令: find ./ -inum 1445331 -exec rm {} \;

October 15, 2019 · 1 min · jiezi

Linux中如何删除特殊符号文件名文件

微信公众号:51码农网专业编程问答社区www.51manong.com1.对于特殊字符列如<>\*开头的文件,删除加引号 [root@ky35z 51mn]# rm "<>\*"rm: remove regular file ‘<>\\*’? y2.对于-开头的文本,删除使用- - [root@ky35z 51mn]# rm -- -B.file rm: remove regular file ‘-B.file’? y这种你使用删除加目录也可以,rm ./-B.file 3.对于特殊字符!*,要增加转义字符 [root@ky35z 51mn]# rm \!*rm: remove regular file ‘!*’? ylinux中很多字符有着特殊的含义,在前面加上转义字符,就可以当成普通字符使用。4.按照节点号删除 [root@ky35z 51mn]# ls -i ./-B.file1446218 ./-B.file[root@iz2ze720onwdpm0gqiky35z 51mn]# find ./ -inum 1446218 -exec rm {} \;对于乱码文件,这个方法很好用。

October 15, 2019 · 1 min · jiezi

sh执行脚本命令没有权限也能正常执行

微信公众号:51码农网专业编程问答社区www.51manong.comsh+脚本名称,可以不必事先设定shell的执行权限。因为这个是将test.sh作为参数传给sh(bash)命令来执行的。这时不是test.sh自己来执行,而是被人家调用执行,所以不要执行权限。 [root@iz2ze720onwdpm0gqiky35z 51mn]# ls -lrt test.sh -r--r--r-- 1 root root 22 Oct 14 22:34 test.sh[root@iz2ze720onwdpm0gqiky35z 51mn]# sh test.sh hello world如果直接运行test.sh,就会报权限问题 [root@iz2ze720onwdpm0gqiky35z 51mn]# ./test.sh -bash: ./test.sh: Permission denied

October 15, 2019 · 1 min · jiezi

linux中是如何找到执行shell的命令

微信公众号:51码农网专业编程问答社区www.51manong.com用ls命令举例,在linux中,执行ls命令,会经过几个查找过程寻找到ls程序。alias中查找alias可以用来设置命令别名,例如 alias la='ls -lrt'alias ls='ls --color=auto'如果在这里找到了,就会执行下去。如果没有找到,就会继续寻找下去 内置命令中查找在shell中,如果是内置命令,则会直接执行,否则还会继续寻找下去。用help命令看有哪些内置命令。 [root@iz2ze720onwdpm0gqiky35z ~]# help....type [-afptP] name [name ...]pwd [-LP]echo [-neE] [arg ...]....通过type命令查看命令类型 [root@iz2ze720onwdpm0gqiky35z ~]# type pwdpwd is a shell builtinPATH中查找shell中输入ls命令,首先它会从PATH环境变量中查找。看看PATH的内容: [root@iz2ze720onwdpm0gqiky35z ~]# echo $PATH/otyu/java/jdk1.7.0_75/bin:/otyu/java/jdk1.7.0_75/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin它会在这些路径下寻找ls程序,按照路径找到的第一个ls程序会被执行。我们在看一下ls命令的位置: [root@iz2ze720onwdpm0gqiky35z ~]# whereis lsls: /usr/bin/ls /usr/share/man/man1/ls.1.gz可以看出ls是在/usr/bin/目录下的。如果将ls命令移到其他目录,执行ls命令,就提提示你没有安装这个程序或者没找到命令。

October 15, 2019 · 1 min · jiezi

vim中如何实现列编辑操作

微信公众号:51码农网专业编程问答社区www.51manong.com1.列如一次注释vim中的多行a.按Esc(退出编辑或其他模式)b.打ctrl+ v(视觉遮挡模式)c.使用向上↑或向下↓箭头键选择所需的行d.Shift+ i(大写字母I)e.插入您想要的文本,例如##f.按 Esc 输入 :wq 即可完成统一编辑了多行。 2.取消vim多行的注释a.按Esc(退出编辑或其他模式)b.打ctrl+ v(视觉遮挡模式)c.使用向上↑或向下↓箭头键选择要取消注释的行。d.如果要选择多个字符,请使用一个或组合以下方法:e.使用向左←或向右→箭头键选择更多文本f.按d或x删除字符。g.按 Esc 输入 :wq 即可完成统一删除多行注释。

October 14, 2019 · 1 min · jiezi

SFTP与FTP之间的区别

微信公众号:51码农网专业编程问答社区www.51manong.com1、安全通道FTP 不提供任何安全通道来在主机之间传输文件;而SFTP协议提供了一个安全通道,用于在网络上的主机之间传输文件。 2、使用的协议FTP使用TCP / IP协议。而,SFTP是SSH协议的一部分,它是一种远程登录信息。 3、链接方式FTP使用TCP端口21上的控制连接建立连接。而,SFTP是在客户端和服务器之间通过SSH协议(TCP端口22)建立的安全连接来传输文件。 4、安全性FTP密码和数据以纯文本格式发送,大多数情况下是不加密的,安全性不高。而,SFTP会在发送之前加密数据,二进制的形式传递,是无法“按原样”阅读的,安全性较高

October 14, 2019 · 1 min · jiezi

linux中CPU调度或进程调度是分时

微信公众号:51码农网专业编程问答社区www.51manong.com现象:一个实现某功能的方法,低的执行时间有0的,高的有90毫秒的。原因:这是线程切换的成本,但是你可能反驳,调用该方法的时候,线程不是已经切换过来了。按理说执行的时间应该是差不多的。看如下:CPU在windows下是抢占式的,所以一个线程抢到CPU,就能跑跑跑。而linux是分时的,一个线程分到多少时间,执行几个指令后就要让渡CPU给其他线程或进程。例如:线程进入到你的方法,但是你的方法大,指令多。容易被切换。切换的成本就体现在耗时上面了。这也是为啥要求方法体要小一些,指令尽可能小。 微信公众号:51码农网

October 13, 2019 · 1 min · jiezi

小鸟初学Shell编程九环境变量变量配置文件

介绍在上一篇使用完了环境变量,并且知道PATH环境变量概念,那么我们对命令的执行就有了一定深入的理解。那么PATH环境变量或其他环境变量是保存在哪呢?那么这篇文章主要介绍环境变量配置文件。 配置文件环境变量主要保存在以下四个文件和一个目录中: /etc/profile/etc/profile.d/~/.bash_profile~/.bashrc/etc/bashrc保存在/etc/目录下的配置文件,都是所有用户通用的配置,就是不管是root用户还是普通用户。 保存在~/用户家目录的配置文件,是保存特定用户的配置,例如在某些环境只有root用户才可使用。 加载配置文件顺序在重新打开新的终端或切换不同用户时,配置文件的加载顺序是如何的呢?我在这分别对每个配置文件的开头加上了echo 配置文件名,当加载配置文件的时候就会输出对应的配置文件名,便于观察执行的顺序。 使用su - root切换用户时,加载的配置文件: [root@lincoding ~]# su - root/ect/profile~/.bash_profile~/.bashrc/ect/bashrc使用su root切换用户时,加载的配置文件: [root@lincoding ~]# su root~/.bashrc/ect/bashrc可见su和su -切换用户加载配置文件是不同的,最好使用su -的方式切换用户,因为这相当于重新登录Shell,就会把所有配置重新加载一次。 小结本节主要说明系统环境变量配置文件的作用,通过配置文件可以添加自定义的环境变量,在这还需要注意的每个配置文件的功能是不同的。放在/etc/目录下的配置文件,是所有用户都通用的配置文件,放在~/目录下的配置文件,是单个用户的配置文件。

October 9, 2019 · 1 min · jiezi

使用-sed-命令替换删除-文本字符的-20-个例子

简述在以下的文章中会介绍使用 linux sed 命令删除和替换文件中指定字符的 20 个例子。sed 替换字符的命令格式 如下: $ sed 's/find/replace/' file示例文件: $ cat fileLinuxSolarisUbuntuFedoraRedHat 1. 删除指定的字符,比如 'a'$ sed 's/a//' fileLinuxSolrisUbuntuFedorRedHt以上命令会删除每一行匹配到的第一个 'a' 字符,如果要移除每一行的所有 'a' 字符: $ sed 's/a//g' file2. 移除每一行的第一个字符$ sed 's/^.//' fileinuxolarisbuntuedoraedHat. 谁匹配任意的单个字符,^ 指定匹配每一行的开头。以下的命令也可以达到同样的效果 $ sed 's/.//' file因为 sed 命令默认是从开头匹配字符串的,所以使用 . 可以匹配开头的第一个字符。 3. 移除每一行的最后一个字符$ sed 's/.$//' fileLinuSolariUbuntFedorRedHa$ 会匹配每一行字符串的结尾。 4. 同时移除每一行的第一个字符和最后一个字符$ sed 's/^.//;s/.$//' fileinuolaribuntedoredHased命令可以结合多个操作指令,每个指令之间通过';'分割 5. 移除每一行的匹配到的第一个字符,如果没有匹配不做处理$ sed 's/^F//' fileLinuxSolarisUbuntuedoraRedHat以上命令移除了第一个且匹配F的字符 6. 移除每一行的匹配到的最后一个字符,如果没有匹配不做处理$ sed 's/x$//' fileLinuSolarisUbuntuFedoraRedHat以上命令只会删除每一行结尾是 x 的字符 ...

October 8, 2019 · 1 min · jiezi

利用Travis-CIGitHub实现持续集成和自动部署

前言如果你手动部署过项目,一定会深感持续集成的必要性,因为手动部署实在又繁琐又耗时,虽然部署流程基本固定,依然容易出错。 如果你很熟悉持续集成,一定会同意这样的观点:“使用它已经成为一种标配”。 什么是持续集成Continuous Integration(CI) is a development practice that requires developers to integrate code into a shared repository several times a day. Each check-in is then verified by an automated build, allowing teams to detect problems early.———ThoughtWorks 翻译过来就是:持续集成是一个开发行为,它要求开发者每天多次将代码集成到一个共享的仓库,每次提交都会被自动构建所检查,团队可因此提前检测出问题。持续集成的工具非常多,例如用java语言开发的Jenkins,由于其可以在多台机器上进行分布式地构建和负载测试的特性,很多大公司都在使用它。 但是Jenkins的不加修饰的界面界面让我有些嫌弃... 随着GitHub的发展,出现了越来越多支持GitHub的CI/CD产品。在GitHub市场上,可以看到,已经支持的持续集成服务提供商已超过300多家(详情)。 选择Travis CI,是因为身边很多朋友的推荐。 下面分享一下我是如何利用Travis CI+GitHub实现持续集成和自动部署的,通过我的一些研究和实战经验,希望可以帮到有需要的朋友。 什么是Travis CITravis CI是用Ruby语言开发的一个开源的分布式持续集成服务,用于自动构建和测试在GitHub托管的项目。支持包括Javascript、Node.js、Ruby等20多种程序语言。对于开源项目免费提供CI服务。你也可以买他的收费版,享受更多的服务。 Travis CI目前有两个官网,分别是 https://travis-ci.org 和 https://travis-ci.com 。https://travis-ci.org 是旧平台,已经逐渐往新平台 https://travis-ci.com 上迁移了。对于私有仓库的免费自动构建,Travis CI在新平台上给予了支持。 一、获取GitHub Access TokenTravis CI在自动部署的时候,需要push内容到仓库的某个分支,而访问GitHub仓库需要用户授权,授权方式就是用户提供 Access Token 给Travis CI。 ...

October 4, 2019 · 1 min · jiezi

LINUX-shell-脚本讲解

注释一个常用的shell脚本,理解了里面用的语法和命令,就可以自己去写shell脚本了。\#!/bin/bash\# 功能:拷贝远程机器的model文件到本机set -u # 遇到不存在的变量就会报错,并停止执行set -x # 进入跟踪方式,显示所执行的每一条命令work_dir=$(readlink -f $(dirname $0)) # 获取脚本所在的目录,并赋值给变量,$0 表示 当前脚本的文件名 if [ $# -eq 1 ]; then # shell的if语句,括号内的空格不能少,$#表示传递给脚本或函数的参数个数,-eq 判断两个数字是相等 date=$1 # $1 表示传递给脚本表示第一个参数 env="prod" # 变量的赋值elif [ $# -eq 2 ]; then date=$1 env=$2 # $2 表示传递给脚本表示第二个参数else date=$(date -d "1 day ago" +"%Y-%m-%d 00:00:00") # 这里的$(command)是固定用法,将command的结果赋值给date这个变量 env="prod"fidingtalk_webhook="https://oapi.dingtalk.com/robot/send?access_token=some_token"function dingtalk_request(){ # 在shell中定义一个函数 curl -H "Content-type: application/json" -X POST -d '{"msgtype": "text","text": {"content": "'$message'"}}' $dingtalk_webhook}local_path="/path/to/local"date_suffix=$(date -d "$date" +"%Y%m%d") # 这里三个变量都是通过命令获取到具体的值date_now=$(date +"%Y-%m-%d_%H:%M:%S")host_name=$(hostname)remote_host="hostname_test"remote_path="/path/to/remote_test"if [ $env = "prod" ]; then # shell 中字符串比较是否相等用 = remote_host="hostname_prod" remote_path="/path/to/remote_prod"fitest -e $local_path/copy_tag/done.$date_suffix # test -e 命令来查看文件是否存在,$date_suffix表示获取date_suffix这个变量的值if [ $? -eq 0 ]; then # $?表示上一条命令(即test -e,文件存在返回值为0)的返回值;如果本地有done文件,说明已经拷贝过了,就不用重复拷贝 echo "$local_path/copy_tag/done.$date_suffix exist" # echo 向屏幕打印一条信息 exit 0 # shell 脚本正常退出,返回值是0 (脚本执行完,0可以通过$?获取,即上一条命令的返回值)fissh $remote_host "test -e $remote_path/model.$date_suffix" # 使用ssh命令到远程机器上执行test命令if [ $? -ne 0 ]; then # -ne 用来判断数字不相等;远程机器的model文件还没有生成,退出 echo "$remote_path/model.$date_suffix not exist" exit -1 # shell 脚本异常退出,返回值是-1fifile_flag=$(head $local_path/flag) # head 命令打印文件中内容(内容只用一行,0或者1),并赋值给file_flagcurrent_file_flag="0"if [ $file_flag -eq 0 ]; then current_file_flag="1"elif [ $file_flag -eq 1 ]; then current_file_flag="0"else message="[$host_name]Discp_reomte_model_failed:Get_invalid_flag_$file_flag[$date_now]" # 将多个变量和一些信息拼接成字符串 echo $message dingtalk_request # 调用之前定义的函数 exit -1fiscp $remote_host:$remote_path/model.$date_suffix $local_path/$current_file_flag/modelFile # 将远程机器的文件拷贝到本地if [ $? -ne 0 ]; then # 拷贝失败,即返回值不为0,就发送钉钉报警,并退出 message="[$host_name]Discp_reomte_model_failed:$remote_path/model.$date_suffix[$date_now]" echo $message dingtalk_request exit -1fiecho "$current_file_flag" > $local_path/flag # 将信息(current_file_flag的值)重定向到指定文件中,即shell的写文件echo "$current_file_flag" > $local_path/copy_tag/model.done.$date_suffixmd5sum $local_path/$current_file_flag/modelFile # md5sum 用来查看文件的md5值ssh $remote_host "md5sum $remote_path/model.$date_suffix" # 查看远程机器文件的md5值,这两条命令记录下md5,用来检查文件是否一致message="[$host_name]Discp_reomte_model_success_to_$local_path/$current_file_flag/modelFile[$date_now]" echo $message # 拷贝成功,打印信息dingtalk_request # 拷贝成功,发送钉钉信息

October 4, 2019 · 1 min · jiezi

LINUX-shell-常用命令和技巧总结datesortfind

时间(date)获取当前的时间戳 date +%s1570093753时间戳转化为可读时间 date -d @1570093753 "+%Y%m%d %H:%M:%S"20191003 18:09:13时间偏移计算 date -d "2019-10-03 30 days ago" "+%Y%m%d" 20190903获取当前是周几 date +%u # day of week (1..7); 1 is Mondaydate +%w # day of week (0..6); 0 is Sunday4其他更详细的用法 man date排序(sort)主要用于小文件排序(sort lines of text files) sort -t ',' -k 2 -nr ./file_name #次将文件用,分割,对第2列(从1开始算),按照数字顺序(numeric-sort)将整行内容降序排列文件快速去重 sort -u ./file_name其他更详细的用法 man sort 查找(find)找到文件夹中最大的文本 find /path/to/file -name "*txt" | xargs ls -li|sort -k 6|tail -n 1找到文件夹中30天前修改的文件并打印/删除 ...

October 3, 2019 · 1 min · jiezi

小鸟初学Shell编程八环境变量预定义变量与位置变量

环境变量环境变量:每个Shell打开都可以获得到的变量。我们知道通过export的方式打开可以让子进程读取父进程的变量的值,那怎么样才能让每一个进程都能读取到变量的值呢? 在这呢,系统有一些默认的配置文件,把变量嵌入到配置文件就可以了。 那么,系统已经自带了哪些环境变量呢?我们可以通过env这个命令,查看系统中内置的环节变量。 [root@lincoding ~]# envHOSTNAME=lincodingSHELL=/bin/bash……SSH_TTY=/dev/pts/0USER=root……PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/binLANG=en_US.UTF-8SHLVL=1HOME=/rootLOGNAME=root……由于环节变量太多了,省略一部分。以上都是系统的环境变量,新的终端打开,以上的变量都会被初始化完成。 可以通过变量的引用查看单独某个的环境变量的值,环境变量的都是大写为主。 [root@lincoding ~]# echo $PATH/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin[root@lincoding ~]# echo $SHELL/bin/bashPATH系统环境变量是定义了命令的搜索路径,SHELL是定义了系统默认的Shell是bash。 PATH环境变量PATH系统环境变量是定义了命令的搜索路径,意思就是我们输入的Linux命令,都会在PATH变量定义的路径里寻找,若存在则执行命令,若不存在则报错命令不存在。其实所谓的不存在,就是在搜索路径里没有找到对应的命令。 [root@lincoding ~]# echo $PATH/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin假设要增加自定义的搜索路径,则可以通过下面的方式 [root@lincoding ~]# PATH=$PATH:/home[root@lincoding ~]# echo $PATH/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin:/home不过上面的方式,新增的自定义路径是PATH变量,只在当前终端作用范围生效,其他进程是不生效的。 预定义变量预定义变量有$?、$$、$0三个 $?表示的是上一条命令执行的状态码,0代表正常,非0代表出错[root@lincoding home]# cd /home/[root@lincoding home]# echo $?0[root@lincoding home]# cd /file-bash: cd: /file: No such file or directory[root@lincoding home]# echo $?1$$查看当前进程的pid[root@lincoding home]# echo $$18136$0表示当前进程的名称[root@lincoding home]# echo $0-bashShell脚本里使用上述三个预定义变量,脚本如下: #!/bin/bash# PIDecho $$echo $0执行效果: [root@lincoding home]# ./test.sh702./test.sh[root@lincoding home]# . test.sh18136-bash[root@lincoding home]# source test.sh18136-bash根据不同的执行方式,那么$0产生的名称也不同。 位置参数位置参数用于读取执行Shell脚本时传入的参数的值,形式如下: ...

October 2, 2019 · 1 min · jiezi

iOS编译自动升级版本号脚本

版权申明:本文原创首发于以下网站,您可以自由转载,但必须加入完整的版权声明博客园:https://www.cnblogs.com/Mogoo... csdn博客:https://blog.csdn.net/nmjkl001/ 知乎:https://www.zhihu.com/people/... 简书:https://www.jianshu.com/u/954... segmentfault:https://segmentfault.com/u/mo...使用方法Shell代码设置到xcode运行脚本里在每次成功构建后版本号会改变Shell代码#!/usr/bin/env bashecho $CONFIGURATIONif [ $CONFIGURATION == Release ]; thenecho " Bumping build number... "#!/bin/bashbuildNumber=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "$INFOPLIST_FILE")if [ "${buildNumber}" == "" ]; thenecho 2fivar1=${buildNumber##*.}var1=$(($var1 + 1))var2=${buildNumber%.*}buildNumber=${var2}.${var1} /usr/libexec/PlistBuddy -c "Set CFBundleVersion $buildNumber" "$INFOPLIST_FILE"echo " Bumped build number to $buildNumber " elseecho $CONFIGURATION " build - Not bumping build number. "fi我的联系方式:QQ:2161044579 邮箱:mogoostudio@outlook.com Github:https://github.com/MogooStudio

October 1, 2019 · 1 min · jiezi

小鸟初学Shell编程七变量引用及作用范围

变量引用那么定义好变量,如何打印变量的值呢?举例下变量引用的方式。 ${变量名}称作为对变量的引用echo ${变量名}查看变量的值${变量名}在部分情况下可以省略成 $变量名[root@lincoding ~]# string="hello Shell"[root@lincoding ~]# echo ${string}hello Shell[root@lincoding ~]# echo $stringhello Shell那么有花括号括起来的变量和没有花括号的区别是什么呢? [root@lincoding ~]# echo $string9[root@lincoding ~]# echo ${string}9hello Shell9可以发现在引用string变量后加了个9,没有加花括号的引用,会把string9当做一个变量名,有加花括号的引用,则在打印string变量后,尾部多增加一个9 变量的默认作用范围我们通过定义的变量只会在当前的Shell环境生效,当切换成另外一个Shell的时候,之前定义好的变量是不生效的 我们在Shell脚本里定义了一个变量str #!/bin/bashstr="my shell"echo ${str}执行Shell脚本的时候,会打印在Shell脚本定义的变量的值。当前终端引用了Shell脚本的变量,打印了空值。 [root@lincoding ~]# ./test.shmy shell[root@lincoding ~]# echo ${str}[root@lincoding ~]#说明变量str作用范围只在Shell脚本里。 如果在终端定义个一变量,Shell脚本里引用该变量会生效吗? [root@lincoding ~]# mystr="abc"[root@lincoding ~]# cat test.sh#!/bin/bashecho ${mystr}[root@lincoding ~]# ./test.sh[root@lincoding ~]# bash test.sh[root@lincoding ~]# . test.shabc[root@lincoding ~]# source test.shabc上面分别使用了四种执行方式运行脚本,这四种执行方式的影响也在前面章节详细说明过。 方式一和方式二,是会产生子进程来执行脚本,由于当前终端定义的变量作用范围只在当前的终端,所以子进程引用于父进程定义的变量是不生效的。 方式三和方式四,是不会产生子进程,而是直接在当前终端环境执行脚本,所以也在变量的作用范围内,所以引用了变量是生效的。 export导出变量假设想让父进程定义的变量在子进程或子Shell也同时生效的话,那么需要用export将变量导出,使用的具体方式如下例子: [root@lincoding ~]# mystr="abc"[root@lincoding ~]# bash test.sh[root@lincoding ~]# export mystr[root@lincoding ~]# bash test.shabc[root@lincoding ~]# ./test.shabc可见在使用export后,终端定义的变量,test.sh脚本里引用了该变量是生效的。也就说子进程可以获取父进程定义的变量的值。 ...

October 1, 2019 · 1 min · jiezi

小鸟初学Shell编程六变量赋值

变量的意义我们在使用Linux命令或脚本的时候,会有一些输出,那么这些输出的信息可以用变量临时存储,以备我们下一条命令或脚本使用。 变量的定义变量的定义建议用一个有意义的英文单词来代表变量,不要使用简单的字母a,b 这类的变量名定义。因为我们写好Shell脚本实际上是要给人看的,所以我们定义好的变量,是希望变量有具体的含义,能让阅读Shell脚本人能轻松的明白。 变量的命名规则: 字母、数字、下划线不以数字开头变量的赋值为变量赋值的过程,称为变量替换 Shell脚本里变量是不区分变量类型的 变量赋值的规则:变量名=变量值var=123注意:赋值的等号左边右边是不能有空格的,如果出现空格那么执行的时候回进行报错 [root@lincoding ~]# var=123[root@lincoding ~]#[root@lincoding ~]# var =123-bash: var: command not found[root@lincoding ~]# var = 123-bash: var: command not found因为出现空格,Shell会认为前面的是命令而不是变量 使用let为变量赋值[root@lincoding ~]# let num=10+10[root@lincoding ~]# echo $num20用let可以做简单的数字运算 将命令赋值给变量[root@lincoding ~]# ls_cmd=ls[root@lincoding ~]# ${ls_cmd}anaconda-ks.cfg install.log install.log.syslog还可以使用把命令赋值给变量,在使用变量的时候,相当于执行命令 将命令结果赋值给变量,使用$()或者``[root@lincoding ~]# file_list=$(ls /tmp)[root@lincoding ~]# echo ${file_list}pear yum.log[root@lincoding ~]# file_list=`ls /tmp`[root@lincoding ~]# echo ${file_list}pear yum.log使用这种方式的好处,就是避免重复执行相同命令,增加服务器的开销,而是只执行一次命令,并把命令的结果保存到变量,做下一步的使用 变量值有空格等特殊字符可以包含在双引号""和单引号''[root@lincoding ~]# var="1 2 3"[root@lincoding ~]# echo $var1 2 3[root@lincoding ~]# var='a b c'[root@lincoding ~]# echo $vara b c当字符串需要双引号时,需要用单引号来定义字符串 ...

October 1, 2019 · 1 min · jiezi

Mac-终端效率神技

一、 增强各种预览的插件预览查看图片分辨率&大小代码语法高亮快速预览zip压缩包内容快速预览markdown格式内容brew cask install qlcolorcode betterzipql qlimagesize qlmarkdown二、 iTerm2具体的配置网上一大堆。贴一个本人亲身操刀操作过的教程 程序员经常与终端操作打交道,所以很多命令便是做成了命令行模式,在自带的 Terminal 命令都保存在 .bash_profile 文件中,使用了 iterm2,命令都保存在 .zshrc 中。 所以我们将很多命令保存且编辑 cd ~vim .zshrc # 输入自己常用的命令# 文件相关alias co='code ./'alias fo='open ./'alias o='open *.xcodeproj'alias po='open *.xcworkspace'# cocoapodsalias pru='pod repo update'alias pi='pod install'alias pu='pod update'alias piu='pod install --repo-update'alias repoanalysis='specbackwarddependency /Users/liubinpeng/.cocoapods/repos/51xianqu-xq_specs'alias plint='pod spec lint --sources="git@gitlab.51xianqu.com:xq_ios/xq_specs.git"'# Gitalias gck='git checkout'alias gm='git merge'alias gb='git branch'alias gbr='git branch -a'alias gs='git status'alias gc='git clone'alias gl='git log'alias ga='git add .'alias gpull='git pull'alias gpush='git push'alias gcm='git commit -m'alias glocalbranchPush='git push --set-upstream origin 'alias glg="git log --graph --pretty=format:'%Cred%h%Crest -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative"alias ns='npm start'alias ni='npm install'alias nb='npm run build'alias nig='npm install -g '# 浏览器打开alias OpenWithChrome='open -a "/Applications/Safari.app" 'alias OpenWithSafari='open -a "/Applications/Google Chrome.app" '# 用 Typora 打开 markdown 文件预览写作效果。alias OpenMDPreview='open -a "/Applications/Typora.app" 'OCLINT_HOME=/Users/liubinpeng/Documents/oclint/build/oclint-releaseexport PATH=/Users/liubinpeng/Workspace/Native/iOS/sdgcli/bin:$PATHexport PATH=/Users/liubinpeng/Workspace/Native/iOS/sdg_frontend_gitflowcli/bin:$PATHexport PATH=$OCLINT_HOME/bin:$PATH#Flutter 镜像export PUB_HOSTED_URL=https://pub.flutter-io.cn export FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cnexport PATH=/Users/liubinpeng/flutter/bin:$PATH# Android Studio SDK 路径export ANDROID_HOME=~/Library/Android/sdkexport PATH=${PATH}:${ANDROID_HOME}/emulatorexport PATH=${PATH}:${ANDROID_HOME}/toolsexport PATH=${PATH}:${ANDROID_HOME}/platform-toolscd ~source .zshrc验证:在你的 git 项目所在的目录的终端下输入 glg ...

September 30, 2019 · 2 min · jiezi

分享一个git-缩写脚本

分享一个git 缩写脚本git 简写命令,加入linux,mac别名使用方法: ./gsh [命令名] [参数,可选] set 设置用户名和邮箱, 1:名称, 2:邮箱init 设置git 简洁命令gst: 代码变化状态,git statusgd: 查看当前代码改动变化, git diff, git diff 分支1 分支2gam: [gam 备注] 代码提交本地仓库: git commit -am "备注"gpu: [gpu 远程分支名] 与远程仓库关联: git push -u origin 分支名gp: [gp]推送到远程仓库: git pushgl: [gl]拉取远程仓库代码:git pullgb: [gb 新分支名]创建并切换新分支:git checkout -b 新分支名gm: [gm 分支名]合并分支: git merge 分支名gcm: [gcm 目标分支名]切换分支,并更新,再合并: git checkout 分支名B && git pull && git merge 分支名Agsave 保存临时修改文件, git stash savegpop 恢复临时修改的文件,git stash popglg 查看git日志.git log ...

September 10, 2019 · 5 min · jiezi

linux-vivim-的使用完整版

为什么要学 vimlinux 有大量的配置文件,所以 linux 的文本处理工具也是比较多的,常用的有 less vi head tail cat grep sed awk .... 。其中编辑一些配置文件,及查看日志时,常用的工具就是 vim 和 less ,而且它两的快捷键又很相似,所以学会 vim 的使用还是挺必要的。 预期读者运维,开发、及想对 linux 进阶的人。学 bash 的话, 会 vim 还是方便点,不可能每次都要跑到 windows 上去编辑吧 开始学习vi 的三种模式及切换一般模式编辑模式指令列模式graph LRA[一般模式] -- I/O/A/R--> B[编辑模式]A -- 冒号/问号/正斜杠 --> C[指令列模式]C -- ESC --> AB -- ESC --> A从一般模式切换到编辑模式各命令区别 i 在当前光标处插入o 另起一行插入a 后面一个字符插入r 替换输入。这个在改单个字符很有用,因为它只替换一个字符又变回一般模式了常用按键及功能下面的指令是区分大小写的 移动游标的方法 (一般模式)↑→↓← 上右下左移动,5↓ 向下移动 5 行ctrl + f 向下翻页,翻半页命令为 ctrl + dctrl + b 向上翻页,翻半页命令为 ctrl + u0 移动到一行的开头,移到到一行的结尾为 $gg 到开头,G 移动到结尾 ,3G 移动到第 3 行<enter> 游标向下移动一行,3<enter> 游标向下移动 3 行删除,复制,粘贴 (一般模式)x 向后删除一个字符,X 向前删除一个字符,3x 向后删除 3 个字符dd 删除一行,3dd 删除3 行d$ 从当前光标位置删除到结尾 ,dG 从当前位置到最后一行全部删除yy 复制当前行 ,3yy 复制 3 行p 在下一行粘贴复制的东西,P 在上一行粘贴u 撤回操作. 重复上一次操作查找与替换(一般模式)/word 向下查找字符,?word 向上查找字符n 重复前一个搜索的动作,按下 n 后,会继续找下一个匹配的字符1,5s/sanri/9420/g 搜索第 1 行到第 5 行的 sanri 字符串,替换成 94201,$s/sanri/9420/g 搜索第 1 行到最后一行的 sanri 字符串,替换成 9420选择文本 (一般模式)v 然后使用方向键,相当于在 windows 按住鼠标拖动V 光标经过的行会选择ctrl +v 选择列模式y 选择的文本复制d 选择的文本删除 ...

September 9, 2019 · 2 min · jiezi

Linux-shell-获得字符串所在行数及位置

shell 获得字符串所在行数及位置01 获取字符串所在的行数方式一:用grep -n[root@root]# cat testapplebitcreatedelectexeflowgood[root@root]# cat test | grep -n exe5:exe[root@root]# cat test | grep -n exe | awk -F ":" '{print $1}'5方式二:用sed -n '/查询的字符串/=' 文件[root@root]# cat testapplebitcreatedelectexeflowgood[root@root]# [root@root]# sed -n '/exe/=' test502 获取字符串中字符所在的位置方式一:用awk -F 和 wc -c 组合[root@root]# echo 'uellevcmpottcap' | awk -F 'ott' '{print $1}';uellevcmp[root@root]# echo 'uellevcmpottcap' | awk -F 'ott' '{print $1}' | wc -c10方式二:用awk 'BEGIN{print index("'${str}'","'${str1}'") }'[root@root]# str='uellevcmpottcap';str1='ott';awk 'BEGIN{print index("'${str}'","'${str1}'") }'10

August 18, 2019 · 1 min · jiezi

Linux-shell脚本判断服务器网络是否可以上网

介绍在编写shell脚本时,有的功能需要确保服务器网络是可以上网才可以往下执行,那么此时就需要有个函数来判断服务器网络状态 我们可以通过curl来访问 www.baidu.com,从而判断服务器网络状态是否可以畅通的 网络状态判断#!/bin/bash#检测网络链接畅通function network(){ #超时时间 local timeout=1 #目标网站 local target=www.baidu.com #获取响应状态码 local ret_code=`curl -I -s --connect-timeout ${timeout} ${target} -w %{http_code} | tail -n1` if [ "x$ret_code" = "x200" ]; then #网络畅通 return 1 else #网络不畅通 return 0 fi return 0}networkif [ $? -eq 0 ];then echo "网络不畅通,请检查网络设置!" exit -1fiecho "网络畅通,你可以上网冲浪!"exit 0网络状态正常的脚本执行结果:网络畅通,你可以上网冲浪! 网络状态不正常的脚本执行结果:网络不畅通,请检查网络设置!

August 18, 2019 · 1 min · jiezi

Linux下-keepalived-的安装和配置

安装前准备基础系统:CentOS 7yum -y install gcc gcc-c++ autoconf automake make yum -y install zlib zlib-devel openssl openssl-devel pcre pcre-devel1.下载keepalived方法一: yum -y install keepalived方法二: 下载二进制源码包:http://www.keepalived.org/dow... #下载安装文件cd /usr/localwget http://www.keepalived.org/software/keepalived-2.0.18.tar.gz#解压文件tar -zxvf keepalived-2.0.18.tar.gz#编译cd keepalived-2.0.18/#--prefix 指定安装地址#/usr/local/keepalived/ 安装的目录,不要和自己安装文件一个目录,不然报错./configure --prefix=/usr/local/keepalived/#编译并安装 make && make install2.配置复制文件: [root@localhost ~]# cp /usr/local/keepalived-2.0.18/keepalived/etc/init.d/keepalived /etc/init.d/[root@localhost ~]# mkdir /etc/keepalived[root@localhost ~]# cp /usr/local/keepalived/etc/keepalived/keepalived.conf /etc/keepalived/[root@localhost ~]# cp /usr/local/keepalived-2.0.18/keepalived/etc/sysconfig/keepalived /etc/sysconfig/[root@localhost ~]# cp /usr/local/keepalived/sbin/keepalived /usr/sbin/编辑: vi /etc/keepalived/keepalived.conf/etc/keepalived/keepalived.conf内容如下 global_defs { notification_email { #mr@mruse.cn # 指定keepalived在发生切换时需要发送email到的对象,一行一个 #sysadmin@firewall.loc } notification_email_from xxx@163.com # 指定发件人 smtp_server smtp@163.com # smtp 服务器地址 smtp_connect_timeout 30 # smtp 服务器连接超时时间 router_id LVS_1 # 必填,标识本节点的字符串,通常为hostname,但不一定非得是hostname,故障发生时,邮件通知会用到 }vrrp_script chk_tomcat { #详细看下面 script "/etc/keepalived/tomcat_check.sh" #检测服务shell interval 2 #每个多长时间探测一次 weight -20 #每个多长时间探测一次 }_instance VI_1 { # 实例名称 state MASTER # 必填,可以是MASTER或BACKUP,不过当其他节点keepalived启动时会将priority比较大的节点选举为MASTER interface ens33 # 必填, 节点固有IP(非VIP)的网卡,用来发VRRP包做心跳检测 mcast_src_ip 192.168.2.89 #本机的ip,需要修改 virtual_router_id 101 # 必填,虚拟路由ID,取值在0-255之间,用来区分多个instance的VRRP组播,同一网段内ID不能重复;主备必须为一样; priority 100 # 必填,用来选举master的,要成为master那么这个选项的值最好高于其他机器50个点,该项取值范围是1-255(在此范围之外会被识别成默认值100) advert_int 1 # 必填,检查间隔默认为1秒,即1秒进行一次master选举(可以认为是健康查检时间间隔) authentication { # 必填,认证区域,认证类型有PASS和HA(IPSEC),推荐使用PASS(密码只识别前8位) auth_type PASS # 默认是PASS认证 auth_pass 1111 # PASS认证密码 } virtual_ipaddress { 192.168.2.90 # 必填,虚拟VIP地址,允许多个 } track_script { # 检测shell chk_tomcat }}vrrp_script 里的script返回值为0时认为检测成功,其它值都会当成检测失败; ...

August 18, 2019 · 2 min · jiezi

用shell脚本生成x509pem-和pk8-文件并签名

用shell脚本生成.x509.pem 和.pk8 文件并且signed apk。文章末有完整脚本 -----生成keystore 的文件 keytool -genkey -v -keystore ${KEY_STORE_PATH} -alias ${ALIASES} -storepass ${PASS} -keypass ${PASS} -keyalg RSA -validity 20000 -dname "CN='Android', OU='xxx-shanghai', O='xxx', L='Mountain View', ST='California', C='US'"-keystore 生成文件的路径 -alias 文件别名 -storepass -keypass 密码 -keyalg 加密方式 -validity 有效时间 -dname 把需要的国家 地址 公司名等信息 一次写入使用 java sdk 的keytool 生成keystore 文件。-----把keystore文件转换为pkcs12格式 keytool -importkeystore -srckeystore ${KEY_STORE_PATH} -destkeystore ${DEST_KEY_STORE_PATH} -srcstoretype JKS -deststoretype PKCS12 -deststorepass ${PASS} -srcstorepass ${PASS} -destkeypass ${PASS}-srckeystore keystore文件路径 -destkeystore 生成的pkc12文件路径-----把pkcs12 转成pem,方便可以通过文本方式查看 openssl pkcs12 -in ${DEST_KEY_STORE_PATH} -nodes -out ${DEST_TMP_RSA_PATH} -password pass:${PASS}-in pkcs12 路径, -out 生成的pem 路径 password pass: 密码-----截取pem文件生成.X509.pem .rsa.pem文件 ...

August 7, 2019 · 2 min · jiezi

如何结合npm做一个前端脚手架

背景需求:在日常开发中,随着项目越来越多,能重复利用的代码就越多,急需一套基本的模板来初始化项目,把代码放到自己的gitlab或github上,每次又得找到地址重新clone一下,很麻烦期望的结果:XXX init 。。。一行命令解决步骤:1、申请一个npm账号,https://www.npmjs.com/2、写一个npm项目package.json: { "name": "windssr", "version": "1.0.8", "description": "a tool service for react-ssr", "main": "index.js", "bin": { "windssr": "index.js" }, "author": "windseek", "license": "ISC", "dependencies": { "chalk": "^2.4.2", "co": "^4.6.0", "co-prompt": "^1.0.0", "commander": "^2.20.0" }, "scripts": { "test": "test" }, "repository": { "type": "git", "url": "git+https://github.com/Windseek/react-ssr-cli.git" }, "keywords": [ "react", "react-ssr", "wind-ssr", "react-ssr-cli" ], "bugs": { "url": "https://github.com/Windseek/react-ssr-cli/issues" }, "homepage": "https://github.com/Windseek/react-ssr-cli#readme"}init.js 'use strict'const exec = require('child_process').execconst co = require('co')const prompt = require('co-prompt')const config = require('./template.json')const chalk = require('chalk')module.exports = () => { co(function *() { // 处理用户输入 let tplName = yield prompt('Template name (you can input one like react, vue, angular): ') let projectName = yield prompt('Project name: ') let gitUrl,branch; console.log(config.tpl); if (!config.tpl[tplName]) { console.log(chalk.red('\n × Template does not support!')) process.exit() } gitUrl = config.tpl[tplName].url branch = config.tpl[tplName].branch // git命令,远程拉取项目并自定义项目名 let cmdStr = `git clone ${gitUrl} ${projectName} && cd ${projectName} && git checkout ${branch}` exec(cmdStr, (error, stdout, stderr) => { if (error) { console.log(error) process.exit() } console.log(chalk.green('\n √ Generation completed!')) console.log(`\n cd ${projectName} && npm install \n`) process.exit() }) })}index.js ...

July 26, 2019 · 1 min · jiezi

Shell脚本应用条件测试操作

Shell脚本应用——条件测试操作 前言:在简单的shell脚本程序中,各条语句将按先后顺序依次执行,从而实现批处理的自动化过程,这就使得脚本过于机械化,不够“智能”,难以处理更加灵活的系统任务。 下面让我们一起了解如何进行条件测试操作,并通过正确使用if语句,使shell脚本具有一定的“判断”能力,以根据不同的条件来完成不同的管理任务。 条件测试操作 要是shell脚本程序具备一定的“智能”,面临的第一个问题就是如何区分不同的情况以确定执行何种操作。例如,当磁盘使用率超过95%时,发送警告消息;当备份目录不存在时,能够自动创建;当源码编译程序时,若配置失败则不再继续安装等。 Shell环境根据命令执行后的返回状态值($?)来判断是否执行成功,当返回值为0时表示成功,否则(非0值)表示失败或异常。这两种方式的作用完全相同,但通常后一种形式更为常用(按照个人习惯吧)。需要注意的是,用方括号“[ ]”测试格式时,方括号“[ ]”左右与条件表达式之间需要至少一个空格进行分隔,否则会报错。 根据需要测试的条件类别不同,条件表达式也不同。常用的条件操作包括:文件测试、整数值比较、字符串比较、以及针对多个条件的逻辑测试。 1.文件测试 文件测试指的是根据给定的路径名称,判断对应的是文件还是目录,或者判断文件是否可读、可写、可执行等。 常见的操作选项如下,使用时将测试对象放在操作选项之后即可。 -d:测试是否为目录(Directory)-f:测试是否为文件(File)-e:测试目录或文件是否存在(Exist)-r:测试当前用户是否有读的权限(Read)-w:测试当前用户是否有写入权限(Write)-x:测试是否有可执行权限(Excute)示例 宝宝起名网 通过“$?”返回的值可以判断前一步的条件测试结果,但输出的结果也并不是很直观。为了可以更直观的查看测试结果,可以结合命令分隔符“&&”和echo命令一起使用,其中“&&”符号表示“而且”的关系,只有当前面的命令执行成功后才会执行后面的命令,否则后面的命令将会被忽略。 2.数值比较 数值比较指的是根据给定的两个整数值,判断第一个数与第二个数的关系,如第一个数是否大于、等于、小于第二个数。 整数值比较的常用操作选项如下,使用时将操作选项放在要比较的两个整数之间。 -eq:第一个数等于(Equal)第二个数-ne:第一个数不等于(Not Equal)第二个数-gt:第一个数大于(Greater Than)第二个数-lt:第一个数小于(Lesser Than)第二个数-le:第一个数小于等于(Lesser or Equal)第二个数-ge:第一个数大于等于(Greater or Equal)第二个数整数值比较在shell脚本编写中的应用较多。例如,用来判断已登录用户数量、开启进程数、磁盘使用率是否超标,以及软件版本是否符合要求等。实际使用时,往往通过变量引用、命令替换等方式来获取一个数值。 示例:判断当前已登录的用户数,当超过五个时输出“Too many”。如下图: 示例:判断物理内存(Mem)当前的磁盘缓存(buff/cache)大小,当低于1024MB时输出具体数值。如下图: 3.字符串比较 字符串比较通常用来检查用户输入、系统环境等是否满足条件,在提供交互式操作的shell脚本中,也可以用来判断用户输入的位置参数是否符合要求。 字符串比较的常用操作选项如下: -z:检查字符串是否为空(Zero),对于未定义或赋予空值的变量将视为空串。-n:测试变量的值不为空,与-z相反=:第一个字符串与第二个字符串相同!=:第一个字符串与第二个字符串不相同,其中“!”表示取反示例:判断当前系统的语言环境,若不是“en.US”时输出提示信息“Not en.US”。如下图: 示例:在脚本应用中,经常需要用户输入“yes或no”来确认某个任务。这时需要用到确认交互的过程,通过判断用户输入的内容来执行下一步操作。此示例只是其中一个简单的过程。如下图: 关于read命令的用法可以点击查看Linux——Shell脚本中自定义变量的应用(基础)2 4.逻辑测试(与、或、非) 逻辑测试指的是判断两个或多个条件之间的依赖关系。当系统任务取决于多个不同的条件时,根据这些条件是否同时成立或者只要其中一个成立等情况,需要有一个测试的过程。 逻辑测试操作可分为表达式与表达式之间的逻辑、表达式内部逻辑两种,如下: 表达式之间逻辑:&&、||、! 表达式内部逻辑:-a、-o、! &&(-a):逻辑与,表示“而且”,只有当两个条件都成立时,整个测试命令的返回值才为0(结果成立)。||(-o):逻辑或,表示“或者”,只要两个条件中有一个成立,整个测试命令的返回值就为0(结果成立)。!:逻辑否,表示“不”,只有当指定的条件不成立时,整个测试命令的返回值才为0(结果成立)在上述的逻辑测试的操作选项中,在实际应用中也用于间隔不同的命令操作,其作用也是相似的。如“make && make install”的编译安装操作。

July 11, 2019 · 1 min · jiezi

Windows-10-Shell要巨变

根据爆料,微软正致力于Windows Lite(Windows轻量级版本)的研发,旨在实现双屏和高性价比的设备。微软也将Shell与Windows 10基础系统分离,这一改变可能使微软能够使Shell UI等升级更加灵活。 Windows Core OS模块化和灵活的操作系统,这是我们在过去几个月听到的所有令人兴奋的项目基础。目前的Windows Core OS产品列表包括AndromedaWindows IoTEdgeOS、Polaris和Modern PC。 据报道,微软已经删除了对Lite OS的提及,熟悉该开发的人员推测该项目现在改称为Modern PC。生辰八字起名字 值得注意的是,微软最近在Computex公告的博客文章中突出了其对“Modern OS”的看法,这两个项目可能相关。 微软正在分离Shell和Windows 独立开发人员还发现在Windows 10 20H1版本中提到了“Shell Update Agent”,可能会将Shell与基础操作系统分离。 将Shell与操作系统分离还将分离出Shell UI部件(例如Action Center与Windows 10的其余部分)。 Shell Update Agent能够按需获取和更新shell。 调查结果还表明,Shell将是一个独立的封装组件。使用ShellUpdateAgent的功能可以从Microsoft Store安装“UX.Client.ST”。虽然这只是一个占位符,但它表明微软会将Shell控制的元素带到应用程序商店,因此可以在不更改操作系统的情况下更新Windows的某些部分。 值得注意的是,Action Center是Windows 10 20H1中可以从Shell程序包中更新的首批功能之一(如果可用时)。 所有这些变化可能对于普通用户来说差别不是很大,但对于开发者来说,是更加有趣的开始。

July 11, 2019 · 1 min · jiezi

Windows-Shell新代号Santorini-现身-仙女座正淡出视线

微软正在开发内部代号为Windows Lite OS的统一Windows体验。该公司尚未确认有关Windows Lite的任何公开细节,但初步报告显示该操作系统可在各种设备上运行,从双屏硬件到中低端二合一平板设备等。Windows Lite旨在提供更好的性能、统一的Windows代码体验和更高的安全性。微软还开始为LiteOS准备Shell,以便针对不同的设备外形提供定制的体验。 最近微软技术观察者还发现,WindowsLite还有一个名为“Santorini (圣托里尼)”的外壳,它可能正在为微软传闻中的双屏Centaurus设备提供支持。有传言称Centaurus可以是同时具有Windows Core OS和LiteOS的Santorini shell,也可能仅仅是运行Windows Lite OS的设备。 希腊语“Santorini”是位于爱琴海的基克拉迪群岛的其中一个岛屿。 生辰八字起名字 随着微软在支持Windows处理可折叠和双屏外形设备方面的进展,Windows 10 20H1 Build 18934中事实上已经出现了Santorini这一代号。 作为Windows Core OS的一部分,Andromeda mobile shell的已从Windows 10 20H1中淡出,这意味着便携式Andromeda设备可能已被推迟,因为微软迄今为止仍然没有令人信服的理由将可折叠的移动外形设备推向市场,而像Centaurus这样的大型双屏设备或许更有意义。

July 11, 2019 · 1 min · jiezi

用户有望从商店下载并实时切换Shell

微软在为 Windows 10 开发各种不同的 Shell 的事情,早已不是什么新鲜事。 为了照顾不同外形的设备和用例(比如双屏的 Andromeda 智能机、Centaurus 笔记本、以及 Oasis for HoloLens),这家软件巨头正在努力为用户带来更加出色的体验。 有趣的是,在昨日推送的 Windows 10 20H1 Build 18917 预览编译版本中,我们发现微软正在为资源管理器添加 Hook,以便为 Windows 10 UI 带来更多的个性混搭。 有人猜测, 微软 正在为这款操作系统带来可以查看并替换当前 UI Shell 的组件包,且其能够通过下载、或集成于 OS 的方式获得。 率先爆料此事的 Albacore 表示,这项特性是由一个名叫 Microsoft-OneCore-Sheill-UpdateAgent 的组件导入的。 理论上,用户是能够自行通过 Microsoft Store 应用商店下载、并启用一套全新的 Windows 10 Shell 的。 但最令人期待的,莫过于系统能够在运行过程中、实时地完成 Shell 的切换。宝宝起名宝典 如果 Windows 10 20H1 决定正式开放这一权限,那么后续肯定会冒出一堆自诩为“换壳助手”(Shell Switchers)的软件。 此前,已经有报道称微软为开始菜单开辟独立的进程。而在 Windows 10 20H1 中,行动中心(Action Center)最有可能被第一个从 Windows 10 Shell 中剥离。 Albacore 指出,这项特性似乎是 OneCore 的一部分,表明所有备用的 Shell 都可以被动态地更新。 ...

July 11, 2019 · 1 min · jiezi

经验拾忆纯手工-Linux实用工具命令

Ubuntu16升级到18.04“”“ 有特殊新颖强迫症癖好可以升下,如果你觉得16.04好用,就根本没必要升了”“”我当时租的 云服务器通常都是16.04,现在估计也是16.04较多我是个Python3的玩家, 我只想用Python的最新版,或最新标准版3.6-3.7道理很简单,我追求新颖,虽然新版不稳定,但是你可以尝鲜并领先于别人。。。废话不多说: Ubuntu16.04: 默认装的是Python2.7 + Python3.4 或3.5 Ubuntu18.04: 默认装的是Python2.7 + Python3.6.+我喜欢升级系统版本来直接让对应软件升级: lsb_release -a # 查看系统版本 apt update # 一路选Y apt dist-upgrade apt autoremove # 一路选Y apt install update-manager-core # 比较重要 do-release-upgrade -d # 完事注: 如果其中某个命令过程弹出一个黑窗口让你选择, 我记得有个 core-new-update 字眼的,选这个即可 # 选择 新 核心vim多行注释(Python为例)Ubuntu是肯定可以用, CentOS我记得好像用不了直接一套连招:注释: 1. ctrl + v 2. 按 下 箭头方向键,选中多行 3. shift + i 4. 输入 # 5. 按两下 ESC键 取消注释: 1. ctrl + v 2. 按 下 箭头方向键,选中多行 3. 按 x 键注: 此套连招,需要熟练度, 如果不行就多练练。 手不好使,就不要怪我了~~~~ vimrc简单配置:“”“ tab = 4缩进, 设置行号 基于文件名的简单语法高亮 不要想着删一行,直接打开vimrc 全部复制上去,保存退出就可以用了”“”vi ~/.vimrc syntax on set nu set expandtab set tabstop=4 set shiftwidth=4 set softtabstop=4locate查询库locate xxx # 虽然很简单的命令,但是如果,一直为下线,并且还想查找新东西,那么需要更新库updatedb # 更新搜索库, 完事如果 updatedb命令出错,那就安装一下 mlocate就好了: yum/apt-get install mlocatehtop查看服务器负载ubuntu/centos中有 top : 此命令可以详细查看服务器各种负载,资源状况,但是看着不方便,非常费劲 htop : top的升级版, 容易看出资源消耗情况 如果未安装,可通过 apt-get/yum install htop 安装 htop -d 0.1 # 0.1秒动态更新一次资源数据。 看起来有一点炫。 pkillps -el 查看 PId + kill -9 PID # 这套连招可强制杀死一个进程但假如你有一连串的python进程 想要 全部KILL pkill python # 完事,和python有关的全KILL掉了,也可以通过通配符* 的方式来简写patree列出进程tree: 此命令用来列出目录层级结构pstree: 用来列出 正在运行的 程序(所有进程的层级结构,进程名)pstree -p: 以层级的方式,不仅列出进程名, 还列出所有进程的(PID)alias改名vi /etc/profile alias python='python3' # 这里是举个例子,配完,python命令就等价于 python3命令 alias pip='pip3'source /etc/profile # 不要忘记,这条命令 更新一下配置文件重定向管道 ( > 与 tee )date > date.txt # 截流, 屏幕上不显示date | tee date.txt # 不截流, 屏幕上显示, 并且还能输入到文件! 叹号命令”“ !命令前缀 : 运行最后一条以这个前缀开头的命令”“假如下面是你最后按顺序再command终端 输入的四条命令: python aaa.py python bbb.py npm run dev pip install ccc需求:你想迅速运行 python bbb.py这条命令你只需 !py # 即可, 愣着干啥呢, 已经完事了,这条命令就等于你上面那一大串 解惑: 1. !py -> py开头的有两条,为啥不执行第一条 python aaa.py 因为 ! 叹号 的语法意思就是选择 最后出现以py开头的执行。 2. 为啥直接 !p 不行呢? 因为以p开头的最后一条命令是 pip install ccc。 这也不是你想要的啊。ctrl+z 和 & 和 nohup 和 screenctrl+c: 强制终止(最常用的,先提出来。。。。 应该都知道的。。)ctrl+z: 可以把正在运行中的程序挂起到后台(注意这时候程序就暂停了)jobs: 粗略列出 后台挂起的程序jobs -l: 详细列出 后台挂起的程序 (其实就是多列出了个PID) kill -9 PID # 顺水推舟地使用此命令来通过 PID 干掉后台挂起的程序 fg: 把挂起的后台的程序 拿回来继续执行fg 程序编号: 如果有多个后台挂起的程序,选择一个继续执行,编号可通过 jobs 查看。使用场景: 加入正在 vim 编辑东西,想跳出编辑器,写点别的,那么可以 进行下面操作: 不要保存, 直接 ctrl+z 然后去 做别的事 做完了想回到 vim继续编辑剩下的内容, 直接 fg &: 运行 的 时刻 就直接 放到后台 (不实用) eg: (通常是费时的操作,或者长时间占用 command命令行) sleep 100 & # 这样费时100秒的操作,直接让它滚去后台执行,别占我地方 局限: 假如你用 python xxxx.py & 运行一个web服务器,虽然它会滚去后台一直运行。 前台command界面看起来很干净了。 但是,如果有用户请求过来, 你服务器收到打印在终端的信息 可不会乖乖打印在后台。 打印信息会钻出来到前台command界面来恶心你。。。。。 为了解决这一问题, 请移步 下面 ...nohup: (通常和 上面的 & 联合使用) (实用性一般) eg: 同样运行一个服务器 nohup python xxx.py & # 它会乖乖的滚去后台执行,并且将要打印的消息 也不会打印到前台,也不会打印到后台。 那打印的内容去哪了呢?? nohup会自动给你 把打印的东西重定向 到一个 nohup.out文件,通常在当前目录下 # 这时你的前台command 就不会受到 骚扰了。。。。 也许你以为它很好用了,可以完美的决绝运行一个费时的进程。但是 它依然是个 loser。。. 局限: 当我一直用 nohup.out 部署一些服务程序的时候,一部署就是很多天。 当时学校断电(我租的阿里云ECS服务器). 虽然服务器可以不间断的执行。 但是 我需要 用 xshell 一直去远程 查看我的 程序运行的怎么样了啊, 是否崩了? 可惜的是,每次xshell关闭了,你再上去, 想找 通过 nohup & 连招 放到后台程序的时候, 你会痛苦无比。。。非常惨 后来。。。。。。。。。 screen: (会话机制) 没错,后来我就发现了 这个 screen工具 如果你那里没有,就安装一下喽: apt-get / yum install screen 然后需要配置一下: vi ~/.screenrc # 创建文件 shell -$SHELL # 输入此行内容,保存退出 至于为何配置这个: 说实话我有点忘了 貌似不同screen会话对于不同的shell 权限有限制,导致很多东西用不了,so do it 直接说一套我常用且超级实用连招把: eg: screen -S 会话名 # 创建 并 进入这个会话(就像进入另一个世界,但资源共享) python xxx.py # 举例子,这是我的爬虫程序,需要运行 三天 ctrl + a + d # 跳出会话,回到正常命令行,但是这个会话以及你的程序依然在运行, ....... 这段时间(除了关闭服务器)你做什么都行,关闭 shell也可以的。 screen -r 上面的会话名 # 恢复到会话中, 你会发现,爬虫程序还在那里好好的运行呢。 如果你忘记会话名了,不要紧: screen -ls # 这条命令会列出所有 你创建过的会话,你也可以看到会话名 总结: 所以,我不知道阁下能不能感受到 screen的魅力。 我们可以 通过 screen -r 这一条命令来 迅速回到程序运行的环境。 nohup &: 你用这个执行的程序,关了 xshell, 你再连,你就不好找这个运行的程序了 screen 有一套完好的系统(就像有开关一样)来控制会话 你进入screen会话中写程序,screen 自然就能有条不紊的管理好 你程序的运行状态 举个白话例子: 你正遛二哈呢,突然有急事: nohup & : 你说:‘二哈,等我回来,自己玩把’ 你回来时, 二哈跑丢了。 (不受控制,程序找不到了,虽然可以花力气找到) screen : 你说:‘二哈,等我回来,自己玩吧,但我要把你拴起来’ 你回来时, 二哈还在那里乖乖的玩。(程序有效的受到控制,你可以轻松定位)sudo su等操作不好意思,用了好几年linux: 什么 su- su 之类的, 我至今都没搞太明白。。。。。。。。。。但是,我只用下面这一条命令,这些年就没遇到过问题: sudo -s # 变为root, 如果你之前输入过密码, 这条命令还会免去让你输入密码的环节环境变量把某路径加入到环境变量中: vi /etc/profile export PATH=$PATH:/XXX/XX做一些配置: vi /etc/profile vi ~/.bashrc 等修改完后 source /etc/profile # 用一个 source 命令执行一下使配置更新生效 注: Linux-shell我研究的不深,所以这里可能有些说的不是特别明朗。 其实 这些配置文件 以及 source . sh bash 这些命令 和 用户 以及权限等都是有很大关系的。 有兴趣可自行深入了解SSH远程连接小坑假如你的 xshell 连接不上远程服务器, 可能未开启 或 未安装 sshd服务如下命令即可: sudo apt-get install openssh-client # 安装客户端配置 sudo apt-get install openssh-service # 安装服务器配置 systemctl start sshd.service # 开启服务如果你的普通用户可以连接,但是你的root不能登录: vim /etc/sshd/ssh_config PermitRootLogin yes # 找到这个改为yes , 保存退出就完事了 MySQL5.7+/MariaDB修改密码小坑当阁下还在停留在Mysql5.7版本之前,修改密码可以用下面这两种方式: mysqladmin -uroot password -p 或内部设置: update user set password=password('root') where user='root'但是 MySQL5.7 之后 或者 MariaDB ,上面这俩方法 都不能 修改密码了。正确修改方式: 先进入MySQL交互式: MySQL -uroot -p update mysql.user set authentication_string=password("密码") where user="用户名" update user set plugin="mysql_native_password"; flush privileges 最后重启服务, 完事 另外,值得提醒的一点容易出现的问题: 无论你连接的是什么数据库,如果你连不上 首先你应该想到的是,数据库配置文件: bind 0.0.0.0 # 每种数据库几乎都需要先改成这样,才能被外界访问 其次,你用的是云服务器的话 看看是否放通了 对应数据库的宽口 最后,是否开了防火墙: 没记错的话,Centos 和 Ubuntu 防火墙不是同一种,真正需要关闭可自行百度 其他命令""" 一时间也记不起来还用过哪些了"""wc : 统计字,词,行(自己选参数)curl : 可以请求 url,并返回数据(相当于一个小小爬虫),也可以向某个接口发送请求ssh-keygen :生成公私密钥cd - : 跳回到上一次的路径lsb_release -a : 查看Linux发行版信息grep : 过滤字符tar : 压缩/解压netstat : 查端口等

July 10, 2019 · 3 min · jiezi

Shell脚本运行-编写-debug

1 1.1开头定义 #!/bin/bash 1.2. sh -x xxx.sh (sh=shell,-x属于debug模式) ./xxx.sh 运行 如果permission denied就chmod 654 xxx.sh改一下操作权限2.定义变量 2.1 静态变量 k=v ^ k="v" 2.2 动态变量 k=v 等于号前后不能有空格 引用的话 使用 $k^${k} 生产上一般用后面带括号的3.传递参数 sh test.sh a b (这里a,b就是传进去的参数) $#-->传递参数的个数 2 $*-->传递参数的作为一个字符串显示 $$-->PID-->process ID进程号4.数组 一维的 创建:arr=(masiwei tracy j.cole youngflame) 打出全部:echo ${arr[*]} 打出tracy: echo ${arr[1]} 打出元素个数: echo ${#arr[*]}*也可以用@替代掉

July 8, 2019 · 1 min · jiezi

内网穿透神器FRP

frpfrp 是一个可用于内网穿透的高性能的反向代理应用,支持 tcp, udp, http, https 协议原文地址 目前主要的场景是内网穿透,可以用于本地调试微信接口、本地站点公网访问等。 本文主要讲解: frp客户端配置frp服务端配置&&搭建准备frp执行区分不同的平台,在服务器上执行命令: arch如果输出x86_64则需要下载带linux_amd64的那个压缩包;如果输出的是其他的,则在文件列表中找 linux 的对应架构的压缩包 frp_0.20.0_darwin_amd64.tar.gz macfrp_0.20.0_linux_arm64.tar.gz linuxfrp_0.20.0_windows_386.zip windows然后尝试运行./frps --help, 正常会输出帮助信息。 如果提示-bash: ./frps: cannot execute binary file: Exec format error就说明你下错版本了。 客户端-frpc客户端和服务端版本号一致,目前使用的是v0.20.0。 启动命令: ./frpc -c frpc.inifrpc.ini客户端配置(必须) [common]# frp 服务器端地址,ip或域名server_addr = frp.xxx.com# frp 服务端端口,即填写服务端配置中的 bind_portserver_port = 7000token = xxxxxHTTP(S)[apixxx]# http 或 httpstype = http# 默认不需要改变ip,指向本地local_ip = 127.0.0.1# 对应服务的端口号local_port = 9000# http 可以考虑加密和压缩一下use_encryption = trueuse_compression = true# 自定义访问网站的用户名和密码,如果不定义的话谁都可以访问,会不安全http_user = adminhttp_pwd = admin# 对应远程的访问地址web0.frp.xxx.com:10080# frp.idayer.com 为服务端配置的 subdomain_host subdomain = web0TCP/UDP 范围转发# 自定义一个配置名称,格式为“[range:名称]”,放在开头[range:multi-port]type = tcplocal_ip = 127.0.0.1use_encryption = falseuse_compression = false# 本地端口和远程端口可以指定多个范围,如下格式,且范围之间必须一一对应local_port = 6010-6020,6022,6024-6028remote_port = 16010-16020,16022,16024-16028最后我们的配置结果如下: ...

July 8, 2019 · 2 min · jiezi

Windows下WSL2的常规设置

工欲善其事,必先利其器升级Windows10到1903并下载Windows Terminal分享下我的配置 profiles.json 设置WSL为版本2。 添加右键打开,注册表写入更改下面的名字哦 Windows Registry Editor Version 5.00[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Directory\background\shell\Bash]@="Bash here"[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Directory\background\shell\Bash\command]@="C:\\Users\\[your-name]\\AppData\\Local\\Microsoft\\WindowsApps\\Microsoft.WindowsTerminal_8wekyb3d8bbwe\\wt.exe"[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Directory\shell\Bash]@="Bash here"[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Directory\shell\Bash\command]@="C:\\Users\\[your-name]\\AppData\\Local\\Microsoft\\WindowsApps\\Microsoft.WindowsTerminal_8wekyb3d8bbwe\\wt.exe" 在添加~/.bashrc中添加 export windows_host=`ipconfig.exe | grep -n4 WSL | tail -n 1 | awk -F":" '{ print $2 }' | sed 's/^[ \r\n\t]*//;s/[ \r\n\t]*$//'`export ALL_PROXY=socks5://$windows_host:1080export HTTP_PROXY=$ALL_PROXYexport http_proxy=$ALL_PROXYexport HTTPS_PROXY=$ALL_PROXYexport https_proxy=$ALL_PROXYif [ "`git config --global --get proxy.https`" != "socks5://$windows_host:1080" ]; then git config --global proxy.https socks5://$windows_host:1080fi#重写cd# cd C:\\ 自动切换到 /mnt/cfunction cd() { command cd `wslpath "$1"`} 这样,最好的Linux发行版Windows 10就配置好了 ????

July 6, 2019 · 1 min · jiezi

微信小程序的jenkins发布构建

原文地址 环境准备微信开发者工具只支持macOS和Windows平台,所以jenkins也只能运行在这两个环境中。现在假设我们已经安装了jenkins,并且配置好了任务,大家可以参考微信小程序集成 Jenkins中的配置教程 配置mini-deploy插件在任务配置页面的 “构建” 中,选择 “执行 shell” ,贴入如下代码。 # 设置yarn源yarn config set registry https://registry.npm.taobao.orgyarn install # 删除构建文件并执行对应scriptsrm -rf dist && yarn run $build_type# 切换为jenkins帐号身份,这样写的原因是机器配置问题,可以忽略su jenkins <<'EOF' if [ "$build_type" == "prod" ] || [ "$build_type" == "build" ] then yarn run deploy --mode=upload --ver=$upload_version --desc=$upload_desc let "result |= $?" if [ "$result" == "0" ] then yarn run notify fielse yarn run deploy --mode=previewfiEOFyarn run notify为内部推送通知脚本yarn run deploy为mini-deploy的脚本,是本地安装调用方式mini-deploy同时也支持全局mini-deploy --workspace=/Users/xxx/WorkSpace/mini --mode=upload,执行时会检查project.config.json文件是否存在。 ...

July 2, 2019 · 1 min · jiezi

将路由器温度通过MQTT协议加入Homeassistant及Homekit

前言最近入手了一台斐讯K3路由器,可是博通的芯片发热太严重,想要随时了解路由器的温度,于是自己动手实现了一组程序来将路由器温度通过MQTT加入Homeassistant及Homekit. 准备已经获取root权限的K3路由器部署好HomeAssistant的内网服务器部署好Node.js的内网服务器前置知识基本的Shell编程基本的HTTP及web服务器知识基本的MQTT原理基础JavaScript编程软件结构最早的想法是直接在路由器上通过Python获取数据及通过MQTT发送至HASS服务器,但是一个是opkg的源太慢了,另一个是不想给路由器增加额外负担(万一加了测温软件温度涨几度就尴尬了),最终采用了如下的软件结构 路由器---> Node.js Server ---> Homeassistant其中路由器到Node.js通过简单的HTTP,将温度数据通过JSON发送过来.Node.js通过Express.js实现web服务器用于接受路由器数据,mqtt包实现mqtt通讯,发送给Homeassistant. 服务器端Shell程序温度获取首先第一步是获取路由器的温度数据: CPUcat /proc/dmu/temperature #CPU温度wl -i eth1 phy_tempsense #2.4GHz无线芯片温度wl -i eth2 phy_tempsense #5GHz无线芯片温度运行结果如下: 需要注意的是这里有一个坑,CPU温度的文件中又不符合UTF-8的字符,直接用curl发的话会导致错误,这里我们直接用cut进行处理,这里暂时不考虑温度为或3位的情况(事实上不太可能发生)cat /proc/dmu/temperature|cut -c19-20同理我们对另外两项数据也进行处理 wl -i eth1 phy_tempsense|cut -c0-2wl -i eth2 phy_tempsense|cut -c0-2发送温度数据HTTP数据约定GET Method数据位于data参数下,内容封装于JSON中,格式如下{"type":"data","CPU":61,"W24G":51,"W5G":65} curl实现这里我们通过curl来发送数据,这里是用GET方法,为了以后增加控制信息方便,数据包格式如下 {"type":"data","CPU":61,"W24G":51,"W5G":65}经过url encode的结果为 %7B%22type%22:%22data%22,%22CPU%22:61,%22W24G%22:51,%22W5G%22:65%7D我的Node.js服务器地址是192.168.2.103,端口3000所以我们的url是 url="http://192.168.2.103:3000/?data=%7B%22type%22:%22data%22,%22CPU%22:$cpu,%22W24G%22:$w24,%22W5G%22:$w5%7D"增加无限循环后的完整程序#!/bin/shecho " run.. "while truedo cpu=$(cat /proc/dmu/temperature|cut -c19-20) w24=$(wl -i eth1 phy_tempsense|cut -c0-2) w5=$(wl -i eth2 phy_tempsense|cut -c0-2) url="http://192.168.2.103:3000/?data=%7B%22type%22:%22data%22,%22CPU%22:$cpu,%22W24G%22:$w24,%22W5G%22:$w5%7D" curl $url sleep 60 #设置1分钟的查询周期 continuedoneecho " end.. "为了让程序不断运行,推荐用screen来管理Node端程序HTTP服务器这里我们基本使用了模版提供的功能,由于我们这里只对数据进行透明传输,所以JSON不需要反序列化 router.get('/', function(req, res, next) { var data = req.query.data res.render('index', { title: 'Express' });});MQTT客户端MQTT数据约定我们的数据分别放在三个Topic下 ...

July 2, 2019 · 1 min · jiezi

如何用docker快速安装-kalilinux-以及相应工具

docker run --name kali -i -t kalilinux/kali-linux-docker /bin/bashapt-get updateapt-get install kali-linux-all

July 1, 2019 · 1 min · jiezi

编程语言之问何时该借用何时该创造

本文原创并首发于公众号【Python猫】,未经授权,请勿转载。 原文地址:https://mp.weixin.qq.com/s/Oy... 6 月 22 日,Python 之父 Guido 发了一条推特,说了 Python 的一则历史故事,他说 elif 是从 C 语言中偷过来的: elif 是“else if”的简写,用于条件判断。当只有两个分支时,我们会写成“if...else...”,当出现更多分支时,我们会写成如下格式: if 判断条件1: 做事情1elif 判断条件2: 做事情2else: 做其它事简写而成的 elif 不仅是减少了几个字符,而且由于单一而清晰的用途,它还不会给我们带来理解或使用上的困惑。 但是,简写法并不是主流,完整写法才是主流,C 语言中就是采用完整的写法: if(判断条件1){ 做事情1}else if(判断条件2){ 做事情2}else { 做其它事}没错,C 语言使用的是全拼写法,但是在它的预处理/预编译语句中,还有一个 elif 指令,Guido 所说的“偷”,就是从这来的: #if 常量表达式1// 编译1#elif 常量表达式2// 编译2#else// 编译3#endifPython 没有预编译,所以所谓的偷,跟预编译没有关系,只是在对比两种写法后,借用了更简洁的写法而已。 为什么 C 语言不把两种写法统一起来呢?这我不得而知了,而 Guido 在两种写法中,选择了后一种非主流却更好用的写法。我想对他说,你“偷”得好啊! 实际上,留言区里的人也有同感,纷纷表示:不介意、很 okay、非常喜欢,还有人说“不是偷,而是收获(harvested)”、“不是偷,而是把它提升了一些高度”…… 前不久,我写了一篇《聊聊 print 的前世今生》,print 这个词就是从 C 语言中借用来的。除此之外,如果有人仔细比较这两种语言的关键字和习惯命名,肯定会发现不少相同的内容。 编程语言间有一些共享的元素,这很常见,创造一门语言并不意味着要原创每一个词句,毕竟大部分思想是共通的,作为基础设施的词语更是如此。 那么,我突然好奇了:创造一门编程语言时,什么时候该借用,什么时候该创造呢? 这个问题看起来可能没啥意义,因为终其一生,我们多数人也不大可能会参与创造一门编程语言。 但我觉得它还是极有意义的,首先,提问精神值得肯定,其次,它还提供了一种溯源、甄别、遴选、创造的体系性视角,我认为这是求知的正确思维方式。 带着这个疑惑,我特别想要考察的是 Python 的 for 循环。 ...

June 30, 2019 · 3 min · jiezi

高效SHELL环境-step-by-step一-命令别名

基础环境在进行高效的SHELL实践之前,首先配置一下基础环境,当然首先是需要一台MacOS电脑。这里采用: zsh + oh-my-zsh + zsh-completions + zsh-autosuggestions 。具体安装步骤如下: # 切换默认SHELL为 zsh$: chsh -s /bin/zsh# 安装 oh-my-zsh$: sh -c "$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"# 安装 zsh-completions$: git clone https://github.com/zsh-users/zsh-completions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-completions# 安装 zsh-autosuggestions$: git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions安装完成后,轻松敲打几个命令,该提示的、补全的也都如预期般的展示,的确大大的提升了命令输入的效率。 命令别名减少输入的另一个办法就是对拼写复杂的命令设置简易的别名。alias别名命令最常规的用法就是,定义别名。当然这是alias命令的主要功能之一。不过它还具有其它功能,不细看的话很容易被忽略掉。 不妨通过tldr命令查询看看alias的功能列表: $: tldr aliasaliasCreates aliases -- words that are replaced by a command string.Aliases expire with the current shell session, unless they're defined in the shell's configuration file, e.g. `~/.bashrc`.- List all aliases: alias- Create a generic alias: alias word="command"- View the command associated to a given alias: alias word- Remove an aliased command: unalias word- Turn `rm` into an interactive command: alias rm="rm -i"- Create `la` as a shortcut for `ls -a`: alias la="ls -a"不难看出,alias命令还有另外检索的功能,该功能在我们设置别名时先判断是否已经存在别名非常有用。 ...

June 27, 2019 · 2 min · jiezi

linux-常用命令汇总

linux 常用命令汇总linux本质linux : 文件系统,一切皆文件命令、选项、参数彼此之间要用空格命令本质上就是一个程序文件,选项和参数本质上都是参数Linux中的大小写是敏感的,单词容易拼错,建议初学者使用快捷键TAB:对命令的自动补全 - 按一下自动补全,如果没有自动补全代表有多个候选项 - 按两下显示所有的匹配项最常见的Linux初学者的报错: command not found :命令没有找到 命令单词写错了语法格式不对No such file or directory:没有找到该文件或者目录 文件路径写的不对文件名写的不多绝对路径、相对路径相对路径: 如果不加 / ,即为从当前路径开始计算绝对路径: 绝对路径都是使用 / 打头linux基本命令1. ls = list 显示当前目录下所有的文件,包括目录ls /home 显示指定目录下的所有文件 -a 隐藏的文件也要显示出来 -l 显示详细的信息,包括属主,属组,文件大小,创建时间等 -al 显示所有的文件,并且显示详细的信息 2. cd = change directory 切换目录即打开目录目录结构/ 根目录 bin :基本命令的目录,所有用户都可以用的命令就在这里 sbin :超级管理员才能使用的命令,root用户使用的管理类命令 usr :共享软件的安装位置 var :日志目录,重要记录文件的目录 tmp :临时目录 opt :可选目录 lib :库包的目录 etc :Linux的配置文件目录 root :管理员的家目录,root用户的家目录 home :用于存储每个普通用户的家目录的,类似于windows上的用户目录 zhizuobiao 用户名 haitong 用户名 …… 3. 其他常用命令pwd = print word directory 显示当前的目录机构clear:清屏,等价于Ctrl+l ...

June 27, 2019 · 2 min · jiezi

PHP传递数组格式参数到shell脚本中

PHP中传递类似于“数组”格式数据到shell脚本中:模拟场景1:计算捆绑商品的价格,捆绑商品中包含多个商品,这个商品是不确定的,我们暂时定义为苹果、栗子、香蕉,价格分别为8元/斤、10元/斤、3元/斤,重量规格定为500g,我们把价格当做参数传递给shell脚本计算总价格以下是关于PHP部分的代码: $prices = array( "apple" => 8, "banana" => 3, "chestnut" => 10);$command = "bash ".ROOT_PATH."/script/test.sh ";foreach ($prices as $price) { $command .= $price." ";}$output = array();$ret = 1;exec($command." 2>&1", $output, $ret);var_dump($command, $output, $ret);exit;// command命令为:// bash /data/home/tina/script/test.sh 8 3 10下面是关于shell脚本内容: #!/bin/bashall=0for price in $@do all=`expr ${all} + ${price}`doneecho ${all}场景2:在场景1的情况下,我们修改价格为浮点数,苹果、栗子、香蕉价格分别为8.8元/斤、9.9元/斤、3.5元/斤,expr表达式会报错(expr: 参数数目错误),expr不支持浮点类型,这里应该采用bc或者awk,shell脚本修改如下: #!/bin/bashall=0for price in $@do #all=$(echo ${price}+${all}|bc) all=$(awk "BEGIN{print ${all}+${price}}")doneecho ${all}场景3:在场景2的基础上,捆绑商品现在需要变更重量,苹果0.5KG、香蕉1KG、栗子1.5KG,则计算价格时,我们也需要把重量的参数传递到shell脚本中,才能计算价格。方案一:继续把这些参数加在脚本之后,把参数个数一分为二,我们知道前面一半部分为价格参数,后半段参数为重量参数,修改如下:PHP代码部分: $prices = array( "apple" => 8.8, "banana" => 3.5, "chestnut" => 9.9);$weights = array( "apple" => 1, "banana" => 2, "chestnut" => 3);$command = "bash ".ROOT_PATH."/script/test.sh ";foreach ($prices as $price) { $command .= $price." ";}foreach ($weights as $weight) { $command .= $weight." ";}$output = array();$ret = 1;exec($command." 2>&1", $output, $ret);var_dump($command, $output, $ret);exit;// command命令为:// bash /data/home/tina/script/test.sh 8.8 3.5 9.9 1 2 3 修改的shell脚本为: ...

June 26, 2019 · 2 min · jiezi

全栈学习实践一环境搭建准备

初始环境:[注:测试主机已设置好软件源,虚拟主机默认是root用户登录] []:~/tmp# lsb_release -aNo LSB modules are available.Distributor ID: DebianDescription: Debian GNU/Linux 9.9 (stretch)Release: 9.9Codename: stretch[]:~/tmp# 目标环境: [docker+]php-7.3.6redis-5.0.5memcached-1.5.16openresty-1.15.8.1(nginx+lua)mysql-8.0.16mongodb-4.0.10一、前期准备1、文件列表(mysql选择的是debian、x64、server版) https://www.php.net/distributions/php-7.3.6.tar.xzhttp://download.redis.io/releases/redis-5.0.5.tar.gzhttps://memcached.org/files/memcached-1.5.16.tar.gzhttps://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-community-server-dbgsym_8.0.16-2debian9_amd64.debhttps://openresty.org/download/openresty-1.15.8.1.tar.gzhttps://fastdl.mongodb.org/src/mongodb-src-r4.0.10.tar.gz2、依赖准备 PHP:apt-get install curl libxml2-dev libssl-dev libzip4 libzip-dev libbz2-dev libjpeg-dev libpng-dev libxpm-dev libfreetype6-dev libgmp-dev libgmp3-dev libcurl4-gnutls-dev librecode-dev libreadline-dev libtidy-dev libxslt1-dev -yOpenResty:apt-get install libpcre3-dev libssl-dev perl make build-essential curl -y3、docker准备环境搭建使用docker,参考相应官网:《Debian安装Docker》、《使用清华源安装docker》 []:~/tmp# vim docker_install.sh#!/bin/bash#1. 卸载旧版本apt-get remove docker docker-engine docker.io#2. 安装依赖apt-get install apt-transport-https ca-certificates curl gnupg2 software-properties-common -y#3. curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add -#4. x86_64添加软件仓库add-apt-repository "deb [arch=amd64] https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/debian $(lsb_release -cs) stable"#5. 更新源并安装apt-get update && apt-get install docker-ce -y[]:~/tmp# chmod +x docker_install.sh && ./docker_install.sh第一步准备完成 ...

June 25, 2019 · 1 min · jiezi

Shell截取字符串

linux下截取字符串有好多方式,这里介绍几种常用的 假设变量var = http://www.jouypub.com 1、# | % 号截取(#和%效果一样),删除左边字符,保留右边字符 非贪婪模式:echo ${var#*/} 或 echo ${var%*/}执行结果:删除左侧的http:/,为/www.jouypub.com 贪婪模式:echo ${var##*/} 或 echo ${var%%*/}执行结果:删除左侧的http://,为www.jouypub.com##表示从左边开始删除最后(最右边)一个/号及左边的所有字符 2、从左边第几个字符开始,及字符的个数echo ${var:0:5}其中的 0 表示左边第一个字符开始,5 表示字符的总个数。结果是:http: 三、从左边第几个字符开始,一直到结束。echo ${var:7}执行结果:www.jouypub.com 欢迎订阅「K叔区块链」 - 专注于区块链技术学习 博客地址:http://www.jouypub.com简书主页:https://www.jianshu.com/u/756c9c8ae984segmentfault主页:https://segmentfault.com/blog/jouypub腾讯云主页:https://cloud.tencent.com/developer/column/72548

June 25, 2019 · 1 min · jiezi

记录下git1的使用

记录下多人协作中常用的git命令Q: fatal: refusing to merge unrelated histories// (拒绝合并不相关的分支)// 解决办法: git pull origin master --allow-unrelated-histories命令集合 // 查看本地是否有关联的远程分支 git remote -v // 如果本地没有关联任何远程分支 git remote add origin xxxxx git push origin master 推送内容到远程master分支上 // 解除与远程关联的分支 git remote remove origin 通过git log查看版本演变git log --all -n2 --oneline --graphgit help ---web --log // 网页打开查看log相关用户说明gitk打开图形化git界面删除分支 git branch -al // 查看所有分支 git push origin --delete charpeter6 // 远程删除charpeter6分支 git branch -d charpeter1 // 删除本地 tree,blob,commit三者之间的关系find .git/objects -type f 查看.git/objects文件夹下是否还有其他文件git stash储藏修改 git stash // 储藏本次修改 git stash pop 弹出最近一次的储藏修改, 并且删除stash储藏区的记录, git stash apply 弹出最近一次修改,但不会删除stash储藏区的记录 git stash list 查看储藏区的记录 git stash clear 清楚所有储存 git stash drop stash@{0} 移除制定储存 git stash show stash@{0} 查看某次储藏的区别 git stash branch testchanges 如果你想用更方便的方法来重新检验你储藏的变更,你可以运行 git stash branch,这会创建一个新的分支,检出你储藏工作时的所处的提交,重新应用你的工作,如果成功,将会丢弃储藏。

June 23, 2019 · 1 min · jiezi

聊聊-print-的前世今生

本文原创并首发于公众号【Python猫】,未经授权,请勿转载。 原文地址:https://mp.weixin.qq.com/s/Nu... (一) 上周,我翻译了一篇文章,解释了为什么 Python 3 把 print 改为函数? 概括有如下几点原因:1、print 不适宜作为应用程序级的语句。2、改为一个函数,可以实现更复杂的功能。3、改为一个函数,能方便地进行替换。 在 Python 2 中,print 是个语句(statement),它的级别就跟 for、if、def 等关键字相同,这是一个古老的设计(毕竟 Python 诞生于 1989 年),改成 print() 函数,意味着它升级了。 在查阅资料的时候,我发现 print 在历代版本中,一直发展变化,到了今天,它自身已足够完善了,可是外部的挑战一直不断。 因此,这篇文章再来聊聊它:介绍 print 的现状,追溯它的历史,说说它的挑战者,挖挖那些更加本质的东西。 (二) 在 3.0 版本中,print() 函数全新登场,开发者可以自定义打印对象的间隔(默认是空格)、终止方式(默认是换行)、以及输出位置(默认是标准输出 sys.stdout)。 而到了 3.3 版本,它还添加了一个新的参数,可以决定是否要刷新数据流。 至此,这个函数的完整格式就变成了 print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False) ,与升级前的 print 语句是天壤之别啦。 优点是显而易见的,可定制的参数带来了使用场景的扩充。 (三) 其实,在这次大版本的改动之前,早期的 print 语句并非是一成不变的,核心开发者们一直在完善它。 例如,在 2000 年的 PEP-214 之前,print 语句只能用于标准输出(sys.stdout),只有当提出这个提案后,print 才可以打印内容到类文件对象(file-like object)中。 (注:PEP 即 Python 改进提案,更多介绍详见旧文《学习Python,怎能不懂点PEP呢?》) ...

June 23, 2019 · 2 min · jiezi

计算机基础Linux-常用命令

作者:LogM 本文原载于 https://segmentfault.com/u/logm/articles ,不允许转载~ 1. find 文件查找# 查找txt文件# -iname:忽略大小写find . -name "*.txt"find . -iname "*.txt"# 正则表达式查找.txt和.cpp文件,注意特殊符号用`\`转义# -iregex:忽略大小写find . -regex ".*\.\(txt\|cpp\)$"find . -iregex ".*\.\(txt\|cpp\)$"# 使用`!`进行否定,查找非.txt或.cpp的所有文件find . ! -regex ".*\.\(txt\|cpp\)$"# 查找指定深度和指定类型:f为文件,d为目录,l为符号连接find . -maxdepth 3 -type f# 查找后进行指定操作,`-ok`逐文件提示是否进行操作,`-exec`无提示,注意结尾的`;`find . -type f -name "*.txt" -ok cat {} \;find . -type f -name "*.txt" -exec cat {} \;2. grep 文本搜索# 在文件中查找"match_pattern",允许多个文件,支持正则表达式grep "match_pattern" file_1 file_2 file_3# 只打印匹配到的文件名grep -l "match_pattern" file_1 file_2 file_3# 忽略大小写grep -i "match_pattern" file_name# 输出除"match_pattern"的其他行grep -v "match_pattern" file_name# 输出的结果中,对匹配的区域进行高亮grep "match_pattern" file_name --color=auto# 只输出匹配"match_pattern"的区域,而非一行grep -o "match_pattern" file_name# 每个输出的前面带上这个区域在原文件中的位置(第一个字符为0,第二个字符为1,依次类推),一般`-b``-o`连用grep -b -o "match_pattern" file_name# 每行输出的前面带上这行在原文件中的行号grep -n "match_pattern" file_name# 统计文件中包含文本的行数grep -c "match_pattern" file_name# 在目录下递归查找,`-r`和`-R`效果相同grep -r "match_pattern" pathgrep -R "match_pattern" path# `-e`允许多个"match_pattern"grep -e ".*\.html" -e ".*\.php" file_name# `-E`使用正则表达式的写法有所改变,等同于egrep,貌似是`|`和`&`不再需要`\`转义且`*`表示任意数量的任意字符grep -E "*\.php|*\.html" file_name --color=auto# 等同于grep ".*\.html\|.*\.php" file_name3. xargs 命令行参数转换xargs 能够将输入数据转化为特定命令的命令行参数;这样,可以配合很多命令来组合使用。比如grep,比如find。 ...

June 20, 2019 · 4 min · jiezi

究竟什么是前端脚手架

???? 咱也不知道咱也不敢问啊 先查查百度百科里对“脚手架”的定义吧: 脚手架是为了保证各施工过程顺利进行而搭设的工作平台。然后搜一下“脚手架”,基本上都是以下几类: Vue/React 脚手架使用 Node、yeoman 打造自己的脚手架从零搭建 webpack 脚手架此时还是无法确定什么是“脚手架”,也许我心目中的脚手架应该是 vue/cli 或者 create-react-app 吧,然后我打开他们的文档,但是他们的介绍上并没有说这是一款脚手架... 谈一下我自己的“脚手架”???? 我最怕别人看到我的“脚手架”后说这有什么卵用... 看了一下我第一次在 Github 上的提交记录 Commits on Feb 13, 2017,我入行三年多,那时应该是我第一次进入前端工程化的时候吧。在此之前我在公司接手的都是一些很简单的项目,直接新建文件夹,随手下载一个jQuery,然后新建 index.html main.js style.css,有没有同样经历的小伙伴们? 后来做的项目多了,觉得每次这么新建项目太麻烦,我新建了一个文件夹,专门存放初始的模板,然后复制粘贴,继续撸。 再后来,接触到 vue,他可以实现在终端内输入一行指令就能生成模板,这可比我复制粘贴看起来高端多了,为了装逼我开始了研究如何开发自己的“脚手架”。 当时还真是没有几篇文章把这种操作说的很明白,甚至我并不知道我要做的东西叫什么(脚手架)。 我理解的“脚手架”???? 百科里说的很对我的思路,首要的就是保证我的项目可以顺利进行。 能够快速帮我生成新项目的目录模板(Node.js)。能够提升我的开发效率和开发的舒适性(webpack)。分享点干货从零搭建这种我就不说了,毕竟一搜一堆,基本上就是推荐几个库,例如 commander、inquirer、ora 等等。分享一些在我的脚手架开发时遇到的一些问题和需求,分享想给大家。 版本验证首先推荐工具库: semver,版本对比。 request,发送请求,当然你也可以用 axios。 const semver = require('semver');const request = require('request');Node.js 版本验证如果你的脚手架想分享给别人用,这步最好不要避免,因为如果你用了一些现代化的 ES 语法,比如说 async await,老版本跑不起来的。 function checkNodeVersion (wanted) { // process.version 可以获取当前的 node 版本 if (!semver.satisfies(process.version, wanted)) { console.log('Node版本不支持巴拉巴拉'); // 退出进程 process.exit(1); }}脚手架版本验证正如上面所说,你如果分享给别人用,在你修改了一些 bug 后,希望其他人用最新的版本,那就应该提示他。 ...

June 14, 2019 · 2 min · jiezi

大数据系列shell的简单语法

1. Linux 简介Linux内核最初只是由芬兰人李纳斯·托瓦兹(Linus Torvalds)在赫尔辛基大学上学时出于个人爱好而编写的Linux是一套免费使用和自由传播的类Unix操作系统Linux能运行主要的UNIX工具软件、应用程序和网络协议2. Linux的发行版Linux的发行版说简单点就是将Linux内核与应用软件做一个打包Ubuntu(图形化接口,个人用户操作比较良好)RedHat(企业使用的比较多,图形化接口比较low,收费)CentOS(免费 开源 图形化接口比较low)Debian、Fedora、SuSE、OpenSUSE、Arch Linux、SolusOS3. Linux应用领域作为企业服务器嵌入式4. Linux vs Windows比较WindowsLinux界面界面统一,外壳程序固定所有Windows程序菜单几乎一致,快捷键也几乎相同图形界面风格因发行版不同而不同,可能互不兼容。GNU/Linux的终端机是从UNIX传承下来,基本命令和操作方法也几乎一致。驱动程序驱动程序丰富,版本更新频繁。默认安装程序里面一般包含有该版本发布时流行的硬件驱动程序,之后所出的新硬件驱动依赖于硬件厂商提供。对于一些老硬件,如果没有了原配的驱动有时很难支持。另外,有时硬件厂商未提供所需版本的Windows下的驱动,也会比较头痛。由志愿者开发,由Linux核心开发小组发布,很多硬件厂商基于版权考虑并未提供驱动程序,尽管多数无需手动安装,但是涉及安装则相对复杂,使得新用户面对驱动程序问题(是否存在和安装方法)会一筹莫展。但是在开源开发模式下,许多老硬件尽管在Windows下很难支持的也容易找到驱动。HP、Intel、AMD等硬件厂商逐步不同程度支持开源驱动,问题正在得到缓解。使用使用比较简单,容易入门。图形化界面对没有计算机背景知识的用户使用十分有利。图形界面使用简单,容易入门。文字界面,需要学习才能掌握。学习系统构造复杂、变化频繁,且知识、技能淘汰快,深入学习困难。系统构造简单、稳定,且知识、技能传承性好,深入学习相对容易。软件每一种特定功能可能都需要商业软件的支持,需要购买相应的授权。大部分软件都可以自由获取,同样功能的软件选择较少。5. Linux的安装刚开始已经安装过centeros6.5 6. Linux 系统启动过程内核的引导 当计算机打开电源后,首先是BIOS开机自检,按照BIOS中设置的启动设备(通常是硬盘)来启动。操作系统接管硬件以后,首先读入 /boot 目录下的内核文件。 运行 init init 进程是系统所有进程的起点,你可以把它比拟成系统所有进程的老祖宗,没有这个进程,系统中任何进程都不会启动。init 程序首先是需要读取配置文件 /etc/inittab 系统初始化 在init的配置文件中有这么一行: si::sysinit:/etc/rc.d/rc.sysinit 它调用执行了/etc/rc.d/rc.sysinit,而rc.sysinit是一个bash shell的脚本,它主要是完成一些系统初始化的工作,rc.sysinit是每一个运行级别都要首先运行的重要脚本建立终端 rc执行完毕后,返回init。这时基本系统环境已经设置好了,各种守护进程也已经启动了。init接下来会打开6个终端,以便用户登录系统。在inittab中的以下6行就是定义了6个终端: 用户登录系统 命令行登录ssh登录图形界面登录7. Linux 系统目录结构/bin bin是Binary的缩写, 这个目录存放着最经常使用的命令/boot 这里存放的是启动Linux时使用的一些核心文件,包括一些连接文件以及镜像文件/dev dev是Device(设备)的缩写, 该目录下存放的是Linux的外部设备,在Linux中访问设备的方式和访问文件的方式是相同的/etc 这个目录用来存放所有的系统管理所需要的配置文件和子目录/home 用户的主目录,在Linux中,每个用户都有一个自己的目录,一般该目录名是以用户的账号命名的/lib 这个目录里存放着系统最基本的动态连接共享库,其作用类似于Windows里的DLL文件。几乎所有的应用程序都需要用到这些共享库/lost+found 这个目录一般情况下是空的,当系统非法关机后,这里就存放了一些文件/media inux系统会自动识别一些设备,例如U盘、光驱等等,当识别后,linux会把识别的设备挂载到这个目录下。/mnt 系统提供该目录是为了让用户临时挂载别的文件系统的,我们可以将光驱挂载在/mnt/上,然后进入该目录就可以查看光驱里的内容了/opt 这是给主机额外安装软件所摆放的目录。比如你安装一个ORACLE数据库则就可以放到这个目录下。默认是空的/proc 这个目录是一个虚拟的目录,它是系统内存的映射,我们可以通过直接访问这个目录来获取系统信息。/root 该目录为系统管理员,也称作超级权限者的用户主目录/sbin s就是Super User的意思,这里存放的是系统管理员使用的系统管理程序/selinux  这个目录是Redhat/CentOS所特有的目录,Selinux是一个安全机制,类似于windows的防火墙,但是这套机制比较复杂,这个目录就是存放selinux相关的文件的/srv 该目录存放一些服务启动之后需要提取的数据/sys  这是linux2.6内核的一个很大的变化。该目录下安装了2.6内核中新出现的一个文件系统 sysfs 。/tmp 这个目录是用来存放一些临时文件的。/usr 这是一个非常重要的目录,用户的很多应用程序和文件都放在这个目录下,类似于windows下的program files目录。/usr/bin 系统用户使用的应用程序/usr/sbin 超级用户使用的比较高级的管理程序和系统守护程序/usr/src 内核源代码默认的放置目录。/var 这个目录中存放着在不断扩充着的东西,我们习惯将那些经常被修改的目录放在这个目录下。包括各种日志文件8. Linux中忘记密码!进入单用户模式更改一下root密码即可3 秒之内要按一下回车然后输入a在 末尾输入 (single s S)其中的一个,有一个空格最后按回车启动,启动后就进入了单用户模式了此时已经进入到单用户模式了,你可以更改root密码了。更密码的命令为 passwd9. Linux的远程登录ssh(putty mutty Secure CRT xshell)10. Linux 文件基本属性当为[ d ]则是目录当为[ - ]则是文件;若是[ l ]则表示为链接文档(link file); ln -s 源文件 连接文件11. 文件的权限chmod u+x filechmod u=wx filechmod 421 file12. Shell简介Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁Shell 既是一种命令语言,又是一种程序设计语言Shell 是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务13. Shell脚本Shell 脚本(shell script),是一种为 shell 编写的脚本程序。14. Shell 环境编辑器+解释器解释器 ...

June 14, 2019 · 2 min · jiezi

Shell-输入输出重定向

Linux学习路线:阿里云大学——开发者课堂大多数 UNIX 系统命令从你的终端接受输入并将所产生的输出发送回到您的终端。一个命令通常从一个叫标准输入的地方读取输入,默认情况下,这恰好是你的终端。同样,一个命令通常将其输出写入到标准输出,默认情况下,这也是你的终端。 输出重定向重定向一般通过在命令间插入特定的符号来实现。特别的,这些符号的语法如下所示: command1 > file1上面这个命令执行command1然后将输出的内容存入file1。注意任何file1内的已经存在的内容将被新内容替代。如果要将新内容添加在文件末尾,请使用>>操作符。 实例执行下面的 who 命令,它将命令的完整的输出重定向在用户文件中(users): $ who > users执行后,并没有在终端输出信息,这是因为输出已被从默认的标准输出设备(终端)重定向到指定的文件。你可以使用 cat 命令查看文件内容: $ cat users_mbsetupuser console Oct 31 17:35 tianqixin console Oct 31 17:35 tianqixin ttys000 Dec 1 11:33输出重定向会覆盖文件内容,请看下面的例子: $ echo "阿里云大学:edu.aliyun.com" > users$ cat users阿里云大学:edu.aliyun.com$如果不希望文件内容被覆盖,可以使用 >> 追加到文件末尾,例如: $ echo "阿里云大学:edu.aliyun.com" >> users$ cat users阿里云大学:edu.aliyun.com阿里云大学:edu.aliyun.com$输入重定向和输出重定向一样,Unix 命令也可以从文件获取输入,语法为: command1 < file1这样,本来需要从键盘获取输入的命令会转移到文件读取内容。注意:输出重定向是大于号(>),输入重定向是小于号(<)。 实例接着以上实例,我们需要统计 users 文件的行数,执行以下命令: $ wc -l users 2 users也可以将输入重定向到 users 文件: $ wc -l < users 2注意:上面两个例子的结果不同:第一个例子,会输出文件名;第二个不会,因为它仅仅知道从标准输入读取内容。 ...

June 13, 2019 · 1 min · jiezi

实现简单的监控脚本Bash的执行和异常捕获

当我们需要监控服务运行状态时,一般的策略是写定时脚本,定时执行探测服务状态,如果出现预期外情况,就报警。那么第一步我们就需要学会写一个监控脚本,这里我们会讲到bash的执行环境和异常捕获,以及一些简单的全局参数。 示例先看一段shell代码,这个监控脚本会时刻监控我们的mysql进程是否正常服务,每2分钟执行一次: #!/bin/bash#设置异常的捕获和退出set -eset -o pipefailset -u#获取当前脚本执行的命令和路径#self_name=`readlink -f $0`#self_path=`dirname $self_name`set +e# 脚本主体mysql_process_num=`ps aux | grep mysql | grep -v grep | grep -v bash | wc -l`set -e# 判断脚本输出,此处0为异常if [ "$mysql_process_num" -ge 1 ];then echo "$mysql_process_num|proc_name=mysql"else echo "0|proc_name=mysql"fi脚本命令解析执行器#!/bin/bash首行表示此脚本使用/bin/sh来解释执行,#!是特殊的标识符,后跟此脚本解释器的路径。类似的还有/bin/sh, /bin/perl, /bin/awk等。 我们在使用bash执行脚本的时候,会创建一个新的Shell,这个Shell就是脚本的执行环境,并默认提供这个环境的各个参数。 异常捕获set -eset -o pipefailset -uset +e我们的Shell会给脚本提供默认的环境参数,但是我们也可以用set命令来修改运行参数。在官方手册里一共有十几个参数,我们介绍常用的四个参数。 如果我们直接在终端运行set,不带任何参数,会显示所有的环境变量和Shell函数。 开启和关闭参数我们常见的类似传参形式的set -e代表打开e代表的环境参数,相反的set +e代表关闭e代表的环境参数。 捕获单行异常当我们遇到一个异常,如操作不存在的变量或者一行指令执行出错(行指令返回值不为0),Bash会默认输出错误信息,然后忽略这行错误,继续执行。这在大部分场景下并不是开发者想要的行为,也不利于脚本的安全和Debug。我们应该在错误出现的时候输出错误信息并中断执行。这样能够防止错误被累计和放大。 # 可执行文件run#!/bin/bash# 调用未定义的命令fooecho bar# 执行该文件$ ./run./run: line 3: foo: command not foundbar可以看到输出了错误信息,并继续执行。 如果我们想保证单行如果出现错误,就中断执行脚本,可以有三种写法: # 方法一command || exit 1# 方法二if ! command; then exit 1; fi# 方法三commandif [ "$?" -ne 0 ]; then exit 1; fi上面的方法统一为判断一行指令返回值是否为0来判断异常。类似的,如果我们的多个命令有依赖关系,即后者的执行需要前者成功,则需要写: ...

June 11, 2019 · 2 min · jiezi

如何管理系统路由表

1 路由原理 从图示中可以看出:能够操作系统路由表的的有三个实体: 路由守护程序 routed路由命令 routenetstat命令其中,netstat命令只能读取路由信息无法直接对系统路由表进行操作。 增删路由表信息,只能由路由守护程序 routed与路由命令 route提供。两者的区别在于: 守护程序 routed提供动态路由管理功能,即通过实际网络状况操作动态路由信息。 路由命令 route 则提供了供系统管理员修改静态路由信息的接口。 下面分别就:linux系统与mac系统进行命令对比介绍。 2 路由表查询2.1 Linux# netstat $: netstat -rnKernel IP routing tableDestination Gateway Genmask Flags MSS Window irtt Iface0.0.0.0 172.16.15.253 0.0.0.0 UG 0 0 0 eth0169.254.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0...# ip route$: ip route listdefault via 172.16.15.253 dev eth0169.254.0.0/16 dev eth0 scope link metric 1002172.16.0.0/20 dev eth0 proto kernel scope link src 172.16.5.102...ip 命令是一个非常强大网络管理命令,不仅仅是操作路由表。更多功能请参阅 man ip 或者 tldr ip 。 ...

June 11, 2019 · 2 min · jiezi

一文读懂链路追踪

背景介绍在微服务横行的时代,服务化思维逐渐成为了程序员的基本思维模式,但是,由于绝大部分项目只是一味地增加服务,并没有对其妥善管理,当接口出现问题时,很难从错综复杂的服务调用网络中找到问题根源,从而错失了止损的黄金时机。 而链路追踪的出现正是为了解决这种问题,它可以在复杂的服务调用中定位问题,还可以在新人加入后台团队之后,让其清楚地知道自己所负责的服务在哪一环。 除此之外,如果某个接口突然耗时增加,也不必再逐个服务查询耗时情况,我们可以直观地分析出服务的性能瓶颈,方便在流量激增的情况下精准合理地扩容。 链路追踪“链路追踪”一词是在2010年提出的,当时谷歌发布了一篇Dapper论文,介绍了谷歌自研的分布式链路追踪的实现原理,还介绍了他们是怎么低成本实现对应用透明的。 其实Dapper一开始只是一个独立的调用链路追踪系统,后来逐渐演化成了监控平台,并且基于监控平台孕育出了很多工具,比如实时预警、过载保护、指标数据查询等。 除了谷歌的dapper,还有一些其他比较有名的产品,比如阿里的鹰眼、大众点评的CAT、Twitter的Zipkin、Naver(著名社交软件LINE的母公司)的pinpoint以及国产开源的skywalking等。 基本实现原理如果想知道一个接口在哪个环节出现了问题,就必须清楚该接口调用了哪些服务,以及调用的顺序,如果把这些服务串起来,看起来就像链条一样,我们称其为调用链。 想要实现调用链,就要为每次调用做个标识,然后将服务按标识大小排列,可以更清晰地看出调用顺序,我们暂且将该标识命名为spanid。 实际场景中,我们需要知道某次请求调用的情况,所以只有spanid还不够,得为每次请求做个唯一标识,这样才能根据标识查出本次请求调用的所有服务,而这个标识我们命名为traceid。 现在根据spanid可以轻易地知道被调用服务的先后顺序,但无法体现调用的层级关系,正如下图所示,多个服务可能是逐级调用的链条,也可能是同时被同一个服务调用。 所以应该每次都记录下是谁调用的,我们用parentid作为这个标识的名字。 到现在,已经知道调用顺序和层级关系了,但是接口出现问题后,还是不能找到出问题的环节,如果某个服务有问题,那个被调用执行的服务一定耗时很长,要想计算出耗时,上述的三个标识还不够,还需要加上时间戳,时间戳可以更精细一点,精确到微秒级。 只记录发起调用时的时间戳还算不出耗时,要记录下服务返回时的时间戳,有始有终才能算出时间差,既然返回的也记了,就把上述的三个标识都记一下吧,不然区分不出是谁的时间戳。 虽然能计算出从服务调用到服务返回的总耗时,但是这个时间包含了服务的执行时间和网络延迟,有时候我们需要区分出这两类时间以方便做针对性优化。那如何计算网络延迟呢?我们可以把调用和返回的过程分为以下四个事件。 Client Sent简称cs,客户端发起调用请求到服务端。Server Received简称sr,指服务端接收到了客户端的调用请求。Server Sent简称ss,指服务端完成了处理,准备将信息返给客户端。Client Received简称cr,指客户端接收到了服务端的返回信息。 假如在这四个事件发生时记录下时间戳,就可以轻松计算出耗时,比如sr减去cs就是调用时的网络延迟,ss减去sr就是服务执行时间,cr减去ss就是服务响应的延迟,cr减cs就是整个服务调用执行的时间。 其实span块内除了记录这几个参数之外,还可以记录一些其他信息,比如发起调用服务名称、被调服务名称、返回结果、IP、调用服务的名称等,最后,我们再把相同spanid的信息合成一个大的span块,就完成了一个完整的调用链。感兴趣的同学可以去深入了解一下链路追踪,希望本文对你有所帮助。

June 7, 2019 · 1 min · jiezi

php-shell-编程

说明脚本文件为: phpClilinux文件路径: /usr/local/bin/phpCli (需要可执行权限 chmod +x phpCli)linux执行: phpCliwindow执行: php phpCli 1.hash-bang 声明 #!/usr/local/bin/php -Cq针对 linux 使用声明,将脚本放置 linux 系统 默认shell执行位置 /usr/local/bin文件名(一般无后缀)就是命令名称 phpCli 对应执行命令为 /usr/local/bin/php -Cq /usr/local/bin/phpCli 参数脚本操作比较大时建议 用后即焚 (关闭文件操作符,清空数组,关闭连接等)2.基本参数var_dump($argv);/*array(2) { [0]=> string(6) "phpCli" [1]=> string(4) "test"}*/运行:phpCli test ; cli 模式下,参数会保存在$argv中. 3.用户输入print 'please input something !'."\n";$message = trim(fgets(STDIN));var_dump($message);//test标准输入在 PHP流的 STDIN 中,或者 unix风格的 '终端输入' 设备 /dev/tty 中获得.运行:phpCli 会得到提示语 please input something ! .输入信息 test ,var_dump($message)会输出 test . 4.解析命令行选项//这里使用了自定义switch ('test'){ case '-m': $this->shell = 'php -m'; break; case '-v': echo $this->command.' 1.0.1-dev (cli)'; $this->putFormat(true); break; case '-h': case '-help': $this->help(); break; default: $this->help(); break;}PEAR 提供了 Console_Getopt包可以同时支付简短和长格式(GNU风格)的选项.默认是与PHP绑定安装的,除非你关闭了PEAR .也可以自行定义 . ...

June 4, 2019 · 2 min · jiezi

Shell-函数

详细Shell课程:阿里云大学——开发者课堂linux shell 可以用户定义函数,然后在shell脚本中可以随便调用。shell中函数的定义格式如下: [ function ] funname [()]{ action; [return int;]}说明:1、可以带function fun() 定义,也可以直接fun() 定义,不带任何参数。2、参数返回,可以显示加:return 返回,如果不加,将以最后一条命令运行结果,作为返回值。 return后跟数值n(0-255下面的例子定义了一个函数并进行调用: #!/bin/bash# author:阿里云大学# url:edu.aliyun.comdemoFun(){ echo "这是我的第一个 shell 函数!"}echo "-----函数开始执行-----"demoFunecho "-----函数执行完毕-----"输出结果: -----函数开始执行-----这是我的第一个 shell 函数!-----函数执行完毕-----下面定义一个带有return语句的函数: #!/bin/bash# author:阿里云大学# url:edu.aliyun.comfunWithReturn(){ echo "这个函数会对输入的两个数字进行相加运算..." echo "输入第一个数字: " read aNum echo "输入第二个数字: " read anotherNum echo "两个数字分别为 $aNum 和 $anotherNum !" return $(($aNum+$anotherNum))}funWithReturnecho "输入的两个数字之和为 $? !"输出类似下面: 这个函数会对输入的两个数字进行相加运算...输入第一个数字: 1输入第二个数字: 2两个数字分别为 1 和 2 !输入的两个数字之和为 3 !函数返回值在调用该函数后通过 $? 来获得。注意:所有函数在使用前必须定义。这意味着必须将函数放在脚本开始部分,直至shell解释器首次发现它时,才可以使用。调用函数仅使用其函数名即可。 函数参数在Shell中,调用函数时可以向其传递参数。在函数体内部,通过 $n 的形式来获取参数的值,例如,$1表示第一个参数,$2表示第二个参数...带参数的函数示例: ...

May 31, 2019 · 1 min · jiezi

开源运维自动化平台opendevops

开源运维自动化平台-opendevops简介官网 | Github | 在线体验 CODO是一款为用户提供企业多混合云、自动化运维、完全开源的云管理平台。 CODO前端基于Vue iview开发、为用户提供友好的操作界面,增强用户体验。 CODO后端基于Python Tornado开发,其优势为轻量、简洁清晰、异步非阻塞。 CODO开源多云管理平台将为用户提供多功能:ITSM、基于RBAC权限系统、Web Terminnal登陆日志审计、录像回放、强大的作业调度系统、CMDB、监控报警系统、DNS管理、配置中心等 产品架构 产品功能 Demo我们提供了Demo供使用者体验,可点击Try Online Demo快速进行体验。 <img src="https://img.alicdn.com/tfs/TB...; width="180" /> 地址:http://demo.opendevops.cn/login用户:demo密码:2ZbFYNv9WibWcR7GB6kcEY 开始使用注意:由于是微服务部署比较复杂,我们目前只支持分布式一步步部署,depoly.sh暂不更新,后续会提供其余快速部署方式,请知悉。官方文档更新日志快速体验分布式部署文档模块链接CODO 项目我们是使用模块化、微服务化,以下为各个模块地址,同时也欢迎业界感兴趣各位大佬前来贡献前端代码:codo管理后端:codo-admin定时任务:codo-cron任务调度:codo-task资产管理:codo-cmdb配置中心:codo-kerrigan运维工具:codo-tools域名管理:codo-dns功能截图

May 27, 2019 · 1 min · jiezi

OCLint-实现-Code-Review-给你的代码提提质量

工程代码质量,一个永恒的话题。好的质量的好处不言而喻,团队成员间除了保持统一的风格和较高的自我约束力之外,还需要一些工具来统计分析代码质量问题。 本文就是针对 OC 项目,提出的一个思路和实践步骤的记录,最后形成了一个可以直接用的脚本。如果觉得文章篇幅过长,则直接可以下载脚本 OCLint is a static code analysis tool for improving quality and reducing defects by inspecting C, C++ and Objective-C code and looking for potential problems ...从官方的解释来看,它通过检查 C、C++、Objective-C 代码来寻找潜在问题,来提高代码质量并减少缺陷的静态代码分析工具 OCLint 的下载和安装有3种方式安装,分别为 Homebrew、源代码编译安装、下载安装包安装。区别: 如果需要自定义 Lint 规则,则需要下载源码编译安装如果仅仅是使用自带的规则来 Lint,那么以上3种安装方式都可以1. Homebrew 安装在安装前,确保安装了 homebrew。步骤简单快捷 brew tap oclint/formulae brew install oclint2. 安装包安装进入 OCLint 在 Github 中的地址,选择 Release。选择最新版本的安装包(目前最新版本为:oclint-0.13.1-x86_64-darwin-17.4.0.tar.gz)解压下载文件。将文件存放到一个合适的位置。(比如我选择将这些需要的源代码存放到 Document 目录下)在终端编辑当前环境的配置文件,我使用的是 zsh,所以编辑 .zshrc 文件。(如果使用系统的终端则编辑 .bash_profile 文件) OCLint_PATH=/Users/liubinpeng/Desktop/oclint/build/oclint-releaseexport PATH=$OCLint_PATH/bin:$PATH将配置文件 source 一下。 source .zshrc // 如果你使用系统的终端则执行 soucer .bash_profile验证是否安装成功。在终端输入 oclint --version3. 源码编译安装homebrew 安装 CMake 和 Ninja 这2个编译工具 ...

May 26, 2019 · 6 min · jiezi

shell输出与终端宽度相同的重复字符

来自我的笔记 我们有时候希望输出与当前终端宽度相等(或成正比)的重复字符,一般用作分隔、提示等,说白了就是好看或易于辨识一点点,例如使用yum安装软件时的那一排=,总是刚好排满一行,不会多不会少 Dependencies Resolved=============================================================================== Package Arch Version Repository Size===============================================================================Reinstalling: vim-enhanced x86_64 2:7.4.160-5.el7 os 1.0 MTransaction Summary===============================================================================Reinstall 1 Package这个功能的实现的两个重点: 获取到当前终端的“宽度”重复输出刚好填满一行的字符获取终端的“宽高”(列数和行数)终端以单个字符为基本“单位”,终端中一行能输入多少个字符,该行就能划分成多少列(columns),也就是该行有多“宽”,“高度”亦同,即当前终端能划分成多少行(lines)。我们可以使用以下方法获取终端的列数(宽)和行数(高): $COLUMNS和LINES内置变量tput cols和tput linesstty size(输出两个数字,以空格分开,前面为行数--高,后面为列数-宽)重复输出同一个字符串这里我们以单个字符=为例,实现输出10个连续的=即==========重复输出一个字符 使用printf s=$(printf "%-10s" "=")echo -e "${s// /=}"#或#sed "s/ /=/g"#printf "%-10s" "="|sed "s/ /=/g"prints前面的10表示占用10个字符宽度,-表示左对齐(没有该符号表示右对齐),%s不必说,就是很多语言中的占位符号,s表示string类型(不过把宽度10写到里面真是。。。)因此print语句就是占用10个字符的宽度,以=字符串填充,不过只有一个=因此实际上是1个+9个空格占位= 再将9个空格替换成= 使用seq seq作用是连续输出指定的数字,用法: seq [选项]... 尾数seq [选项]... 首数 尾数seq [选项]... 首数 增量 尾数默认的,seq以\n为分隔符,每行输出一个数字,如果不指定首数,则首数为1,如果不指定增量,则增量也为1。 seq 3 #这里只写了一个数字,则改数字就被当作尾数 也就是终止的数字输出 123 seq -s "=" 10|sed -E "s/[0-9]//g"seq以=为分隔符生成与终端宽度字符数量相等的数字(形如1=2=3=4)sed正则匹配所有数字并替换为空字符串。因此输出文章开头举例的那种一行=也就容易了: #使用sed+printprintf "%-${COLUMNS}s" "="|sed "s/ /=/g"#使用seq+sed seq -s "=" ${COLUMNS}|sed -E "s/[0-9]//g"

May 24, 2019 · 1 min · jiezi

干货-京东云托管Kubernetes集成镜像仓库并部署原生DashBoard

1. 京东云Kubernetes介绍随着Docker技术的发展和广泛流行,云原生应用和容器调度管理系统也成为IT领域大热的词汇。事实上,云原生应用的思想,在Docker技术火爆之前,已经由云计算技术的领导者和分布式系统架构的推广者广泛传播,例如云原生应用的12要素早在2011年就由Heroku的工程师提出了;只不过以虚拟机技术作为云原生应用的基础实施,由于虚拟机镜像大、镜像标准不统一以及打包流程和工具不统一,无法业界广泛接受的云原生应用标准,限制了云原生应用的流行。而Docker的出现正好解决了这些限制云原生应用构建、交付和运行的瓶颈,使得构建云原生应用成为了使用Docker的开发者自然而然的选择。单机的Docker引擎和单一的容器镜像只能解决单一服务的打包和测试问题。而要运行生产级的企业级应用,就需要容器调度管理系统。在这里面,Docker技术就仿佛运送系统零件的集装箱,把云原生应用的各个标准化零件交付到各个企业的不同码头,而容器调度管理系统就是企业应用的运行车间,把不同的零件组装、运行、维护起来。 Kubernetes是为生产环境而设计的容器调度管理系统,对于负载均衡、服务发现、高可用、滚动升级、自动伸缩等容器云平台的功能要求有原生支持。由于Kubernetes在K和s间有8个字母,因此常简称K8s。事实上,随着对K8s系统架构与设计理念的了解深入,我们会发现K8s系统正是处处为运行云原生应用而设计考虑;同时,随着对K8s系统使用的加深和加广,也会有越来越多有关云原生应用的设计模式产生出来,使得基于K8s系统设计和开发生产级的复杂云原生应用变得像启动一个单机版容器服务那样简单易用。 根据CNCF在2018年8月进行的第六次测量容器管理市场的温度,83%的受访者更喜欢Kubernetes的容器管理工具,58%的受访者在生产中使用Kubernetes,42%的受访者正在进行评估以备将来使用,40%的企业(员工规模在5000+)正在使用Kubernetes。Kubernetes在开发人员中已经变得非常流行。 京东云Kubernetes集群采用管理节点全托管的方式,为用户提供简单易用、高可靠、功能强大的容器管理服务。该产品完全兼容标准Kubernetes API ,集成京东云网络、存储等插件。Kubernetes集群服务简化了Kubernetes部署、管理,降低了Kubernetes使用门槛,增强应用的可靠性,提升开发的效率,减少资源投入成本。 1.1 产品优势相较于传统自建Kubernetes集群,京东云Kubernetes集群服务有如下优势: 易用性:在控制台一键式创建Kubernetes集群服务;管理节点采用全托管的方式,免除繁琐的部署、运维、升级等工作;提供工作节点定制镜像,预置集群工作节点所需的各种组件。可靠性:同地域下,集群的管理、工作节点可跨可用区部署,支持单集群至少运行三台云主机作为管理节点,同时基于京东云高可用组隔离故障域,进一步增强了可靠性。功能性:基于京东云SDN网络,提供CNI网络插件,依托京东云私有网络的高可用及可靠性,轻松适应不同规模生产环境的网络需求;提供CRI存储插件,集成京东云云硬盘,提供安全可靠的持久化存储;集成京东云负载均衡服务,提供安全、可靠的网络访问。性价比:京东云Kubernetes集群服务本身暂时免费,目前您只需为集群中创建的云主机、公网IP、云硬盘等云资源按需付费。1.2 京东云Kubernetes部署架构 下面会演示京东云Kubernetes集成京东云镜像仓库,构建原生dashboard的最佳实践,希望能起到抛砖引玉的作用。 2. 环境准备2.1 创建AK、SK登陆京东云控制台后,点击账号下拉菜单,选择Access Key管理。 点击创建,并输入相关手机号码。 至此AK、SK创建成功。 2.2 容器镜像仓库准备选择容器镜像仓库: 镜像仓库模板为:registry-URL/repository:tag,所以我们创建顺序为: 创建注册表创建仓库2.2.1 创建注册表点击创建按钮,后输入注册表名称,本例中的名称为:pocexam. 2.2.2 创建镜像仓库由于Kubernetes 官方dashboard 镜像kubernetes-dashboard-amd64为国外资源,国内无法pull,所以我们需要先从Google镜像仓库push到本地后再上传到镜像仓库。 此处创建镜像仓库时的名称为:kubernetes-dashboard-amd64。 2.2.3 上传Kubernetes-dashboard镜像此处需要创建一台Linux云主机(建议使用Ubuntu镜像),并安装Docker。此处不再赘述。通过ssh工具连接,执行如下命令安装Docker工具: apt-get install -y docker.io由于国内网络原因,Google官方镜像k8s.gcr.io/kubernetes-dashboard-amd64:v1.10.1无法pull,所以我们需要从docker.io仓库的Google容器镜像进行拉取: docker pull mirrorgooglecontainers/kubernetes-dashboard-amd64:v1.10.1然后执行docker images会看到拉取到的镜像。 上传至京东云镜像仓库之前,需要有上传权限,可以通过临时令牌的方式登录并上传镜像。获取临时令牌方法为:京东云控制台-->容器镜像仓库-->注册表,选择之前创建的registry,右侧点击获取临时令牌: 设置有效期: 确认后,可以获得多种格式的登陆方式,本次操作使用Docker客户端登录命令,点击复制按钮,并在Linux云主机中执行。 需要注意:完全复制粘贴到Linux shell 命令中即可,无需修改任何参数。 将k8s.gcr.io/kubernetes-dashboard-amd64:v1.10.1修改为$registry-URL/kubernetes-dashboard-amd64:v1.10.1,此处的registry-URL变量需要替换为你所创建的registry的值,或者可以在控制台获取到: 比如本次操作的值为pocexam-cn-north-1.jcr.service.jdcloud.com/kubernetes-dashboard-amd64,那么操作命令如下: docker tag mirrorgooglecontainers/kubernetes-dashboard-amd64:v1.10.1 pocexam-cn-north-1.jcr.service.jdcloud.com/kubernetes-dashboard-amd64:v1.10.1 && docker push !$修改tag并成功上传至京东云镜像仓库的截图如下: ...

May 23, 2019 · 4 min · jiezi

Linux生产环境上最常用的一套Sed技巧

sed命令应用广泛,使用简单,是快速文本处理的利器。它其实没多少技巧,背诵、使用是最合适的学习渠道,属于硬技能。但它又很复杂,因为高级功能太多。本篇不去关注sed的高级功能,仅对常用的一些操作,进行说明。 随着使用,你会发现它和vim的一些理念是想通的,正则表达式的语法也基本上一样,并没有多少学习成本。从个人视野和工作效率上来看,sed命令都是程序员必须掌握的一个重要工具。 那些说可以现场google用法的,大多习惯将文本拷贝到excel里,慢慢磨洋工,遇到大批量文件更是手忙脚乱。不是一家人不进一家门,本文不是为你写的。一个简单的入门如图,一个简单的sed命令包含三个主要部分:参数、范围、操作。要操作的文件,可以直接挂在命令行的最后。除了命令行,sed也可以通过-f参数指定一个sed脚本,这个属于高级用法,不做过多描述。 有些示例命令我会重复多次,聪明如你一定能发现其中规律,有时连解释都用不着。 参数-n 这个参数是--quiet或者--silent的意思。表明忽略执行过程的输出,只输出我们的结果即可。 我们常用的还有另外一个参数 :-i。 使用此参数后,所有改动将在原文件上执行。你的输出将覆盖原文件。非常危险,一定要注意。范围1,4 表示找到文件中1,2,3,4行的内容。这个范围的指定很有灵性,请看以下示例(请自行替换图中的范围部分)。 5 选择第5行。2,5 选择2到5行,共4行。 1~2 选择奇数行。 2~2 选择偶数行。 2,+3 和2,5的效果是一样的,共4行。 2,$ 从第二行到文件结尾。 范围的选择还可以使用正则匹配。请看下面示例。 /sys/,+3 选择出现sys字样的行,以及后面的三行。/^sys/,/mem/ 选择以sys开头的行,和出现mem字样行之间的数据。 为了直观,下面的命令一一对应上面的介绍,范围和操作之间是可以有空格的。 sed -n '5p' filesed -n '2,5 p' filesed -n '1~2 p' filesed -n '2~2 p' filesed -n '2,+3p' filesed -n '2,$ p' filesed -n '/sys/,+3 p' filesed -n '/^sys/,/mem/p' file操作最常用的操作就是p,意思就是打印。比如,以下两个命令就是等同的: cat file sed -n 'p' file除了打印,还有以下操作,我们来说常用的。 p 对匹配内容进行打印。d 对匹配内容进行删除。这个时候就要去掉-n参数了,想想为什么。 w 将匹配内容写入到其他地方。 ...

May 22, 2019 · 2 min · jiezi

替换n换行符为实际的n字符

shell下处理文件时,有时候有替换或去掉\n换行符号的需求。今天我遇到了将换行符号替换成实的\n字符的需求,有点绕,示例,一篇文章内容为: line1line2需要将其内容变成一行,所有换行符变成字符\n,如下: line1nline2如果直接用 sed -i "s/\n/\\\n/" #\\\n转义 为\n字样我们会发现替换不了,因为sed每次处理完毕一行后有自动添加一行(白忙活.jpg),如之奈何? 如果你sed技能熟练一点,知道分支和模式空间,这就好说啦: sed ":tag;N;s/\n/\\\n/;b tag" file #tag只是一个标签名随意是有点头大。说个容易懂的方法吧,利用echo不使用-e时自动去掉换行符的特点: echo $(sed "$ ! s/$/\\\n/" flie) > file$表示行匹配中的最后一行,$ !即使取反,表示不匹配最后一行;/$/不用说,学过正则就知道这是匹配行尾之意,这个命令意思是: 将行尾(出了最后一行)变成\n(注意这里是实际的字符\n,转义过了,没有换行符的特殊意义了)。于是有了: line1nline2sed帮倒忙给你加上\n换行符,于是有了: line1nline2echo输出自动去掉换行,于是有了line1\nline2当然,如果只想将换行符号换成空格,那就简单了echo $(cat file)即可。 参看我的笔记

May 22, 2019 · 1 min · jiezi

5G时代服务器如何管理

轰轰烈烈的5G时代拉开帷幕了,对于服务器运维人员来说,有新的市场就有新的领域,将因为5G的加入不一样了.所有的大数据,AI智能,工业4.0都建立在云服务器的管理配置下,只有好的一体化容器化的服务器支撑,才有刚需市场和人群,唯有新的设备或软件产生,才有市场和时代的进步.如果现在今天你还在运用古老的方式管理云服务器,有点过时而失去效率了.互联网大趋势就是带宽加大,硬件不断进步,2019年年中由于AMD在服务器处理器上开始布局7nm,服务器硬件将会实现非常便宜现象,不像现在被intel牢牢把控,一家独大,现在市场上一个intel 金牌服务器处理器便宜的一万人民币,贵的一万美金一颗,更不要考虑铂金或更高级的处理器,不过这样的时代将会过去,我们将迎来一个使用云端服务器就像菜市场买菜的时代.硬件一旦便宜,带宽资源加大,软件和服务将迎来新的变革和时代.服务商在这个十字路口就是最直接的受益者,最终的盈利和爆发,将是使用这些新技术的公司和个人.对于管理服务器,现在传统还在一个单机化操作,没有云端概念,被不少站长推上神坛的宝塔和WDCP这两个linux面板,都是属于古老的单机管理模式,而不是云端不是SAAS,只是一个古老的单机服务器软件,运维市场的进步是进步者和先驱者的,对于未来新的取代者来了,依托于平台SAAS化的旗鱼云梯,在这个新旧交替的阶段出生了,她将是运维云服务器市场的一把利剑.唯有新的变革方式,才是进步的标准,移动端下的管理服务器模式,将打破只能够通过传统pc的一种方式,新的设备新的环境,将诞生新的先驱者走上神坛.旗鱼云梯我预言将是新时代linux云端管理面板的领头羊,将是批量化集群化的代表,各种运维新方式和新模式将会诞生,收益的必然是使用者.总结:新的云服务器管理市场变化了,方式的变化将带来变革,旗鱼云梯将是个人和企业管理云服务器的一个极品工具.

May 18, 2019 · 1 min · jiezi

你必须知道的Git命令

这篇笔记是为了学习Git知识而收集总结的,主要是看受一篇帖子《你可能不知道的15条Git命令》的影响,才想记录这篇笔记的,如有雷同,纯属巧合。 Git 是一个分布式版本控制软件, 最初目的是为更好地管理Linux内核开发而设计。来源:维基百科 - Git Git是一个软件,它允许你通过提交对一个系统(或一组)文件的历史进行注释。这些提交便是在给定时间点对系统做出的差异“快照”。 官网下载速度慢,可使用这个链接下载 或者Github下载地址, 需要其他版本请提issue联系我。 1. Git 配置--system #系统级别--global #用户全局--local #单独一个项目git config --global user.name "xxxx" #用户名git config --global user.email "xxxx@xxx.com" #邮箱git config --list # 列举所有配置连接远程仓库github 创建SSH Key ssh-keygen -t rsa -C <youremail@example.com>登陆GitHub,打开Account settings -> SSH Keys -> Add SSH Key,填上任意Title,在Key文本框里粘贴id_rsa.pub文件的内容测试是否连接 ssh git@github.com几个概念: 工作区(Working Directory): 你在电脑里能看到的目录。 暂存区(stage / index): 保存了下次将提交的文件列表信息, 一般存放在 .git目录下 下的index文件(.git/index)中,所以我们把暂存区有时也叫作索引(index)。 版本库(Repository): 工作区有一个隐藏目录.git,这个不算工作区,而是Git的版本库。 远程仓库(Remote) 阮一峰老师对Git工作区、暂存区、版本库、远程仓库的解释 Runoob对Git工作区、暂存区、版本库、远程仓库的解释 忽略文件配置:添加.gitignore文件 文件 .gitignore 的格式规范如下: ...

May 9, 2019 · 4 min · jiezi

HTTP学习笔记

一、WWW概念WWW(World Wide Web),主要包括三部分概念URI,俗称网址HTTP,两个电脑之间传输内容的协议HTML,超级文本,主要用来做页面跳转解释:URL 的作用是能让你访问一个页面,HTTP 的作用是让你能下载这个页面,HTML 的作用是让你能看懂这个页面。 URI 是什么概念:统一资源标识符(英语:Uniform Resource Identifier,缩写URI)URI 分为 URL 和 URN,我们一般使用 URL 作为网址。 URN是什么概念:统一资源名称(英语:Uniform Resource Name,缩写URN) URL是什么概念:统一资源定位符(英语:Uniform Resource Locator,缩写URL) DNS是什么网域名称系统(英语:Domain Name System,缩写:DNS)是互联网的一项服务。它作为将域名和IP地址相互映射的一个分布式数据库,能够使人更方便地访问互联网。DNS使用TCP和UDP端口53[1]。当前,对于每一级域名长度的限制是63个字符,域名总长度则不能超过253个字符。 二、请求与响应2.1http作用HTTP 的作用就是指导浏览器和服务器如何进行沟通。浏览器负责发起请求服务器在 80 端口接收请求服务器负责返回内容(响应)浏览器负责下载响应内容 2.2请求示例Git Bash命令行执行后,请求内容为:-s显示进度-v完整的显示请求和响应-H添加请求头 curl -s -v -H "Frank: xxx" -- "https://www.baidu.com"【GET请求内容】GET / HTTP/1.1Host: www.baidu.comUser-Agent: curl/7.54.0Accept: */*Frank: xxxcurl -X POST -s -v -H "Frank: xxx" -- "https://www.baidu.com"【POST请求内容】POST / HTTP/1.1Host: www.baidu.comUser-Agent: curl/7.54.0Accept: */*Frank: xxxcurl -X POST -d "1234567890" -s -v -H "Frank: xxx" -- "https://www.baidu.com"【POST带数据请求内容】POST / HTTP/1.1Host: www.baidu.comUser-Agent: curl/7.54.0Accept: */*Frank: xxxContent-Length: 10Content-Type: application/x-www-form-urlencoded//注意此处是空行12345678902.3请求内容格式示例 ...

May 5, 2019 · 2 min · jiezi

Hadoop中间结果lzop压缩

为了节省磁盘空间,文件的存储往往需要压缩,有的需要压缩比大,有的需要压缩速度快。而对于一套计算的结果存储,如多个MapReduce之间,需要能支持分片的压缩方式。lzop就是个可以支持分片的压缩方式,非常适合用于多个MapReduce之间的计算中间结果存储。 一、在Hadoop上安装lzop与在hive上的使用https://www.iteblog.com/archi... 二、添加索引以支持分片lzop默认是不支持分片的,需要添加索引。https://www.iteblog.com/archi...

May 4, 2019 · 1 min · jiezi

linux-curl请求时参数被截断

当我在curl一个url时,发现在后端PHP环境使用xdebug时,只能捕获第一个参数: curl test.baidu.com/oss/index.php?r=info/data/query&username=xxx&password=xxx# 在后端url被截断,只能捕获到第一个参数$_GET: array(1) r: "info/data/query"这导致了我的认证失败,无法获取正确的数据。 其实这里的原因是在shell 命令中&符号有特殊的含义,而并不只是url参数的连接符。因此,我们有两种解决方法: # 方法一:转义,加上\符curl test.baidu.com/oss/index.php?r=info/data/query\&username=xxx\&password=xxx# 方法二:包装,在url外加上引号,用字符串处理curl 'test.baidu.com/oss/index.php?r=info/data/query&username=xxx&password=xxx'重新测试,解决问题。 参考资料Linux curl get请求参数多个参数被截断的解决方法:https://blog.csdn.net/top_cod...

April 28, 2019 · 1 min · jiezi

后端相关技能七脚本

批处理基本语法# 关闭单行回显@# 关闭命令回显(从下一行开始)echo off# 注释:: # 注释rem# 暂停pause# 重定向输出>>>

April 27, 2019 · 1 min · jiezi

运行shell脚本时进程数量变多

写了一个很简单的脚本,用于统计memcache进程的数量: #!/bin/bashecho `ps aux | grep memcache | grep -v grep | wc -l`然而在执行时却遇到了问题: [work@ oss_memcache_status]$ pwd/home/work/cdn/monitor/ocelot-scripts/oss_memcache_status[work@ oss_memcache_status]$ ./run.sh1[work@ oss_memcache_status]$ ../oss_memcache_status/run.sh3这个原因是因为我们在执行shell脚本时,会通过子进程的方式来执行,因此统计数量比预期要多。解决方案为grep -v bash。 执行shell脚本的方式我们有三种常用的方式执行shell脚本: source run.sh: 会在当前进程下执行脚本,执行时的变量会保存下来。. run.sh: 和source方法基本一样,区别在于source不是POSIX要求的。./run.sh: 如果脚本以#!/bin/bash开头,会在单独的子进程中执行,执行完毕后变量不保存。否则和source一样。因此,在上面的脚本中,我们在执行时,因为是以#!/bin/bash开头,会在子进程中执行,我们改动一下脚本看都是哪些进程: #!/bin/bashecho `ps aux | grep memcache | grep -v grep`执行: work 24414 0.0 0.0 108116 1276 pts/0 S+ 15:31 0:00 /bin/bash ../oss_memcache_status/run.shwork 24415 0.0 0.0 108116 612 pts/0 S+ 15:31 0:00 /bin/bash ../oss_memcache_status/run.shwork 30558 0.0 0.0 371236 47096 ? Ssl 2016 15:14 /usr/local/bin/memcached -d -m 256 -u nobody -l localhost -p 11211我们通过结果,可以看出来,第一个进程和第二个进程的父进程相同,他们都属于当前终端启动的进程。前两个分别为执行run脚本的进程和调起的子进程(这两个什么区别,我也不太清楚),第三个为真正的进程。 ...

April 25, 2019 · 1 min · jiezi

将你的前端应用打包成docker镜像并部署到服务器仅需一个脚本搞定

1.前言前段时间,自己搞了个阿里云的服务器。想自己在上面折腾,但是不想因为自己瞎折腾而污染了现有的环境。毕竟,现在的阿里云已经没有免费的快照服务了。要想还原的话,最简单的办法就是重新装系统。而一旦重装,之前的搭建的所有环境就都白搭了。 再加上之前本身就想引入docker,所以就打算利用docker容器来部署这次的前端应用。 2.构建前端应用在打包之前,首先需要一个可正常运行的前端应用。这个可以使用umi或者create-react-app来构建。 3.nginx的默认配置文件然后需要在项目中加上默认nginx配置文件。 server { listen 80; server_name localhost; location / { root /usr/share/nginx/html; index index.html index.htm; try_files $uri $uri/ /index.html; }}4.编写本地构建脚本4.1. 移除上次的目录和Dockerfile#!/bin/bashif [ -d "./dist" ]; then rm -rf ./distfiif [ -f "./Dockerfile" ]; then rm -f ./Dockerfilefi因为每次更改后dist中的内容肯定与之前不同,其实这一步显得不是那么必要。运行npm的打包命令也会自动清楚该目录。 而清除Dockerfile则是为了防止更新了Dockerfile,而这次却不能得到最新的配置。 4.2. 打包前端应用执行前端的打包命令,生成静态文件目录。 yarn build4.3. 生成Dockerfileecho "FROM nginx:latest" >> ./Dockerfileecho "COPY ./dist /usr/share/nginx/html/" >> ./Dockerfileecho "COPY ./default.conf /etc/nginx/conf.d/" >> ./Dockerfileecho "EXPOSE 80" >> ./DockerfileFROM制定了该定制容器的基础镜像为nginx:latest;COPY命里将打包好的静态文件目录复制到容器内的/usr/share/nginx/html/目录下,然后将nginx的配置写入容器中对应的位置; EXPOSE则是设置对外暴露容器的80端口。 4.4. 生成并推送定制imagedocker build -t detectivehlh/mine .docker login -u detectivehlh -p ********docker push detectivehlh/mine这里是在开发本地,使用docker命令来打包,所以该脚本对docker有强依赖。build命令表示打包docker应用的,-t选项则制定了docker镜像的名字和tag,tag会默认为latest。 ...

April 23, 2019 · 2 min · jiezi

早些时候的shell笔记

一、shell简介 1.常见的shell bash: linux标准shell sh: 早起shell csh: ksh tcsh Unix shell vi: /etc/shells linux支持的shell 2.编写运行 #!/bin/bash echo "helloworld!" wq hello.sh chmod 755 ./hello.sh ./hello.sh 3.常见命令 1).历史命令 history /etc/profile 是linux的环境变量文件。注销才能使改变生效 HISTSIZE 属性指示可以保存的历史记录条数 历史命令保存在~/.bash_history history -w 把内存中的命令保存到文件 history -c 清空历史命令 !+历史命令的行号 执行该条命令 !+字符串 执行以该字符串开头的最近执行的历史命令 2).别名 alias alias ls='ls --color=never' 手工设定别名 ~/bashrc 是linux的环境变量文件,其中可以配置命令别名 4.输入输出重定向 标准输入 /dev/stdin 0 键盘 标准输出 /dev/stdout 1 显示器 标准错误输出 /dev/stderr 2 显示器 #设备文件名 #文件描述 #默认设备 1).输出重定向 > 覆盖 ls > aa >> 追加 ls >> aa ls zzzzz 2>>aa 错误信息输出到aa (注意:错误输出不能有空格) ls zzzzz &>aa 正确和错误的信息都输出到aa (注意:只能覆盖不能追加) ls zzzzz >>aa 2>>bb 正确的信息输出到aa,错误的信息输出到bb ls zzzzz >>a 2>&1 错误和正确信息都输出到aa,可以追加 2>&1 把标准错误重定向到标准正确输出 2).多命令的顺序执行 命令1; 命令2; 命令3; 命令1、2、3顺序依次执行,之间没有任何关系 命令1 && 命令2 命令1正确执行后命令2才会执行 命令1 || 命令2 命令1不正确执行命令2才会执行 ls && echo "yes" || ehco "no" 可以做简单的条件测试 命令1 | 命令2 命令1的执行结果作为命令2的执行条件或者操作对象。没有输出的命令不能作为第一条命令 netstat -tlun | grep 80 该命令用于查看端口是否开启 netstat -tlun 查看端口监听状态,grep 80 提取其中有80字样的内容。(管道符:将前者的结果作为后者的操作对象)二、变量 ...

April 22, 2019 · 9 min · jiezi

Bash脚本编程之算数扩张

算数扩张(Arithmetic Expansion)。通过使用反引号,双括号和let命令可以将字符串转换为数字表达式。 使用反引号通常和expr结合使用: z=`expr $z + 3`使用双括号((...))或$((...))双括号中的变量引用符号$可以省略。 z=$(($z+3))# 等同于z=$((z+3)) ((n=$n+1))# 等同于((n=n+1))# 等同于((n+=1)) # 但(($n+=1))会报错使用let命令let命令中的变量引用符号$可以省略。使用引号允许在let表达式中使用空格符号: let z=z+3let "z = z + 3"

April 21, 2019 · 1 min · jiezi

Bash脚本编程之数组

声明数组declare -a array_name 数组初始赋值array_name[xx]=value 其中xx表示下标,为大于等于0的整数数字array_name=([xx]=value1 [yy]=value2 ...)其中xx表示下标,为大于等于0的整数数字array_name=(value1 value2 value3 ...)或declare -a array_name=(value1 value2 value3 ...)数组追加元素array=( "${array[@]}" "new element" )或array[${#array[*]}]="new element" 复制数组array2=( "${array1[@]}" )或array2="${array1[@]}" 获取单个、全部或连续的部分数组元素${array_name[xx]}获取下标为xx的单个元素${array_name[@]}或${array_name[*]}获取所有元素。在有引号括起的情况下,"${array_name[@]}"表示单独的数组元素,"${array_name[*]}"表示数组元素整体,没有引号括起的情况下都表示单独的数组元素,类似$*和$@的区别${array_name[@]:index:length}获取连续的部分数组元素,其中:length可省略。 arrayZ=( one two three four five )# 提取所有元素echo ${arrayZ[@]:0} # one two three four five# 提取下标从1开始(包含)的所有元素echo ${arrayZ[@]:1} # two three four five# 提取下标从1开始(包含)的2个元素echo ${arrayZ[@]:1:2} # two three获取数组元素个数${#array_name[*]}或${#array_name[@]} 获取数组某个元素的字符串长度${#array_name[xx]} 提取数组中某个元素的部分字符串${array_name[xx]:index:length}, 其中:length可省略 删除数组或数组元素unset array_name[xx]删除下标为xx的数组元素,等同于array_name[xx]=unset array_name删除整个数组数组元素的字符串替换/删除操作通常情况下,形如${name...}表示法的字符串操作都可以应用在数组上,使用${name[@]...}或${name[*]...}的方式。 子字符串移除 arrayZ=( one two three four five five )# 从每个元素的最左侧进行最短匹配,并删除匹配的字符串echo ${arrayZ[@]#fiv} # one two three four e eecho ${arrayZ[@]#t*e} # one two e four five five# 从每个元素的最左侧进行最长匹配,并删除匹配的字符串echo ${arrayZ[@]##t*e} # one two four five five# 从每个元素的最右侧进行最短匹配,并删除匹配的字符串echo ${arrayZ[@]%h*e} # one two t four five five# 从每个元素的最右侧进行最长匹配,并删除匹配的字符串echo ${arrayZ[@]%%t*e} # one two four five five子字符串替换 ...

April 21, 2019 · 1 min · jiezi

Bash脚本编程之引用

引用的意思是用引号括起一个字符串,以保护字符串中的特殊字符不被shell或shell脚本重新解释或扩展: # 在通配和正则模式中拥有特殊含义的*号在引用中失去了特殊意义bash$ ls -l [Vv]*-rw-rw-r-- 1 bozo bozo 324 Apr 2 15:05 VIEWDATA.BAT -rw-rw-r-- 1 bozo bozo 507 May 4 14:25 vartrace.sh -rw-rw-r-- 1 bozo bozo 539 Apr 14 17:11 viewdata.shbash$ ls -l '[Vv]*'ls: [Vv]*: No such file or directory但某些程序会重新解释或扩展引号括起的字符串中的特殊字符。比如某些场景下引号的用途是保护shell命令参数,但仍然允许调用程序扩展特殊字符: bash$ cat file1.txtfirst name in file1.txtbash$ cat file2.txtFirst name in file2.txtbash$ grep '[Ff]irst name' *.txtfile1.txt:first name in file1.txtfile2.txt:First name in file2.txt引用变量引用变量时,通常建议用双引号括起。这可以防止重新解释引用字符串中除$, `, \外的所有特殊字符。 使用双引号可以防止单词拆分,用双引号括起的参数即使包含空格也将视为一个整体: List="one two three"for a in $List # 空格拆分变量为多个部分do echo "$a"done# one# two# threeecho "---"for a in "$List" # 双引号括起变量视为一个整体do echo "$a"done# one two three一个更详细的例子: ...

April 21, 2019 · 1 min · jiezi

跟着360架构师学shell

变量替换${变量名#匹配规则} 从头开始匹配,最短删除${变量名##匹配规则} 从头开始匹配,最长删除${变量名%匹配规则} 从尾开始匹配,最短删除${变量名%%匹配规则} 从尾开始匹配,最长删除${变量名/旧字符串/新字符串} 替换旧的字符串为新字符串,只替换第一个${变量名//旧字符串/新字符串} 替换旧的字符串为新字符串,替换所有例:variable_1=“i love u, do you love me"echo ${variable_1#ov}# e u, do you love meecho ${variable_1##ov}# e meecho ${variable_1%ov}# i love u, do you lecho ${variable_1%%ov}# i lecho ${variable_1/ov/bb}# i lbbe u, do you love mevariable_1=“i love u, do you love me"variable_2=${variable_1/ov/bb}echo $variable_2# i lbbe u, do you lbbe me2. 字符串处理2.1 获取字符串长度${#string}expr length “$string"例:variable_1=“i love u, do you love me"echo ${#variable_1}expr length “$variable_1"len=expr length "$variable_1"echo $len2.2 获取子串在字符串中的索引位置expr index “$string” “$substring” [不是子串,而是子串切分成单个字符,查找第一个出现的字符的位置]例:variable_1=“i love u, do you love me"variable_2=“ov"expr index “$variable_1” “$variable_2”# 4variable_2=“ok"expr index “$variable_1” “$variable_2”# 42.3 获取子串长度expr match “string substring” [必须从头开始匹配,能匹配到的子串返回长度,支持正则]例:variable_1=“quickstart is a app"echo expr match "$variable_1" app# 0echo expr match "$variable_1" quick# 5echo expr match "$variable_1" quick.# 6echo expr match "$variable_1" quick.*# 192.4 子串抽取${string:position} 从string的position位置开始${string:position:length} 从position位置开始抽取length长度${string:-position} 从右边开始匹配${string:(position)} 从左边开始匹配expr substr “$string” “$position” “$length” 从position位置开始抽取length长度,索引从0开始注意:${string:position}索引从1开始,而 expr 索引从0开始例:variable_1=“i love u, do you love me"position=4length=4echo ${variable_1:position}# ve u, do you love meecho ${variable_1:position:length}# ve uecho ${variable_1: -position}# e meecho ${variable_1:(-position)}# ve u, do you love meecho ${variable_1:(-position)}# e mevariable_2=expr substr "$variable_1" "$position" "$length"echo $variable_2# ove3. 字符串练习string=“bigdata process framework is hadoop, hadoop is an open source project"执行脚本后,打印输出string字符串变量,并给出用户以下选项:(1) 打印string长度(2) 在整个字符串中删除Hadoop(3) 替换第一个Hadoop为Mapreduce(4) 替换全部Hadoop为Mapreduce用户输入对应的数字会执行相应的功能,输入q|Q退出操作#!/bin/bashstring=“Bigdata process framework is Hadoop,Hadoop is an open source project"function print_tips { echo “” echo “ (1) 打印string长度” echo “ (2) 在整个字符串中删除Hadoop” echo “ (3) 替换第一个Hadoop为Mapreduce” echo “ (4) 替换全部Hadoop为Mapreduce” echo “"}function print_len { echo “${#string}"}function del_Hadoop { echo “${string//Hadoop/}"}function rep_Hadoop_to_Mapreduce_first { echo “${string/Hadoop/Mapreduce}"}function rep_Hadoop_to_Mapreduce_alll { echo “${string//Hadoop/Mapreduce}"}while truedo echo echo echo “【string=$string】” print_tips read -p “please input your choice(1|2|3|4|q|Q): " choice case $choice in 1) echo print_len ;; 2) echo del_Hadoop ;; 3) echo rep_Hadoop_to_Mapreduce_first ;; 4) echo rep_Hadoop_to_Mapreduce_alll ;; q|Q) exit ;; ) echo echo “error input!” ;; esacdone4. 命令替换command$(command)$(())主要用来进行整数运算,包括加减乘除例1:获取系统中的所有用户并输出(/etc/passwd)cat /etc/passwd | cut -d “:” -f 1#!/bin/bashindex=1for user in cat /etc/passwd | cut -d ":" -f 1do echo “this is $index user: $user” index=$(($index+1))done例2:根据系统时间计算今年、明年echo “this is $(date +%Y), next year is $(($(date +%Y)+1))“例3:根据系统时间获取今年还剩下多少个星期,已经过了多少个星期echo “今年已经过了$(date +%j)天,合$(($(date +%j) / 7))周,还剩下$(((365-$(date +%j)) / 7))周"例子4:判断nginx进程是否存在,不存在的话拉起该进程#!/bin/bashnginx_process_num=$(ps -ef | grep nginx | grep -v grep | wc -l)if [ $nginx_process_num -eq 0 ]; then systemctl start nginxfi5. 有类型变量declare、typeset-r 只读-i 整数-a 数组-f 在脚本中显示定义的函数和函数体-F 在脚本中显示定义的函数-x 环境变量如果要取消类型声明,减号变加号就行了例:declare -r variable_1=“hello java"variable_1=“abc"num1=10echo $num1+1declare -i num2=10declare -i num3num3=$num2+1echo $num2+1echo $num3declare -fdeclare -Farray=(“jane” “jone” “jack” “jordan”)输出数组内容 echo ${array[@]} 输出所有内容 echo ${array[0]} 输出下标对应的内容获取数组长度 echo ${#array} echo ${#array[0]}6. 数字运算expr $num1 operator $num2$(($num1 operator $num2))注意:expr只支持整型运算expr 操作符num1 | num2 num1不为空且不为0,返回num1,否则返回num2num1 & num2 num1不为空且不为0,返回num1,否则返回0num1 < num2 num1小于num2,返回1,否则返回0num1 <= num2 num1小于等于num2,返回1,否则返回0num1 = num2 num1等于num2,返回1,否则返回0num1 != num2 num1不等于num2,返回1,否则返回0num1 > num2 num1大于num2,返回1,否则返回0num1 >= num2 num1大于等于num2,返回1,否则返回0num1 + num2num1 - num2num1 * num2num1 / num2num1 % num2例:num1=10num2=20expr $num1 + $num2echo $(($num1 + $num2))expr $num1 | $num2expr $num1 &amp; $num2expr $num1 &gt; $num2expr $num1 &gt;= $num2expr $num1 &lt; $num2expr $num1 &lt;= $num2expr $num1 = $num2expr $num1 + $num2expr $num1 - $num2expr $num1 * $num2expr $num1 / $num2expr $num1 % $num2练习:提示用户输入一个正整数num,然后计算1+2+3+…+num的值,必须判断num是否为正整数,不符合允许再次输入#!/bin/bashsum=0while truedo read -p “please input: " num expr $num + 1 &> /dev/null if [ $? -eq 0 ]; then if [ expr $num \&gt; 0 -eq 1 ]; then for ((i=0;i<=$num;i++)) do sum=$(($sum + $i)) done echo $sum exit else echo “小于等于0” continue fi else echo “不是整数” continue fidone7. 函数定义和使用7.1 函数定义function name {}name() {}例:写一个nginx的守护脚本#!/bin/bashthis_pid=$$while truedo ps -ef | grep nginx | grep -v grep | grep -v $this_pid &> /dev/null if [ $? -eq 0 ]; then echo “nginx is running well!” sleep 3 else echo “starting!” systemctl nginx start sleep 1 fidone7.2 传递参数例:写一个脚本支持+-/四种运算#!/bin/bashfunction cal { case $2 in +) echo $(($1 + $3)) ;; -) echo $(($1 - $3)) ;; *) echo $(($1 * $3)) ;; /) echo $(($1 / $3)) ;; ) echo “error input!” ;; esac}cal $1 $2 $37.3 返回值return返回值,只能返回1-255之内的整数。使用return返回值,通常供其他地方调用获取状态,因此通常返回0或者1,0表示成功,1表示失败。return表示return 0echo返回值,可以返回任何字符结果,通常用于返回数据,比如一个字符串或列表值例:#!/bin/bashthis_pid=$$function is_nginx_running { ps -ef | grep nginx | grep -v grep | grep -v $this_pid &> /dev/null if [ $? -eq 0 ]; then return else return 1 fi}is_nginx_running && echo “nginx is running” || echo “nginx is down"sh -x nginx_stat.sh [-x可以查看执行过程]#!/bin/bashfunction get_user_list { users=$(cat /etc/passwd | cut -d “:” -f1) echo $users}index=1user_list=$(get_user_list)for u in $user_listdo echo “this is the $((index++)) user: $u"done7.4 变量使用local定义变量表示局部变量,否则一般的变量都是全局变量函数内部的变量如果跟外部变量同名,则函数内部的变量替换外部的变量7.5 函数库例:定义一个函数库,该函数库实现以下几个函数(1)加法函数 add(2)减法函数 reduce(3)乘法函数 multiple(4)除法函数 dived(5)打印系统运行情况的函数sys_load,该函数可以显示系统内存运行情况base_function.lib#!/bin/echofunction add { echo “expr $1 + $2"}function reduce { echo “expr $1 - $2"}function multiple { echo “expr $1 \* $2"}function divide { echo “expr $1 / $2"}function sys_load { echo “—memory info—” free -m echo echo “—disk info—” df -h}calculate.sh#!/bin/bash. /root/script/base_function.libadd 1 2reduce 11 33multiple 3 44divide 20 2sys_load库文件的后缀是任意的,但是一般以.lib使用库文件通常没有执行权限8. 常用查找命令8.1 find [路径] [选项] [操作]选项-name 根据名字-iname 根据名字,不区分大小写-perm 根据权限-prune 该选项可以排除某些查找目录-user 根据文件用主-group 根据文件属组-mtime -n|+n 根据文件更改时间,-n表示n天以内修改的文件,+n表示n天意外修改的文件-mmin -n|+n 根据文件更改时间,-n表示n分钟以内修改的文件,+n表示n分钟意外修改的文件-newer file1 ! file2 比file1新但是比file2旧的文件-type 根据文件类型 f-文件,d-目录,l-管道文件-size -n +n 根据文件大小-mindepth n 从n级子目录开始搜索-maxdepth n 最多搜索到n级子目录-a 与-o 或!|-not 非操作-print 默认操作-exec 对搜索到的文件执行特定操作,格式为 -exec command {} ; ,其中{}代表搜索到的文件,如:find . -name “.conf” -exec rm -rf {} ;-ok 跟-exec一样,只是每次操作都会给用户提示例:将/var/log目录下以log结尾,且更改时间在7天以上的删除find /var/log -name “log” -mtime +7 -exec rm -rf {} ;8.2 locate which whereislocate 不同于 find,find会查找整个磁盘,而locate命令会在数据库中查找,只能查找单个文件。可以用updatedb更新数据库文件,该文件是 /var/lib/mlocate/locate.dbwhereis -b,只返回二进制文件,-m,只返回帮助文档文件,-s,只返回源码文件which 只查找二进制文件9. grepgrep [option] [pattern] [file1,file2]command | grep [option] [pattern]参数-i 不区分大小写-v 反向选择-n 显示行号-r 递归-E 支持扩展正则表达式-F 不按正则表达式,按字符串字面匹配-x 匹配整行-w 匹配整词-c 只输出匹配到的总行数,不显示具体内容-l 只列出文件,不显示具体内容例:grep -E “python|PYTHON” fileegrep 和 grep -E 等价10. sed(stream editor缩写)10.1 sedsed [option] “pattern command” filestdout | sed [option] “pattern command” fileoption-n 只打印模式匹配行。sed -n “/python/p” sed.txt-e 直接在命令行编辑。sed -n -e “/PYTHON/p” -e “/python/p” sed.txt,多重处理的时候用-e连接-f 指定编辑处理的 pattern command 内容。sed -n edit.sed sed.txt,edit.sed中的内容是/python/p-r pattern支持扩展正则表达式。sed -n -r “/python|PYTHON/p” sed.txt-i 对源文件进行修改例:替换文件中love为likesed -n “s/love/like/g;p” sed.txtsed -i “s/love/like/g” sed.txtpattern10command 匹配第10行10,20command 匹配第10-20行10,+5command 匹配第10-16行/pattern1/command 匹配pattern1的行。sed -n “//spool//p” /etc/passwd,匹配带有/spool/的行。sed -n “/^daemon/p” /etc/passwd,匹配daemon开头的行/pattern1/,/pattern2/command 匹配pattern1到pattern2的行结束。sed -n “/^daemon/p” /etc/passwd10,/pattern1/command 从第10行开始匹配到第一个pattern1的行结束/pattern1/,10command 连续匹配10行command查询 p 打印增加 a 行后追加。sed -i “//bin/bash/a this user can login to system” passwd i 行前追加 r 外部文件读入,行尾追加 w 匹配行写入外部文件删除 d 删除不能登录的用户,sed -i “//sbin/nologin/d” passwd。删除从mail开头的行到ftp开头的行,sed -i “/^mail/,/^ftp/d” passwd 例:删除配置文件中的所有空行和注释行。sed -i “/^$/d;/[:blank:]#/d;/\t/d” nginx.conf,[:blank:]匹配空格,\t匹配tab 例:在配置文件中所有不以#开头的行前面添加符号(#开头的行不添加)。sed -i “s/^([^#])/*\1/g” nginx.conf 或者 sed -i “s/^[^#]/&/g” nginx.conf更改 s/old/new/ 将行内第一个替换 s/old/new/g 将行内所有替换 s/old/new/2 将行内第二个替换 s/old/new/2g 从第二个开始替换所有的 s/old/new/ig 忽略大小写 例:删掉所有的数字。sed -i “s/[0-9]+//g” sed.txt其它 = 显示行号。sed -n “//sbin/nologin/=” passwd10.2 反向引用& 和 1 引用模式匹配到的整个串(1的时候要替换的模式匹配中的串要用小括号包围起来)例:sed -i “s/had..p/&s/g” sed.txt 给能匹配到had..p的字符串后面加上s,hadoopx -> hadoopsxsed -i “s/ha(d..p)/XX\1/g” sed.txt 给能匹配到had..p的d..p之外的串全替换成上XX,hadoopx -> XXdoopx例:统计mysql配置文件各配置段的数量#!/bin/bashFILE_NAME=/root/script/my.cnffunction get_all_segament { sed -n ‘/[.]/p’ $FILE_NAME | sed -e “s/[//g” | sed -e “s/]//g” # 查找[开头]结尾的行,并且删除掉[和]}function get_all_segament_count { count=sed -n "/\[$1\]/,/\[.*\]/p" $FILE_NAME | grep -v "^#" | grep -v "^$" | grep -v "\[.*\]" | wc -l # 查找[$1]开头的行到发现[.]的行结束,去掉#开头和空行,并去掉[.]的行(即开头和结束的行),统计数量 echo $count}index=0for segament in $(get_all_segament)do index=expr $index + 1 count=get_all_segament_count $segament echo “$index: $segament $count"done输出:1: client 12: mysql 13: mysqld 64: mysqldump 311. awkawk ‘BEGIN{}pattern{commands}END{}’ file_namestdout | ‘BEGIN{}pattern{commands}END{}‘BEGIN{} 正式处理之前执行的pattern 匹配模式{commands} 执行命令(可能多行)END{} 处理完所有的匹配数据之后执行11.1 内置变量$0 整行内容$1-$n 本行中按照某个字符分隔后的第n个变量NF 当前行的字段个数,也就是列的个数(Number Field)NR 当前行的行号,从1开始计算(Number Row)FNR 多文件处理时,每个文件行号单独计数,都是从1开始(File Number Row)FS 输入字段分隔符,不输入默认是空格或者tab键分隔(Field Separator)RS 输入行分隔符。默认回车换行(Row Separator)OFS 输出字段分隔符。默认空格ORS 输出行分隔符。默认回车FILENAME 处理的文件名ARGC 命令行参数个数ARGV 命令行参数数组例:打印/etc/passwd文件的内容awk ‘{print $0}’ /etc/passwdawk ‘BEGIN{FS=”:”}{print $1}’ /etc/passwdawk ‘BEGIN{FS=”:”}{print NF}’ /etc/passwdawk ‘{print NR}’ /etc/passwd nginx.confawk ‘{print FNR}’ /etc/passwd nginx.confawk ‘BEGIN{RS=”–”}{print $0}’ test.txtecho “a-b-c–d-e-f–g-h-i” | awk ‘BEGIN{RS=”–";FS=”-”}{print $3}’echo “a-b-c–d-e-f–g-h-i” | awk ‘BEGIN{RS=”–";FS=”-";ORS="|";OFS="&”}{print $1,$2,$3}’ #必须用逗号分隔,否则输出字段分隔符不会起作用。a&b&c|d&e&f|g&h&iawk ‘{print FILENAME}’ nginx.conf #文件有多少行就会输出多少次awk ‘{print ARGC}’ /etc/passwd test.txt11.2 printf 格式化输出%s 打印字符串%d 打印十进制数字%x 打印十六进制%f 打印浮点型%o 打印八进制%e 打印科学计数法%c 打印ascii码- 左对齐+ 右对齐# 显示八进制在前面加0,十六进制在前面加0x例:awk ‘BEGIN{FS=”:”}{printf “%s\n”,$1}’ /etc/passwdawk ‘BEGIN{FS=”:”}{printf “%-20s %-20s\n”,$1,$7}’ /etc/passwdawk ‘BEGIN{FS=”:”}{printf “%#o\n”,$3}’ /etc/passwd11.3 模式匹配的两种方式正则表达式按关系运算符匹配><== 可以用于数值和字符串<=>=!=~ 匹配正则表达式!~ 不匹配正则表达式&&||!例:匹配/etc/passwd中包含root的行。 awk ‘/root/{print $0}’ /etc/passwd匹配/etc/passwd中以root开头的行。 awk ‘/^root/{print $0}’ /etc/passwd匹配/etc/passwd中第3个字段大于50的行。 awk ‘BEGIN{FS=”:”}$3>50{printf “%s\n”,$0}’ /etc/passwd匹配/etc/passwd中第7个字段等于/sbin/nologin的行。 awk ‘BEGIN{FS=”:”}$7=="/sbin/nologin”{printf “%s\n”,$7}’ /etc/passwd匹配/etc/passwd中第7个字段不等于/sbin/nologin的行。 awk ‘BEGIN{FS=”:”}$7!="/sbin/nologin”{printf “%s\n”,$7}’ /etc/passwd匹配/etc/passwd中第3个字段包含三个以上数字的行(匹配正则表达式)。 awk ‘BEGIN{FS=”:”}$3~/[0-9]{3,}/{printf “%d\n”,$3}’ /etc/passwd匹配/etc/passwd中包含root或nologin的所有行。awk ‘/root/ || /nologin/{print $0}’ /etc/passwd匹配/etc/passwd中第3个字段包含小于50并且第4个字段大于60并且第7行包含/sbin/nologin的所有行 awk ‘BEGIN{FS=”:”}$3>50 && $4<60 && $7~//sbin/nologin/{printf “%s %s %s\n”,$3,$4,$7}’ /etc/passwd11.4 动作表达式中的算术运算符+-^或 乘方++xx++–xx–例:awk ‘BEGIN{var1=10;var2=“hello”;print var1,var2}‘awk ‘BEGIN{num1=10;num2+=num1;print num1,num2}‘awk ‘BEGIN{num1=10;num2=29;print num1+num2}‘awk ‘BEGIN{num1=10;num2=29;print num1-num2}‘awk ‘BEGIN{num1=10;num2=29;print num1num2}‘awk ‘BEGIN{num1=10;num2=29;print num1/num2}‘awk ‘BEGIN{num1=10;num2=29;print num1^num2}‘awk ‘BEGIN{x=10;y=20;print x++;y++}‘awk ‘BEGIN{x=10;y=20;print ++x;++y}‘awk ‘BEGIN{num1=10;num2=29;printf “%0.2f\n”,num1/num2}’ #保留两位小数例:使用awk计算某文件中空白行的数量awk ‘/^$/{sum++}END{print sum}’ my.cnf例:计算课程分数平均值Allen 90 99 93 73Jone 83 23 38 97Monica 99 77 89 43Jerry 77 44 32 91awk ‘BEGIN{printf “%-8s %-8s %-8s %-8s %-8s\n”,“姓名”,“语文”,“数学”,“物理”,“平均分”}{total=$2+$3+$4+$5;avg=total/4;printf “%-8s %-8d %-8d %-8d %-8d %0.2f\n”,$1,$2,$3,$4,$5,avg}’ score.txt11.5 条件if (条件表达式1) 动作1else if (条件表达式2) 动作2else 动作3例:awk ‘BEGIN{FS=”:"}{if($3<50) {printf “%-10s %-4d\n”,“小于50的uid”,$3} else if($3<80) {printf “%-10s %-4d\n”,“小于80的uid”,$3} else {printf “%-10s %-4d\n”,“其它uid”,$3}}’ /etc/passwdawk的代码可能很长,这个时候可以写成脚本用-f来调用BEGIN { FS=":"}{ if($3<50) { printf “%-10s %-4d\n”,“小于50的uid”,$3 } else if($3<80) { printf “%-10s %-4d\n”,“小于80的uid”,$3 } else { printf “%-10s %-4d\n”,“其它uid”,$3 }}awk -f script.awk /etc/passwd例:计算课程分数平均值,并且只打印分数大于70的同学的姓名和分数Allen 90 99 93 73Jone 83 23 38 97Monica 99 77 89 43Jerry 77 44 32 91awk ‘{total=$2+$3+$4+$5;avg=total/4;if(avg>70){printf “%-10s %-0.2f\n”,$1,avg}}’ score.txt11.6 循环while(条件表达式) 动作do 动作while(条件表达式)for(初始化计数器;测试计数器;计数器变更) 动作例:计算1+2+3+…+100的和,分别使用do-while、while、for实现awk ‘BEGIN{for(i=1;i<=100;i++){sum+=i};printf “sum=%d\n”,sum}‘awk ‘BEGIN{do{sum+=i++}while(i<=100);printf “sum=%d\n”,sum}‘awk ‘BEGIN{while(i<=100){sum+=i++};printf “sum=%d\n”,sum}‘11.7 字符串函数函数名 解释 函数返回值———————————————————————————————————–length(str) 计算字符串长度 整数返回值index(str1,str2) 在str1中查找str2的位置 返回值为索引,从1开始toupper(str) 转换为大写 转换后的大写字符串tolower(str) 转换为小写 转换后的小写字符串substr(str,m,n) 从str的m个字符截取n位 截取后的子串split(str,arr,fs) 按fs切割字符串,结果保存到arr(分隔符默认是空格,可以省略) 切割后的子串的个数match(str,RE) 在str中按照RE查找,返回位置 返回索引位置,从1开始sub(RE,RepStr,str) 在str中按RE搜索字符串并将其替换为RepStr,只替换第一个,返回替换的个数gsub(RE,RepStr,str) 在str中按RE搜索字符串并将其替换为RepStr,替换所有例:awk ‘BEGIN{print length(“abcd”)}‘awk ‘BEGIN{print index(“abcd”,“c”)}‘awk ‘BEGIN{print toupper(“abCd”)}‘awk ‘BEGIN{print tolower(“abCd”)}‘awk ‘BEGIN{print substr(“hello,world”,3,6)}‘awk ‘BEGIN{print split(“root❌0:0:root”,arr,":");print arr}‘awk ‘BEGIN{print match(“hello,world”, /lo/)}‘例:返回/etc/passwd中每个字段的长度awk ‘BEGIN{FS=":";OFS=":"}{print length($1),length($2),length($3),length($4),length($5),length($6),length($7)}’ /etc/passwd搜索"i have a dream"中ea的位置awk ‘BEGIN{print index(“i have a dream”,“ea”)}‘awk ‘BEGIN{print match(“i have a dream”,“ea”)}‘将"Hadoop is a bigdata framework"转换为小写awk ‘BEGIN{print tolower(“Hadoop is a bigdata framework”)}‘将"Hadoop is a bigdata framework"转换为大写awk ‘BEGIN{print toupper(“Hadoop is a bigdata framework”)}‘将"Hadoop is a bigdata framework"按空格分割后保存在数组中awk ‘BEGIN{str=“Hadoop is a bigdata framework”;split(str,arr," “);for(a in arr){print arr[a]}}‘找出字符串"Transaction 23345 start: select * from master"中第一个数字出现的位置awk ‘BEGIN{str=“Transaction 23345 start: select * from master”;print match(str,/[0-9]/)}‘截取字符串"Transaction 23345 start: select * from master”,从第4个开始截取5位awk ‘BEGIN{str=“Transaction 23345 start: select * from master”;print substr(str,4,5)}‘替换"Transaction 23345 start, Event ID: 9002"中出现的第一个数字串为$awk ‘BEGIN{str=“Transaction 23345 start, Event ID: 9002”;count=sub(/[0-9]+/,"$",str);print count,str}‘11.8 选项-v 参数传递-f 指定awk脚本文件-F 指定分隔符,可以连着写-V 查看awk版本例:awk -v arg1=12 -v arg2=“hello world” ‘BEGIN{print arg1,arg2}‘awk -F “:” ‘{print $1}’ /etc/passwdawk -F: ‘{print $1}’ /etc/passwd11.9 awk中数组的用法数组使用(索引从0开始)array=(“janee” “jone” “jacek” “jordan”)打印元素 echo ${array[0]}、echo ${array[@]}打印元素个数 echo ${#array[@]}打印元素长度 echo ${#array[0]}给元素赋值 array[2]=“messi"删除元素 unset array[2]、unset array分片访问 echo ${array[0]:1:3}元素替换 ${array[@]/e/E}(替换元素中的第一个e为E)、${array[@]//e/E}(替换元素中的所有e为E)元素便利 for a in ${array[@]}; do echo $a; doneawk中数组的用法(索引从1开始)awk ‘BEGIN{str=“hadoop spark yarn storm flume”;split(str,array,” “);for(i=1;i<=length(array);i++){print array[i]}}‘awk的数组中可以使用字符串作为数组的下标awk ‘BEGIN{array[“var1”]=“zhangsan”;array[“var2”]=“lisi”;array[“var3”]=“wangwu”;for(i in array){print array[i]}}‘例:统计各种tcp状态连接状态数netstat -an | grep tcp | awk ‘{array[$6]++}END{for(i in array){print i,array[i]}}‘例:计算纵向横向总和Allen 90 99 93 73Jone 83 23 38 97Monica 99 77 89 43Jerry 77 44 32 91awk ‘{line++;line_sum=0;for(i=1;i<=NF;i++){line_sum+=$i;col_sum[i]+=$i;printf “%-6s “,$i};print line_sum}END{printf “%-6s”,”";for(i=2;i<=length(col_sum);i++){printf “%-6s “,col_sum[i]};printf “\n”}’ score.txt输出:Allen 90 99 93 73 355Jone 83 23 38 97 241Monica 99 77 89 43 308Jerry 77 44 32 91 244 349 243 252 304 11.10 awk中数组的用法例:用awk脚本处理数据并生成报告生成数据的脚本:insert.sh#!/bin/bashfunction create_random { min=$1 max=$(($2-$min+1)) num=$(date +%s%N) echo $(($num%$max+$min))}INDEX=1while truedo for user in Mike Allen Jerry Tracy Hanmeimei Lilei do COUNT=$RANDOM NUM1=create_random 1 $COUNT NUM2=expr $COUNT - $NUM1 echo “date "+%Y-%m-%d %H:%M:%S"” $INDEX Batches: $user insert $COUNT data into table ’test1’, insert $NUM1 records successfully, failed insert $NUM2 records >> /root/script/data.txt INDEX=expr $INDEX + 1 donedone数据格式:2019-04-17 23:44:36 495 Batches: Jerry insert 7658 data into table test1, insert 1008 records successfully, failed insert 6650 records2019-04-17 23:44:36 496 Batches: Tracy insert 17609 data into table test1, insert 10348 records successfully, failed insert 7261 records2019-04-17 23:44:36 497 Batches: Hanmeimei insert 14256 data into table test1, insert 1599 records successfully, failed insert 12657 records2019-04-17 23:44:36 498 Batches: Lilei insert 9279 data into table test1, insert 7856 records successfully, failed insert 1423 records2019-04-17 23:44:36 499 Batches: Mike insert 22652 data into table test1, insert 6291 records successfully, failed insert 16361 records(1)、统计每个人员插入了多少条数据进数据库awk ‘BEGIN{printf “%-10s %-10s\n”,“name”,“total”}{stat[$5]+=$7}END{for(i in stat){printf “%-10s %-10s\n”,i,stat[i]}}’ data.txt(2)、统计每个人员插入成功和失败了多少条数据进数据库awk ‘BEGIN{printf “%-10s %-10s %-10s %-10s\n”,“User”,“Total”,“Succeed”,“Failed”}{sum[$5]+=$7;suc_sum[$5]+=$13;fail_sum[$5]+=$18}END{for(i in sum){printf “%-10s %-10s %-10s %-10s\n”,i,sum[i],suc_sum[i],fail_sum[i]}}’ data.txt(3)、在(2)的基础上统计全部插入记录数awk ‘BEGIN{printf “%-10s %-10s %-10s %-10s\n”,“User”,“Total”,“Succeed”,“Failed”}{sum[$5]+=$7;suc_sum[$5]+=$13;fail_sum[$5]+=$18}END{for(i in sum){all_sum+=sum[i];all_suc_sum+=suc_sum[i];all_fail_sum+=fail_sum[i];printf “%-10s %-10s %-10s %-10s\n”,i,sum[i],suc_sum[i],fail_sum[i]};printf “%-10s %-10s %-10s %-10s\n”,”",all_sum,all_suc_sum,all_fail_sum}’ data.txt(4)、查找丢失数据,也就是成功+失败的记录数不等于总共插入的记录数awk ‘{if($7!=$13+$18){print $0}}’ data.txt12. mysql操作12.1 安装启动mariadbyum install mariadb mariadb-server mariadb-libs -ysystemctl start mariadb13. 脚本工具脚本工具功能概述(1)、实现一个脚本,该脚本提供类似supervisor的功能,可以对进程进行管理(2)、一键查看所有进程运行状态(3)、单个或批量启停进程(4)、提供进程分组功能,可以按组查看进程运行状态,可以按组启停进程配置文件 process.cfg[GROUP_LISE]WEB_LISTDB_LISTHADOOP_LISTYARN_LIST[WEB_LIST]nginxhttpd[DB_LIST]mysqlpostgresql[HADOOP_LIST]datanodenamenode[YARN_LIST]resourcemanagernodemanager[nginx]description=“Web Server 1"program_name=tailparameter=-f /root/tmp/web-nginx.conf[httpd]description=“Web Server 2"program_name=tailparameter=-f /root/tmp/web-httpd.conf[mysql]description=“High Perfrmance Database"program_name=tailparameter=-f /root/tmp/db-mysql.conf[postgresql]description=“High Perfrmance Database"program_name=tailparameter=-f /root/tmp/db-postgresql.conf[datanode]description=“Hadoop datanode"program_name=tailparameter=-f /root/tmp/hadoop-datanode.conf[namenode]description=“Hadoop namenode"program_name=tailparameter=-f /root/tmp/hadoop-namenode.conf[resourcemanager]description=“yarn resourcemanager"program_name=tailparameter=-f /root/tmp/yarn-resourcemanager.conf[nodemanager]description=“yarn nodemanager"program_name=tailparameter=-f /root/tmp/yarn-nodemanager.conf#!/bin/bashTHIS_PID=$$GROUP_LIST=GROUP_LISTCFG_FILE=/root/script/tmp/process.cfgfunction group_list { group_list=sed -n "/\[$GROUP_LIST\]/,/^\[.*\]/p" $CFG_FILE | grep -v "^$" | grep -v "\[.*\]" | grep -v "\#" echo $group_list}function get_all_process { for group in $(group_list) do p_list=$(get_all_process_by_group $group) echo $p_list done}function get_all_process_by_group { group_process=sed -n "/\[$1\]/,/\[.*\]/p" $CFG_FILE | grep -v "^$" | grep -v "\[.*\]" | grep -v "\#" echo $group_process}function is_group_exists { count=sed -n "/\[$1\]/p" $CFG_FILE | grep -v "$GROUP_LIST" | wc -l if [ $count -eq 1 ]; then return 0 else return 1 fi}function get_group_by_process_name { for g in $(group_list) do for p in get_all_process_by_group $g do if [ $p == $1 ]; then echo “$g” fi done done}function get_process_info_by_pid { ps -ef | awk -v pid=$1 ‘$2==pid{print}’ &> /dev/null if [ $? -eq 0 ]; then proc_status=“RUNNING” else proc_status=“STOPPED” fi proc_cpu=ps aux | awk -v pid=$1 '$2==pid{print $3}' proc_mem=ps aux | awk -v pid=$1 '$2==pid{print $4}' proc_start_time=ps -p $1 -o lstart | grep -v "STARTED"}function get_pid_by_process_name { if [ $# -ne 1 ]; then return 1 else pid=ps -ef | grep "$1" | grep -v grep | grep -v "$0" | awk '{print $2}' echo $pid fi}function format_print { group=get_group_by_process_name $1 ps -ef | grep $1 | grep -v grep | grep -v $THIS_PID &> /dev/null if [ $? -eq 0 ]; then for pids in get_pid_by_process_name $1 do for _pid in $pids do get_process_info_by_pid $_pid awk -v p_name="$1” \ -v p_group="$group” \ -v p_id="$_pid” \ -v p_status="$proc_status” \ -v p_cpu="$proc_cpu” \ -v p_mem="$proc_mem” \ -v p_start_time="$proc_start_time” \ ‘BEGIN{printf “%-20s%-10s%-10s%-10s%-10s%-10s%-10s\n”,p_name,p_group,p_status,p_id,p_cpu,p_mem,p_start_time;}’ done done else awk -v p_name="$1” \ -v p_group="$group” \ ‘BEGIN{printf “%-20s%-10s%-10s%-10s%-10s%-10s%-10s\n”,p_name,p_group,“NULL”,“NULL”,“NULL”,“NULL”,“NULL”;}’ fi}echo ““echo group_listecho get_all_processecho get_all_process_by_group DB_LISTecho is_group_exists WEB_LISTecho $(get_group_by_process_name mariadb)format_print $1echo “***“14. 其它ps -ef | grep nginx | awk ‘{print $2}’ | xargs kill$? 命令执行的结果,0表示成功,其它表示有异常$$ 脚本执行的子进程的pid$# 参数数量$0 shell文件名$@ shell执行的时候传入的所有参数shift shell执行的时候跳过一个传入的参数netstat -l[listening] -a[all] -t[tcp] -p[program] Show the PID and name of the program to which each socket belongs.

April 19, 2019 · 10 min · jiezi

高效日志分析 - 人人必学的awk

作为每一个Linux发行版本都会内置的文本处理程序,awk是快速分析日志的不二之选。服务日志分析是对了解服务状况、发现问题的最有效的手段。最近发现很多同学在分析服务日志的时候走了弯路:选择使用编程(js、php、python甚至是c)、甚至使用ELK来完成一次性日志统计分析。其实系统自带了功能非常强大的工具:awk,每一个程序员、甚至是每一个IT从业者都需要学会使用awk完成文本的处理和日志分析。什么是awkLinux command - awkOne of the great things we can do in the shell.几乎每一个Linux发行版本都会内置awk,在大小仅有4.2M的Alpine:3.7 Docker Image里面也内置了awk。由此可见其重要性。废话少说,直接进入日志分析。实战选用最常见的Nginx日志。Nginx日志的配置为log_format main ‘$remote_addr - $remote_user [$time_local] “$request” ’ ‘$status $body_bytes_sent “$http_referer” ’ ‘"$http_user_agent" “$http_x_forwarded_for” ’ ‘$request_time $upstream_response_time’;相比默认日志,添加了请求的响应时间和upstream的响应时间。100.120.34.170 - - [24/Jan/2019:00:06:02 +0800] “GET /page1 HTTP/1.1” 200 29087 “-” “Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)” “36.110.179.109” 0.138 0.138统计IP和出现过的次数cat file | awk -F " " ‘{print $1}’ | awk ‘{cnt[$0]++}END{for(i in cnt){print i,cnt[i]}}‘一些个人的喜好:先cat再用管道传给awk;每个awk只做简单的事情,管道传递给下一阶段继续,更清晰易懂分开调试-F " “:以空格做分隔符,默认分隔符就是空格,因此可以被省略cnt是一个数组,以$0作为key,value每次累加;$0指整行END指处理完所有行,再执行后面的逻辑for(i in cnt)遍历cnt并打印key和value只对IP进行去重一般用法:cat file | awk -F " " ‘{print $1}’ | sort | uniq一定要先sort再uniq,否则只对相邻的相邻值去重由于会排序,速度较慢,==不推荐==awk用法:cat file | awk ‘{cnt[$1]++}END{for(i in cnt){print i}}‘awk高级用法:cat file | awk ‘{print $1}’ | awk ‘!a[$0]++’’!a[$1]++‘是一个判断条件,条件为true的时候输出整行或者cat file | awk ‘!a[$1]++{print $1}‘统计平均响应时间cat file | awk ‘{a+=$(NF-1);b++}END{print a/b}’$NF是最后一个字段,$(NF-1)是倒数第二个字段a+=$(NF-1)对所有值累加, b++计数统计时间分布和比例cat file | awk ‘{print $(NF-1)}’|awk ‘{print int($0)}’|awk ’ { cnt[$0]++; total++ } END { for(i in cnt) { print i”“i+1,cnt[i],cnt[i]/total*100”%" } }’ | sort -nprint简单一点,方便理解print i,cnt[i],cnt[i]/totalprintf("%d%d %d %f%\n",i,i+1,cnt[i],cnt[i]/total)int($(NF-1))对数组进行取整四舍五入可以用int($(NF-1) + 0.5)sort -n结果按数字排序print和printf可任意选取使用统计每小时处理时间的平均值cat file | awk ‘{print $NF, $4}’| awk -F"[ :]" ‘{print $1,$3}’ | awk ’ { sum[$2]+=$1; cnt[$2]++ } END { for(i in sum) { print i, sum[i]/cnt[i] } }’ | sort -n-F “[ :]“指用空格或者冒号作为分隔符由于一次切割不容易获取到想要的字符串,故多做几次切割用两个数组用于分小时统计 ...

April 14, 2019 · 1 min · jiezi

Shell发送邮件以HTML展示

有时候,监控一个系统需要在系统出现警告时通过shell发送邮件来通知相关的负责人。本文讲讲如何shell发送邮件。一种是普通邮件,通过附件描述详细报告;一种是高级邮件(哈哈),本来就是告警,还不赶快看,还要慢慢下载附件打开看?所以将附件内容以HTML直接展示到正文处,并通过样式标记警告。1.安装sendEmail工具 下载、解压、配置环境变量]# wget http://caspian.dotconf.net/menu/Software/SendEmail/sendEmail-v1.56.tar.gz]# tar -zxf sendEmail-v1.56.tar.gz -C SendEmail/#配置环境变量这里不一样,不在profile文件里配置,而是拷贝到系统环境变量已有的路径中]# cd ~/myApp/SendEmail/]# cp sendEmail /usr/local/bin/2.开启邮箱的SMTP本文使用QQ邮件作为发送者设置 -> 账户 -> 下图中开启3.发送邮件QQ邮箱对SMTP有如下说明:#!/bin/bashRECIVER=“Wish0123@163.com"SENDER=“964478654@qq.com"SENDER_USERNAME=964478654#密码填写SMTP第三方客户端授权码SENDER_PASSWD=xuxjxankheuubcjdATTACHMENT_PATH=/root/workspace/sh/attach_test.txt#如下图描述,作为邮件发送方应填这个hostnameSTMP_HOST=smtp.qq.comMESSAGEL_SUBJECT=“Have Fun"MESSAGE_BODY=“报警啊…“sendEmail -f $SENDER -t $RECIVER -a $ATTACHMENT_PATH \ -s $STMP_HOST -xu $SENDER_USERNAME -xp $SENDER_PASSWD \ -u $MESSAGEL_SUBJECT -m $MESSAGE_BODY \ -o message-charset=utf-8发送后报错了:******************************************************************* Using the default of SSL_verify_mode of SSL_VERIFY_NONE for client is deprecated! Please set SSL_verify_mode to SSL_VERIFY_PEER possibly with SSL_ca_file|SSL_ca_path for verification. If you really don’t want to verify the certificate and keep the connection open to Man-In-The-Middle attacks please set SSL_verify_mode explicitly to SSL_VERIFY_NONE in your application.******************************************************************* at /usr/local/bin/sendEmail line 1906.invalid SSL_version specified at /usr/share/perl5/vendor_perl/IO/Socket/SSL.pm line 444.意思是SSL版本不对,原因是在cent7中Perl的版本5.16,而应该使用更低版本。或者不用SSL,也就需要在脚本最后一行的sendEmail命令添加一个参数-o tls=nosendEmail -f $SENDER -t $RECIVER -a $ATTACHMENT_PATH \ -s $STMP_HOST -xu $SENDER_USERNAME -xp $SENDER_PASSWD \ -u $MESSAGEL_SUBJECT -m $MESSAGE_BODY \ -o message-charset=utf-8 -o tls=no发送成功了!我擦,居然被当成诈骗钓鱼邮件。。4.HTML版邮箱直接展示html需要两个条件:一是把要展示的数据使用html标签封装起来,就可以随意增加样式了;二是在sendEmail增加参数-o message-content-type=html这里是根据系统内存情况发送系统邮件,当集群中机器的使用内存超过总内存80%的机器信息标红。[root@NN1 sh]# cat memory_info ip consum free total192.168.1.10 100 100 200192.168.1.11 1 239 240192.168.1.12 350 50 400192.168.1.13 40 24 64192.168.1.14 77 33 110192.168.1.15 150 250 400编写脚本#!/bin/bash -xRECIVER=“Wish0123@163.com"SENDER=“964478654@qq.com"SENDER_USERNAME=964478654#密码填写SMTP第三方客户端授权码SENDER_PASSWD=xuxjxankheuubcjdSTMP_HOST=smtp.qq.comMESSAGEL_SUBJECT=“Have Fun"HTML_PATH=html_pathecho “<table>">$HTML_PATHecho “<thead><th>ip</th><th>consum</th><th>free</th><th>total</th></thead>">>$HTML_PATHecho “<tbody>">>$HTML_PATHcreate_tr() { i=2 lines=$(cat memory_info | wc -l) while [ $i -le $lines ] do j=1 ip=$(awk ‘NR==i {print $j}’ i=$i j=$j memory_info) let “j++” m=$(awk ‘NR==i {print $j}’ i=$i j=$j memory_info) let “j++” f=$(awk ‘NR==i {print $j}’ i=$i j=$j memory_info) let “j++” t=$(awk ‘NR==i {print $j}’ i=$i j=$j memory_info) tr="<tr>” #shell不能直接作小数运算 #更简单的运算写法是$[$m + 5] if [ $(expr $m * 5) -gt $(expr $t * 4) ]; then tr="<tr style="background-color:red">” fi echo $tr>>$HTML_PATH echo “<td>"$ip”</td>">>$HTML_PATH echo “<td>"$m”</td>">>$HTML_PATH echo “<td>"$f”</td>">>$HTML_PATH echo “<td>"$t”</td>">>$HTML_PATH echo “</tr>">>$HTML_PATH let “i++” done}create_trecho “</tbody>">>$HTML_PATHecho “</table>">>$HTML_PATHMESSAGE_BODY=$(cat $HTML_PATH)sendEmail -f $SENDER -t $RECIVER -a $ATTACHMENT_PATH \ -s $STMP_HOST -xu $SENDER_USERNAME -xp $SENDER_PASSWD \ -u $MESSAGEL_SUBJECT -m $MESSAGE_BODY \ -o tls=no message-charset=utf-8 message-content-type=html发送成功!参考文章:https://blog.csdn.net/leshami…https://my.oschina.net/u/4005...https://blog.csdn.net/wz94732… ...

April 13, 2019 · 2 min · jiezi

通过端口号关闭当前进程

查看脚本:lsof -i TCP:9100 | grep LISTEN | awk ‘{print $2}‘使用到三个命令lsof、grep、awklsof 获取端口进程列表 grep 精准匹配进程 awk 获取进程号完整示例:#!/bin/bashPROCESS=echo | lsof -i TCP:9100 | grep LISTEN | awk ‘{print $2}‘if [ $PROCESS ]; thenkill -9 $PROCESSecho kill $PROCESSfi

April 12, 2019 · 1 min · jiezi

Bash脚本编程之subshell

(command1;command2;command3;…)会启动子shell。子shell可以访问父shell的变量,对父shell变量的改动只在子shell中有效;子shell中定义的变量是局部变量,外部不能访问:#!/bin/bash# subshell.shecho “We are outside the subshell.“echo “Subshell level OUTSIDE subshell = $BASH_SUBSHELL"echo; echoouter_variable=Outerglobal_variable=(echo “We are inside the subshell.“echo “Subshell level INSIDE subshell = $BASH_SUBSHELL"inner_variable=Innerglobal_variable="$inner_variable"echo “From inside subshell, "inner_variable" = $inner_variable"echo “From inside subshell, "outer" = $outer_variable”)echo; echoecho “We are outside the subshell.“echo “Subshell level OUTSIDE subshell = $BASH_SUBSHELL"echo “From main body of shell, "inner_variable" = $inner_variable”# $inner_variable will show as blank (uninitialized)#+ because variables defined in a subshell are “local variables”.echo “global_variable = “$global_variable"“echo# =======================================================================# Additionally …echo “—————–”; echovar=41 # Global variable.( let “var+=1”; echo “$var INSIDE subshell = $var” ) # 42echo “$var OUTSIDE subshell = $var” # 41# Variable operations inside a subshell, even to a GLOBAL variable#+ do not affect the value of the variable outside the subshell!exit 0在子shell中对目录的改变不会影响父shell:#!/bin/bash# allprofs.sh: Print all user profiles.FILE=.bashrc # File containing user profile.for home in awk -F: '{print $6}' /etc/passwddo [ -d “$home” ] || continue # If no home directory, go to next. [ -r “$home” ] || continue # If not readable, go to next. (cd $home; [ -e $FILE ] && cat $FILE)done# When script terminates, there is no need to ‘cd’ back to original directory,#+ because ‘cd $home’ takes place in a subshell.exit 0程序可以在不同的子shell中并行执行:#!/bin/bash# subshell.sh# 在后台运行以确保并行执行(ping -c 10 127.0.0.1 > /dev/null) &(ping -c 20 127.0.0.1 > /dev/null) &# 等同于:# ping -c 10 127.0.0.1 > /dev/null &# ping -c 20 127.0.0.1 > /dev/null &# 通过ps可以发现两条子命令都是当前脚本启动的子shell,拥有不同的进程ID# 直到子shell执行完成才执行后续命令waitecho “finished"I/O重定向到子shell使用管道操作符,例如ls -al | (command) ...

April 12, 2019 · 2 min · jiezi

谈谈Spring Boot 数据源加载及其多数据源简单实现

业务需求提供所有微服务数据源的图形化维护功能代码生成可以根据选择的数据源加载表等源信息数据源管理要支持动态配置,实时生效附录效果图实现思路本文提供方法仅供类似简单业务场景,在生产环境和复杂的业务场景 请使用分库分表的中间件(例如mycat)或者框架 sharding-sphere (一直在用)等先来看Spring 默认的数据源注入策略,如下代码默认的事务管理器在初始化时回去加载数据源实现。这里就是我们动态数据源的入口// 默认的事务管理器ppublic class DataSourceTransactionManager extends AbstractPlatformTransactionManager implements ResourceTransactionManager, InitializingBean { // 启动时候注入一个数据源 public void setDataSource(@Nullable DataSource dataSource) { if (dataSource instanceof TransactionAwareDataSourceProxy) { this.dataSource = ((TransactionAwareDataSourceProxy) dataSource).getTargetDataSource(); } else { this.dataSource = dataSource; } }」通过注入一个新的DataSourceTransactionManager 实现,并且给它设置多个 DataSource 来实现多数据源实现看下Spring 默认提供的路由数据源字段public abstract class AbstractRoutingDataSource extends AbstractDataSource implements InitializingBean { // 用户设置的全部的数据源配置 @Nullable private Map<Object, Object> targetDataSources; // 为空默认的数据源配置 @Nullable private Object defaultTargetDataSource; // 路由键查找实现 private DataSourceLookup dataSourceLookup = new JndiDataSourceLookup(); // 最终有效的数据源配置(一般清空对应上边用户的设置) @Nullable private Map<Object, DataSource> resolvedDataSources;}开始动手实现AbstractRoutingDataSource,定一个动态数据源实现,只需要实现他的路由key 查找方法即可。这里的路由key 对应其实是resolvedDataSources Map 的key哟@Slf4jpublic class DynamicDataSource extends AbstractRoutingDataSource { /** * 指定路由Key,这里很简单 获取 threadLocal 中目标key 即可 * * @return / @Override protected Object determineCurrentLookupKey() { return DynamicDataSourceContextHolder.getDataSourceType(); }}把我们动态数据源实现注入到Spring 的事务管理器,去数据库查询出来全部的数据源信息,定义一个个具体的数据源实现 我这里使用的HikariDataSource 给他赋值等等@Slf4j@Configuration@AllArgsConstructorpublic class DynamicDataSourceConfig implements TransactionManagementConfigurer { private final Map<Object, Object> dataSourceMap = new HashMap<>(8); private final DataSourceProperties dataSourceProperties; @Bean(“dynamicDataSource”) public DynamicDataSource dataSource() { JdbcTemplate(dds).queryForList(DataSourceConstant.QUERY_DS_SQL); log.info(“开始 -> 初始化动态数据源”); Optional.of(dbList).ifPresent(list -> list.forEach(db -> { log.info(“数据源:{}”, db.get(DataSourceConstant.DS_NAME)); HikariDataSource ds = new HikariDataSource(); dataSourceMap.put(db.get(DataSourceConstant.DS_ROUTE_KEY), ds); })); DynamicDataSource ds = new DynamicDataSource(); ds.setTargetDataSources(dataSourceMap); return ds; } @Bean public PlatformTransactionManager txManager() { return new DataSourceTransactionManager(dataSource()); } @Override public PlatformTransactionManager annotationDrivenTransactionManager() { return txManager(); }}怎么使用只需要根据用户前台选择的数据源key ,在业务类保存到TTL 即可,会自动根据选择路由数据源DynamicDataSourceContextHolder.setDataSourceType(key)这里当然也可以根据AOP 自定义注解等实现。如何动态数据源动态配置上边其实已经完成了 我们想要的需求功能,但是有什么问题呢? 我们在数据源管理面维护了数据源,动态去修改这个 dataSourceMap 其实是无效的,不能做到实时刷新 我们来看下 AbstractRoutingDataSource 的加载map 数据源的源码,只有在初始化的时候调用 afterPropertiesSet 去初始数据源map.那我们只要获取当前的DynamicDataSource bean 手动调用afterPropertiesSet 即可。整个代码如下public class DynamicDataSourceConfig implements TransactionManagementConfigurer { private final Map<Object, Object> dataSourceMap = new HashMap<>(8); private final DataSourceProperties dataSourceProperties; private final StringEncryptor stringEncryptor; @Bean(“dynamicDataSource”) public DynamicDataSource dataSource() { DynamicDataSource ds = new DynamicDataSource(); HikariDataSource cads = new HikariDataSource(); cads.setJdbcUrl(dataSourceProperties.getUrl()); cads.setDriverClassName(dataSourceProperties.getDriverClassName()); cads.setUsername(dataSourceProperties.getUsername()); cads.setPassword(dataSourceProperties.getPassword()); ds.setDefaultTargetDataSource(cads); dataSourceMap.put(0, cads); ds.setTargetDataSources(dataSourceMap); return ds; } /* * 组装默认配置的数据源,查询数据库配置 / @PostConstruct public void init() { DriverManagerDataSource dds = new DriverManagerDataSource(); dds.setUrl(dataSourceProperties.getUrl()); dds.setDriverClassName(dataSourceProperties.getDriverClassName()); dds.setUsername(dataSourceProperties.getUsername()); dds.setPassword(dataSourceProperties.getPassword()); List<Map<String, Object>> dbList = new JdbcTemplate(dds).queryForList(DataSourceConstant.QUERY_DS_SQL); log.info(“开始 -> 初始化动态数据源”); Optional.of(dbList).ifPresent(list -> list.forEach(db -> { log.info(“数据源:{}”, db.get(DataSourceConstant.DS_NAME)); HikariDataSource ds = new HikariDataSource(); ds.setJdbcUrl(String.valueOf(db.get(DataSourceConstant.DS_JDBC_URL))); ds.setDriverClassName(Driver.class.getName()); ds.setUsername((String) db.get(DataSourceConstant.DS_USER_NAME)); String decPwd = stringEncryptor.decrypt((String) db.get(DataSourceConstant.DS_USER_PWD)); ds.setPassword(decPwd); dataSourceMap.put(db.get(DataSourceConstant.DS_ROUTE_KEY), ds); })); log.info(“完毕 -> 初始化动态数据源,共计 {} 条”, dataSourceMap.size()); } /* * 重新加载数据源配置 */ public Boolean reload() { init(); DynamicDataSource dataSource = dataSource(); dataSource.setTargetDataSources(dataSourceMap); dataSource.afterPropertiesSet(); return Boolean.FALSE; } @Bean public PlatformTransactionManager txManager() { return new DataSourceTransactionManager(dataSource()); } @Override public PlatformTransactionManager annotationDrivenTransactionManager() { return txManager(); }总结以上源码参考个人项目 基于Spring Cloud、OAuth2.0开发基于Vue前后分离的开发平台QQ: 2270033969 一起来聊聊你们是咋用 spring cloud 的吧。欢迎关注我们获得更多的好玩JavaEE 实践 ...

April 12, 2019 · 2 min · jiezi

论linux shell脚本的入参

参数概述$# 是传给脚本的参数个数$0 是脚本本身的名字$1 是传递给该shell脚本的第一个参数$2 是传递给该shell脚本的第二个参数${10}是传递给该shell脚本的第10个参数${11}, ${12}以此类推$@ 是传给脚本的所有参数的列表$* 是以一个单字符串显示所有向脚本传递的参数脚本args.sh执行结果$@与$*的区别$@与$之间没有区别,只有在添加双引号的情况下,"$@“与”$“才有区别直接上码执行结果

April 11, 2019 · 1 min · jiezi

hadoop-2.6.0-cdh5.7.0源码编译支持压缩

在hadoop-2.6.0-cdh5.7.0源码中有个BUILDING.txt文件,里面列出了编译所需依赖组件。Requirements:Unix SystemJDK 1.7+Maven 3.0 or laterFindbugs 1.3.9 (if running findbugs)ProtocolBuffer 2.5.0CMake 2.6 or newer (if compiling native code), must be 3.0 or newer on MacZlib devel (if compiling native code)openssl devel ( if compiling native hadoop-pipes )Internet connection for first build (to fetch all Maven and Hadoop dependencies)转载链接文章中或通过yum安装或通过自己下载提供了所有正确版本组件,并将已下载组件通过百度云分享。我想补充一点的是,yum安装可能报出Another app is currently holding the yum lock; waiting for it to exit…的错误,可参考https://blog.csdn.net/testcs_…强制关闭yum进程来解决。根据BUILDING.txt提示Build options:Use -Pnative to compile/bundle native code * Use -Pdocs togenerate & bundle the documentation in the distribution (using -Pdist)Use -Psrc to create a project source TAR.GZ * Use -Dtar to create a TAR with the distribution (using -Pdist)Building distributions:Create binary distribution without native code and withoutdocumentation:$ mvn package -Pdist -DskipTests -DtarCreate binary distribution with native code and with documentation:$ mvn package -Pdist,native,docs -DskipTests -Dtar使用mvn clean package -Pdist,native -DskipTests -Dtar编译,编译完成后,默认会在源码根目录的hadoop-dist目录下生成target,里面的hadoop-2.6.0-cdh5.7.0文件夹就是已经编译好并已解压的hadoop了(直接用的),可以将其拷贝到自定义的位置进行部署配置。[root@NN1 hadoop-2.6.0-cdh5.7.0]# ./bin/hadoop checknative19/04/10 11:22:34 INFO bzip2.Bzip2Factory: Successfully loaded & initialized native-bzip2 library system-native19/04/10 11:22:34 INFO zlib.ZlibFactory: Successfully loaded & initialized native-zlib libraryNative library checking:hadoop: true /root/hadoop-c/hadoop-2.6.0-cdh5.7.0-target/hadoop-2.6.0-cdh5.7.0/lib/native/libhadoop.so.1.0.0zlib: true /lib64/libz.so.1snappy: true /lib64/libsnappy.so.1lz4: true revision:99bzip2: true /lib64/libbz2.so.1openssl: true /lib64/libcrypto.so可以看到编译的hadoop支持了各种压缩,亲测有效! ...

April 10, 2019 · 1 min · jiezi

Mac 终端 shell 公钥失效解决办法

阿里云服务器换了镜像,ip更改了。导致原来的ssh key失效了,提示报错如下:KENFORFORLIN:~ kenforstar$ sudo ssh root@192.168.1.203Password:@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!Someone could be eavesdropping on you right now (man-in-the-middle attack)!It is also possible that the RSA host key has just been changed.The fingerprint for the RSA key sent by the remote host isea:24:31:8d:03:07:36:db:2f:74:15:5d:58:67:a3:5b.Please contact your system administrator.Add correct host key in /var/root/.ssh/known_hosts to get rid of this message.Offending key in /var/root/.ssh/known_hosts:1RSA host key for 192.168.1.203 has changed and you have requested strict checking.Host key verification failed.解决方法:ssh-keygen -R 192.168.1.203(你远程服务器的IP) ...

April 8, 2019 · 1 min · jiezi

你还不会shell命令吗,我来教你

这几天也是刚学习了shell脚本的编写,虽然他不像Python、Java那样能够编写很大型的项目(当然我是这么认为),但是在操控Linux系统方面,还是有独特的优势的,当然在学习过程中我们也能更好的了解Linux。接下来,就开始学习吧。后面会有几个小例子,当然都是别的地方挪过来的,我就是代码的搬运工,嘿嘿。喜欢学习的同志们可以点击Python聚焦专栏,查看更多知识。繁琐的括号总结基本概念解释器种类Bourne Shell(/usr/bin/sh或/bin/sh)Bourne Again Shell(/bin/bash)C Shell(/usr/bin/csh)K Shell(/usr/bin/ksh)Shell for Root(/sbin/sh)在一般情况下,人们并不区分 Bourne Shell 和 Bourne Again Shell,所以,像 #!/bin/sh,它同样也可以改为 #!/bin/bash。脚本编写指定使用的解释器类型#!/bin/bash 运行方式作为可执行程序chmod +x ./test.sh # 修改权限./test.sh # 执行运行时一定要写成./test.sh,因为直接写test.sh,linux会去PATH里寻找,而一般只有/bin,/sbin,/usr/bin,/usr/sbin等在PATH中,所以使用./test.sh告诉系统,就在本目录下找作为解释器参数这种方式可以不用在sh文件中写明解释器类型,写了也是没有用的/bin/sh test.sh基本语法变量定义方式和python类似,只不过定义过程中不允许使用空格,默认都是字符串类型declare命令定义有类型的变量-i : 定义整型变量-a : 定义一个数组-f : 查看系统中所有定义的函数-F : 查看系统中所有定义的函数名称-x : 声明一个环境变量–在脚本文件中可以直接使用的变量取消定义的变量:把命令减号改成加号再执行使用时只需要使用&dollar; / &dollar;{ }就可以了只读变量:在变量定义后,再使用readonly 修饰,再次赋值会报错删除变量:unset var_name,不能删除只读变量变量数据修改语法说明${var_name#规则}从变量开头进行匹配,将符合最短的数据删除${var_name##规则}从变量开头进行匹配,将符合最长的数据删除${var_name%规则}从变量末尾进行匹配,将符合最短的数据删除${var_name%%规则}从变量末尾进行匹配,将符合最长的数据删除${变量名/旧字符串/新字符串}变量内容符合旧字符串,就将第一个替换${变量名//旧字符串/新字符串}变量内容符合旧字符串,就全部替换字符串Shell字符串单引号:不能使用变量双引号:可以使用变量,并转义\n等字符反引号:用于保存要执行的命令,同:&dollar;() 【点击例子】在进行拼接的时候是可以出现以下形式的:“Hello, “$world”"‘Hello, ‘$world’’expr命令是从1开始索引,而普通的提取都是从零开始索引的求长度获取字符串长度:$#var_name${#str}expr lenth $str求字串索引expr index $str substr_regsubstr其实索引的是其每个字符,返回最小索引的那个匹配的字串的长度expr match $str substr_reg截取${str:start}${str:start:lenth}${str:(start)}/${str: -start} start为负数,表示从尾部开始expr substr $str $start $length数组定义:array_name=(value0 value1 value2 value3) 使用空格分隔元素array_name[0]=value0 / array_name[1]=value1下标可以不连续读取:单个读取:${array_name[index]}全部读取:${array_name[@]}获取长度:数组长度:length=&dollar;{#array_name[@]}/length=${#array_name[]}单个元素长度:lengthn=${#array_name[n]}注释单行:#多行::<<EOF . . . EOF使用其他符号替代EOF,如:‘函数定义function func_name { }func_name ( ) { }返回值return : 一般返回一个整数,用于做判断echo : 用于返回数据printf局部变量local修饰,不进行修饰那么函数执行后,其他地方也可以使用。函数库文件后缀是任意的,一般为lib一般不会赋予可执行权限第一行一般使用#!/bin/echo输出警告信息,避免用户执行获取命令行参数$num:num为要获取的参数位置,从0开始,分别代表文件名,参数1,参数2$#:传递到脚本的参数个数&dollar;&dollar;:脚本运行的当前进程ID号$!:后台运行的最后一个进程的ID号$?:显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。$-:显示Shell使用的当前选项,与set命令功能相同。$ / $@:以一个单字符串显示所有向脚本传递的参数。相同点:都是引用所有参数。不同点:只有在双引号中体现出来。假设在脚本运行时写了三个参数 1、2、3,,则 " * " 等价于 “1 2 3”(传递了一个参数),而 “@” 等价于 “1” “2” “3”(传递了三个参数)。中括号的使用(一般可以使用test命令替换)一个变量是否为0, [ $var -eq 0 ]ne:不等于lt/gt:小于/大于le/ge:小于等于/大于等于一个文件是否存在,[ -e $var ], 是否是目录,[ -d $var ]两个字符串是否相同, [[ $var1 = $var2 ]]-a/-o:and/or-e : exist-r : 是否可读-w : 是否可写-n :判断字符串长度是否非0-z :判断字符串长度是否为0$ :判断字符串是否非空运算符:原生bash不支持简单的数学运算,需要使用awk和expr,expr最常用,并且只能进行整数运算表达式和运算符之间要有空格完整的表达式要被 包含带有转移的字符需要使用\修饰才能使用使用$(())中间的运算符不需要转义并且不要求有空格,不能进行相等和不等的判断 echo expr 2 + 2 # 输出4成立返回1,不成立返回0在 MAC 中 shell 的 expr 语法是:$((表达式)),此处表达式中的 “” 不需要转义符号 ““浮点数计算:bcecho “scale=2;1+1.2” | bc几个常用命令read命令从标准输入中接收一行,并对修饰的变量赋值read -p “请输入一段文字:” -n 6 -t 5 -s password-p 输入提示文字-n 输入字符长度限制(达到6位,自动结束)-t 输入限时-s 隐藏输入内容echo-e 开启转义,对字符串中的转义字符进行转义操作,不区分单双引号printfprintf “%s” jimtest:一般用于替换中括号test $num = $num2流程控制if . . . elseif conditionthen command1 elif condition1then command2else commandNfifor . . . infor var in datado command1donewhilewhile conditiondo commanddoneuntil:与while相反操作,条件为true时退出循环死循环while :do commanddone# 使用truewhile truedo commanddone# 使用forfor (( ; ; ))casecase value invalue1) command1;;value2) command2;;) command2;;esaclet执行一个或多个表达式sed(Stream Editor)命令详解,对查找到的数据进行处理【点击例子】# 语法格式:sed [option] “pattern command” file_name# 删除文件第一行sed -i ‘1d’ file_nameoption选项n:只输出匹配的行e:需要匹配的条件,可以指定多个-e “pattern command"f:指定sed文件,用于封装替换"pattern command"r:用于支持正则表达式修改输出内容:sed -n ’s/love/like/g;p’ sed.txti:修改源文件pattern可以使用正则表达式可以使用变量,只要按照脚本使用变量就可以:双引号,$var_name匹配/需要进行转义按行匹配的时候,行数在后面如果小于前一个匹配模式,那么久只显示满足前一个条件的行=:显示行号commanda : 在匹配到行的下一行添加字符串i :在匹配到行的上一行添加字符串r :在匹配到行的下一行添加file内容w :将匹配到的行写入文件d :删除数据p :打印数据g :修改数据时全部匹配,3g表示从第三个开始全部修改,ig忽略大小写= :显示匹配到的行号反向引用在使用替换字符的时候,修改内容使用&表示使用被替换的条件# 在匹配到^la..jim的后面加shuai# &:全匹配,\1:其使用了正则的分组,所以前面需要使用小括号括起来sed -i ’s/^la..jim/&shuai/g’ sed.txt命令详解awk工作模式【点击例子】# 语法格式:awk ‘BEGIN{}pattern{commands}END{}’ file_name适合文本处理和报表生成命令详解小例子<span id=“find_user_all”>查询所有用户</span>for user in cat /etc/passwd | cut -d ":" -f 1do echo “$user"done<span id=“start_nginx”>启动nginx</span>nginx_num_process=$(ps -ef | grep nginx | grep -v grep | wc -l)if [ nginx_num_process -eq 0 ];then systemctl start nginxfi<span id=“num_add”>用户输入num,求1-num之和</span>while truedo read -p “pls input a positive number: " num expr $num + 1 &> /dev/null if [ $? -eq 0 ];then if [ expr $num \&gt; 0 -eq 1 ];then for((i=1;i<=$num;i++)) do sum=expr $sum + $i done echo “1+2+3+….+$num = $sum” exit fi fi echo “error,input enlegal” continuedone<span id=“check_nginx”>检查Nginx是否正常运行,宕机则启动它</span>this_pid=$$while truedops -ef | grep nginx | grep -v grep | grep -v $this_pid &> /dev/nullif [ $? -eq 0 ];then echo “Nginx is running well” sleep 3else systemctl start nginx echo “Nginx is down,Start it….“fidone<span id=“find_mysql”>查找mysql配置文件中有几段</span>FILE_NAME=/root/lesson/5.6/my.cnffunction get_all_segments{ echo “sed -n '/\[.*\]/p' $FILE_NAME | sed -e 's/\[//g' -e 's/\]//g'"}function count_items_in_segment{ items=sed -n '/\['$1'\]/,/\[.*\]/p' $FILE_NAME | grep -v "^#" | grep -v "^$" | grep -v "\[.*\]" index=0 for item in $items do index=expr $index + 1 done echo $index}number=0for segment in get_all_segmentsdo number=expr $number + 1 items_count=count_items_in_segment $segment echo “$number: $segment $items_count"done<span id=“del_blank”>删除配置文件中所有的注释行和空行</span>sed -i ‘/[:blank:]#/^$/d’ config.cnf<span id=“add_not_ano”>在非#注释行前加</span>sed -i ’s/^[^#]/*&/g’ config.cnf<span id=“text_insert_mysql”>文本格式化数据插入mysql</span>user=““password=““host=““mysql_conn=“mysql -u”$user” -p”$password” -h”$host"“IFS=":” # 内置分隔符变量cat data.txt | while read id name birth sexdo $mysql_conn -e “insert into school values(’$id’,’$name’,’$birth’,’$sex’)“done<span id=“script_use_ftp”>脚本使用ftp</span>ftp -inv << EOFopen ftp_ip_addruser user_name passwordput file_namebyeEOF #必须顶格写<span id=“awk”>awk小例子</span>小东东nohub + & 后台启动 : nohub不间断的运行程序,关闭窗口也不会关闭进程,&用于后台运行netstat -tnlp | grep port : 一般用于查看端口&&当左侧的命令返回0(成功)才会执行右侧命令cut -d “:“制定分隔符free -m:内存使用情况df -h:磁盘使用情况n >& m:将输出文件 m 和 n 合并n <& m:将输入文件 m 和 n 合并<< tag:将开始标记 tag 和结束标记 tag 之间的内容作为输入grep -E等同于egrep,用于扩展支持正则表达式cat -n file显示行号输出/sbin/nologin 不可以登陆的用户[:blank:]表示空格^$表示空行sh -x可以查看执行过程根据其他表的结构创建新表create table new_table like other_tablemysql -B不显示边框 -E表示垂直显示 -H输出html -X输出xml -N不显示列名mysqldumps备份mysqld :只导出表结构t :只导出数据,不导出建表语句A :导出所有数据库B :导出一个或者多个数据库crontab定时任务 ...

April 7, 2019 · 3 min · jiezi

使用Expect实现自动化交互

*写在前面最近开发的一个项目希望实现这样一个功能。将本地项目创建脚手架置于远程服务器,而用户需要创建项目时,仅需要在提供的页面上填入一些项目基础配置并提交,后台便会根据选择自动化创建项目并push上仓库。咋看是个非常简单的需求,我们仅需要在用户发起创建请求时在后端调取shell脚本并可以实现这一系列的操作。然而目前项目创建脚手架不支持多参数传递,只能通过用户输入完成各参数传递的操作。于是抛出本文的主角:Expect,以实现一系列的自动化交互动作。Expect简介expect是一个免费的编程工具,用来实现自动的交互式任务,而无需人为干预。说白了,expect就是一套用来实现自动交互功能的软件。在实际工作中,我们运行命令、脚本或程序时,这些命令、脚本或程序都需要从终端输入某些继续运行的指令,而这些输入都需要人为的手工进行。而利用expect,则可以根据程序的提示,模拟标准输入提供给程序,从而实现自动化交互执行。这就是expect!!!Expect命令使用expect时,首先需要在文件顶部写入#!/usr/bin/expect,已告知进程这是一个expect文件。而在脚本书写中基本离不开以下这「六」个命令。spawn 启动新的进程expect 用来等待一个进程的反馈,我们根据进程的反馈,再发送对应的交互命send 发送需要交互的值,替代了用户手动输入内容set 设置变量值expect eof 自动化结束interact 退出自动化,进入人工交互Expect语法expect使用的是tcl语法,详细教程可查阅TCL基本语法 - Tcl教程这里提供几个简单的流程控制,一般来说已经够用了。传参expect参数值存放在$argv中,比如取第一个参数就是[lindex $argv 0],以此类推。// 执行命令 xxx.sh mike 22 engineer#!/usr/bin/expectset name = [lindex $argv 0]set age = [lindex $argv 1]set job = [lindex $argv 2]if/elseif {$a == ‘a’} { set flag = 0} else { set flag = 1}expect ‘请输入xxx的值‘send $flag循环匹配一般来说expect匹配成功会会退出语句,而exp_continue表示循环匹配。匹配到改关键字后继续从头开始匹配。例如安装软件时需要输入多个 yes。expect { “yes/no” { send “yes” exp_continue } eof { send “eof” }}栗子 未完待续

March 31, 2019 · 1 min · jiezi