分类目录归档:理论知识

expect——实现远程服务的自动部署

自动化部署的场景

比如我在本地和服务端都使用 git 来管理代码,当本地代码修改过后,想将改动升级到服务端。这时,我应该先将本地的代码 commit、合并到发布分支、push,然后再 ssh 登录到服务器,在服务器上执行git pull,将代码拉下来。这个过程看似简单,但是如果每天需要执行多次的话,就非常麻烦了。

简单的实现一个 sh 脚本,比如下面

ssh -p 121 root@x.x.x.x
cd /www/wwwroot/xx.com
git pull

执行此脚本,会发现执行到第一行之后,终端会阻塞,因为 ssh 命令是一个阻塞命令,后续的命令将无法执行。

expect 可以实现:开启一个子进程,然后监控这个子进程的输出,按照输出的内容来决定下一步执行的命令。在上面的例子中,就是开启一个子的 ssh 登录的进程,然后监控这个子进程的输出,这样就可以根据输出来决定下面执行的命令啦。

expect 的工作逻辑

先看一个简单的 expect 脚本。

echo '这是一个 shell 脚本'
/usr/bin/expect << eof
set timeout -1
spawn ssh -p 121 root@x.x.x.x
expect "root@*"
send "cd /www/wwwroot/xx/ \r"
expect "root@*"
send "mysqldump -uroot -h localhost -ppassword  dbname > back.sql \r"
expect "root@*"
send "zip db.zip back.sql \r"
expect "root@*"
send "exit \r"
eof
echo 'shell 脚本结束'
  1. expect是一个开发语言,通过/usr/bin/expect进入expect的执行环境。/usr/bin/expect <<eof eof之间是 expect 脚本,而不是shell脚本。
  2. mac预装了expect,这里/usr/bin/expect 是 expect 的安装目录
  3. spawn 指令的含义为开启一个进程,并将这个子进程的标准输入、输出和错误输出重定向到当前 Expect 环境中,从而实现对子进程的监控和控制。这里 spawn 执行的是 ssh 命令,他会将 ssh 进程的 io 结果输出给 expect,所以 expect 才可以实现按照期望输出值来执行命令的能力。
  4. expect 后是期望内容的表达式
  5. send 是发送的命令

通过上面 几点估计你就可以很明白 expect 的工作逻辑了。上面的脚本实现了 ssh 登录一个服务器,然后导出一个数据库并将 导出的 sql 文件压缩。

注意事项

  1. 使用大括号的语法发送的命令将异步执行,不使用大括号发送的命令将同步执行。等待同步执行结果后才执行expect匹配。如:

    expect "root@*"  {send "cd /www/dist/web/ \r"}

    此命令将异步执行,如:

    expect "root@*"  
    send "cd /www/dist/web/ \r"
    expect "root@*"  

    此命令将同步执行,直到cd命令的结果返回才执行下一expect命令。

  2. 使用-d参数可以用调试模式执行命令,这在调试的时候非常有用。如:
    /usr/bin/expect-d<<eof

  3. send执行的命令有超时限制,如果想设定为无限等待阻塞命令,可以使用timeout选项。如:

    echo '🗂 dump 数据 并 zip '
    /usr/bin/expect << eof
    set timeout -1
    spawn ssh -p 1222 root@x.x.x.x
    send "cd /www/wwwroot/xxx.com\r"
    expect "root@*"
    send "zip db.zip db.sql \r"
    expect "root@*"
    send "xxxxx"
    eof
    echo done!
  4. expect是一种编程语言,expect和send是此语言中两个独立的命令。一般来讲一行expect,一行send。

one more thing

服务的自动化部署是一个常见的需求,尤其是当服务较多时。比如一个服务需要部署到多台服务器(负载均衡或者私有化部署)。这时手动部署就成了灾难。麻烦且不稳定,一个不留神就会导致不可预料的结果。此时有两种解决方案。

  • 自己实现一套自动化部署的脚本,实现本地打包->上传到服务器->自动解压等部署操作的自动化;
  • 使用专业的工具比如jenkins;

前者成本较低,但是功能较弱,适合小型项目。后者功能强大,但学习和部署成本较高,适合大型项目(当然如果有jenkens的部署经验,小项目也同样适用)。

一篇文章彻底理解property 和 attribute

js 世界中有两个非常重要的术语,开发和学习过程中会非常密集的接触到,他们是 attribute 和 property。本文解释这两个基础概念,理解他们之后,在看文章、api 文档的时候就会思路清晰,不迷糊了。

Atrribute和Property的概念或定义

html文档渲染时会被浏览器解析为一个dom树,树上每个节的点为一个dom对象(dom object)。

  1. property是dom对象的概念,含义为dom对象属性。
  2. attribute是html元素的概念,含义为元素的特性。
  3. attribute翻译为特性,property翻译为属性。

从不同的角度理解Attribute 和 Property

  1. 在多数面向对象的开发平台中(比如 java、c#等)property的含义都是对象的属性,这一点和js中的property概念是统一的。
  2. attribute的值只能是字符串,property的值可以是任意js类型的数据。
  3. 在js 中比如 let a = {name:"tom"},这里 name 就是对象 a 的property(当然他可以是任意类型的值)。

从实例理解Attribute 和 Property

在vue中,attribute和property的使用当然遵循上面的定义,而且凸显的更加明显。看下面的代码:

<div age="12" v-bind:age1="age1">
  1. age 是一个 html 元素(这里是一个div )的 attribute,他的值只能是字符串。
  2. v-bind指令给此div元素对应的dom对象指定了一个名为age1的属性,其值为组件中名为age1的变量的值,它可以是任意js类型的数据。

>和空格——子元素选择器(子代选择器)

直接子代选择器

例如 p > .title将会选中p元素下第一代有title class的子元素

<p>
<div class='title'></div>
<div class='content'>
        <div class='title'></div>
</div>
</p>


第一个title将会被选中,因为他是p的第一级子元素(直接子元素)
第二个title不会被选中,因为他是p的第二级子元素(非直接子元素)

非直接子代选择器 空格

例如 p .title

上面的例子中,两个title都会被选中,因为他们都是p的子元素,不管是直接的还是非直接的子元素,都会被选中。

css选择器——伪类选择器

使用方式为:选择器:描述。伪类选择器实现了逻辑描述类型的选择器,而不是静态的选择器。符合伪类中的逻辑描述的元素将被选中。

a:hover     表示选择鼠标hover时的a元素
:root   表示选择文档的根元素
p:first-child   表示选择p的第一个子元素

以上选择器中,冒号后的单词都是一个逻辑描述,即:被hover的;根的;第一个子元素。符合这些描述的元素将被选中。

常用的伪类选择器

:link   选择所有未被访问的链接。
:visited    选择所有已经被访问过的链接。
:hover  选择鼠标指针浮动在其上的元素。
:active 选择活动状态的元素。
:focus  选择得到焦点的元素。
:first-child    选择元素的第一个子元素。
:last-child 选择元素的最后一个子元素。
**:nth-child(n)**   选择元素的第n个子元素。
:root   选择文档的根元素 使用:root选择器可以方便地为整个文档设置全局的CSS变量,如下:

css伪类选择器root

xdebug的调试原理

搭建xdebug的调试环境时,经常会出现各种各样的问题导致断点无法命中,调试起来又很麻烦。如果了解xdebug的调试原理的话,可能方便定位问题点。所以这里简单说下xdebug的调试原理。

  1. xdebug和phpstorm(或其他ide)是cs(clint/server)结构的一套体系,他们通过DBGp协议通讯,默认端口是9000,你可以在php.ini配置文件和phpstorm的配置中修改这个端口。xdebug是客户端,phpstorm是服务端。在phpstorm中点击监听按钮,就相当于开启了调试服务,等待xdebug发送调试信息就行啦。

  2. 当php.ini中开启了xdebug扩展,那么当php运行的时候,xdebug就会向服务端发送调试信息,告诉服务端应该如何断点。

了解这个基本原理后,可以顺着调试原理的逻辑思路来判断无法命中断点的具体问题点是出在什么地方。从而准确配置xdebug。