docker部署node应用

环境:centos7

docker的安装以及一些设置

安装docker

     yum install docker

启动docker服务

     systemctl start docker.service

设置开机启动

     systemctl enable docker.service

pull下nodejs镜像

说是docker hub 慢,就找到了一个国内的镜像去下载

     docker pull hub.c.163.com/nce2/nodejs:0.12.2

未分类

查看镜像

     docker images

未分类

创建node应用

然后在工作目录下创建package.json文件

     vi package.json

写入内容
未分类

创建server.js,也就是我们node应用的主文件

     vi server.js

写点内容
未分类

创建Dockerfile文件

在项目代码更目录创建Dockerfile文件

     vi Dockerfile

写入以下内容
未分类
下面简单解释下Dockerfile文件

FROM hub.c.163.com/nce2/nodejs:0.12.2

FROM是构建镜像的基础镜像源,后面的一串是我们刚才pull下来的那个Image,如果本地没有Docker,会自己pull镜像的。

#Create app directory
RUN mkdir -p /home/Service
WORKDIR /home/Service

第一句RUN用于在Image里创建一个文件夹,将会用于保存我们的代码。
第二句WORKDIR是将我们创建的文件夹作为工作目录。

# Bundle app Source
COPY . /home/Service
RUN npm install

第一句的COPY是把本机当前目录下的所有文件拷贝到Image的 /home/Service目录下。
第二句的RUN是用npm 安装我们的node应用中的所有依赖包。

EXPOSE 8888

我们的node应用监听的是8888端口,我们可以把这个端口暴露给主机。这样我们就可以从外网访问我们的应用了。

CMD ["npm" , "start"]

用来启动我们的node应用。

构建Image

在我们的Dockerfile所在的目录下执行构建命令

docker build -t mynodeapp .

别忘了最后那个点,不久我们会看到成功构建的信息。
未分类

然后我们去查看一下我们构建的镜像

docker images

未分类

运行构建的Image

docker run -d -p 8888:8888 50550c

-d表示容器会在后台运行,-p表示端口映射,把本机的8888端口映射到container的8888端口,这样外网就可以通过本机访问我们的应用,
后面的50550c是我们Image的ID,没写后面的是因为根据这几个就能定位出来了。

竟然报错了,也不能访问8888端口。想了一下,应该是镜像的问题。
就跑去dochub找了官方镜像,修改Dockerfile里的基础镜像

FROM node:4-onbuild

然后再次构建我们的应用

docker build -t nodeapp .

然后开始从官网下载镜像,确实特别慢..等了好久才下载完1个。貌似需要下载9个文件..
在漫长的等待过程中。。。
未分类

算了,放弃。。找找国内镜像试试吧~~

然后去daocloud注册了帐号,在这拉镜像吧

未分类
很快,镜像pull下来了。然后查看下现在的镜像。

未分类
现在我们去改下Dockerfile的基础镜像吧。

FROM daocloud.io/library/node

现在我们再来构建下镜像试试

docker build -t nodeapp .

看到了构建成功的信息,接着查看一下imges

然后启动:

docker run -d -p 8888:8888 7b784

果然出现了问题… 启动不成功,最后才知道,镜像和Dockerfile都是对应的,不对应就可能会出现上面的所有问题。(切记)

最近还是选择了官网的镜像,等待了40分钟左右,全部pull下来了,开始干活~~

修改Dockerfile文件如下:

FROM node:4-onbuild
# replace this with your application's default port
EXPOSE 8888

重新构建:

docker build -t my-node-apps .

未分类

启动docker镜像:

docker run -d -p 8888:8888 8b

然后查看下container

docker ps

未分类

然后用浏览器访问下8888端口:

未分类
完美!!!!!!!!!这次终于成功了~

然后去删除没用的images和container…

若要删除所有的image, 使用命令:

docker rmi  $( docker  images -q )

删除container

docker rm id

总结

因为镜像的事情走了不少弯路,浪费了很多的时间,所以最好还是去官网下需要的东西,然后看官方给的文档,英文的也要尽力去看。
今后还要去做学习一些images的管理,container的管理,以及应用日志处理相关的东西。

docker-compose快速搭建python开发环境

Docker提供了容器级别的资源隔离。由于Python的外部依赖管理中存在的问题,我们通常会使用virtualenv来对不同的项目创建其唯一的依赖环境。这时利用Docker进行Python开发,可以轻松解决不同Python项目之间的依赖隔离问题。

作为应用程序,我们通常需要依赖于多种外部服务,比如数据库、缓存服务等等。Docker-compose就是在Docker容器的基础上,提供了统一的容器编排语言,可以让你更轻松的利用Docker构建你的应用环境。

编写Dockerfile

我们使用requirements.txt定义我们的第三方python包依赖
Python
Project-Root
|– static
|– templates
|– server.py
|– requirements.txt
|– Dockerfile
|– docker-compose.yml

编写Dockerfile内容如下:
Python
在Dockerfile中,我们主要目的:通过requirements.txt文件安装第三方的Python库依赖;利用Docker的容器隔离,可以忽略掉很多在本地开发中需要使用的东西,比如virtualenv。

编排我们的Docker容器

在案例中,应用程序依赖了mongodb作为数据存储服务,以及redis作为缓存服务。在一般情况下,作为开发团队要么我们搭建统一的mongodb;要不就每个人在开发机上单独部署。

而在Docker中,我们则不在需要做这么多无用的事情。 Docker官方提供了大量的基础容器,基本涵盖了日常开发中我们需要的大部分依赖。 在https://hub.docker.com/我们可以搜索到我们需要的基础镜像。

比如mongodb以及redis,在docker-hub上官方都提供了容器话的服务。

以redis容器为例,我们在本地搭建redis服务要做的事情主要包括两步:
Python
这个时候我们就可以通过访问0.0.0.0:63775来访问我们的redis服务器了。

我们也可以通过Docker原生的命令来连接我们的应用容器和redis容器,以使我们的代码能够正常的访问redis服务
Python
而事实上,我们可以使用更加简化的方式来定义我们的容器组合管理,使用Docker-compose(前身Fig)来定义我们的容器组合关系。
Python
这里我们定义了3个容器web、redis、mongo。 其中,web容器是通过当前目录的Dockerfile进行构建,同时将当前目录挂在到/app目录。 而redis和mongo则直接使用官方进行。

通过使用links,我们可以在web容器中通过 ‘redis:6375’以及’mongo:21707’直接访问相应的服务。

开始Coding吧

Python
Docker会根据当前的目录下得Dockerfile构建基础镜像,并且使用python server.py运行程序,并且运行redis以及mongo服务。

同时由于使用了volumes挂载了本地目录到/app,此时如果我们是开启的Debug模式,我们就可以直接在本地使用你喜欢的文本编辑器去编写代码,并且更新的代码能够实时被重新加载。

当然在使用Docker中最漫长的过程就是,下镜像,下镜像&下镜像。
Python

RedHat6.5安装配置Cacti监控工具

Cacti 在英文中的意思是仙人掌的意思,Cacti是一套基于PHP、MySQL、SNMP及RRDTool开发的网络流量监测图形分析工具。它通过snmpget来获取数据,使用 RRDtool绘画图形,它的界面非常漂亮,能让你根本无需明白rrdtool的参数能轻易的绘出漂亮的图形。而且你完全可以不需要了解RRDtool复杂的参数。它提供了非常强大的数据和用户管理功能,可以指定每一个用户能查看树状结 构、host以及任何一张图,还可以与LDAP结合进行用户验证,同时也能自己增加模板,让你添加自己的snmp_query和script!功能非常强大完善,界面友好。可以说,Cacti将rrdtool的所有“缺点”都补足了!

官方网站:http://www.cacti.net。好了,Cacti的简单介绍我们就说到这里了,下面我们来看一下Cacti的工作流程。

  • 主机环境 RedHat6.5 64位
  • 实验环境 服务端1 ip 172.25.25.1
    服务端2 ip 172.25.25.2
  • 安装包 cacti-0.8.8h.tar.gz
    php-snmp-5.3.3-26.el6.x86_64.rpm
    cacti-spine-0.8.8g.tar.gz
  • 防火墙状态:关闭
  • Selinux状态:Disabled

1.配置安装cacti及测试

A)配置安装cacti

[root@sever1 Asia]# yum install rrdtool mysql-server php httpdphp-mysql php-xml net-snmp net-snmp-utils- y                        #安装cacti之前要安装的包

[root@sever1 Asia]# cd /mnt/

[root@sever1 mnt]# ls

cacti-0.8.8h.tar.gz php-snmp-5.3.3-26.el6.x86_64.rpm

cacti-spine-0.8.8g.tar.gz

[root@sever1 mnt]# rpm -vih php-snmp-5.3.3-26.el6.x86_64.rpm

[root@sever1 mnt]# vim /etc/php.ini

946 date.timezone =Asia/Shanghai

[root@sever1 mnt]# tar zxf cacti-0.8.8h.tar.gz -C/var/www/html/  #解压到/var/www/html/目录

[root@sever1 mnt]# cd /var/www/html/

[root@sever1 html]# ls

cacti-0.8.8h

[root@sever1 html]# ln -s cacti-0.8.8h/ cacti          #作软链接

[root@sever1 html]# ls

cacti cacti-0.8.8h

[root@sever1 include]# /etc/init.d/mysqld start        #开启数据库

[root@sever1 include]# mysql_secure_installation

初始化,默认没密码,这里将密码设置成了redhat

[root@sever1 html]# cd cacti/                 

[root@sever1 cacti]# mysql -predhat -e "create databasecacti"      #创建名为cacti的数据库

[root@sever1 cacti]# mysql -predhat cacti < cacti.sql              #将cacti.sql文件导入到cacti数据库中

[root@sever1 cacti]# mysql -predhat -e "grant all oncacti.* to cacti@localhost identified by 'redhat'"                #创建本地cacti用户,并将cacti数据库的所有权限给cacti用户

[root@sever1 html]# cd include/               

[root@sever1 include]# vim config.php                  #修改配置文件
 29 $database_username ="cacti";                        #刚创建的cacti数据库的用户名

 30 $database_password ="redhat";                      #用户cacti的密码

 39 $url_path ="/cacti/";

 42 $cacti_session_name ="Cacti";
[root@sever1 cacti]# useradd -u 1000 cacti              #在系统中创建cacti用户

[root@sever1 cacti]# ll

total 1068

-rw-rw-r– 1 cacti cacti 5860 Feb 8 2016 about.php

-rw-rw-r– 1 cacti cacti 5348 Feb 8 2016 auth_changepassword.php

-rw-rw-r– 1 cacti cacti 14690 Mar 7 2016 auth_login.php

-rw-rw-r– 1 cacti cacti 178349 Apr 10 2012 cacti.sql

-rw-rw-r– 1 cacti cacti 20257 Feb 8 2016 cdef.php

[root@sever1 cacti]# su - cacti                        #切换到cacti用户

[cacti@sever1 ~]$ crontab -e                            #创建定时任务

*/5 * * * * php /var/www/html/cacti/poller.php > /dev/null2>&1

[cacti@sever1 ~]$ logout

[root@sever1 ~]# /etc/init.d/httpd start                #开启httpd

Stopping httpd: [ OK ]

安装cacti 172.25.25.1/cacti

点击next

监控
点击next
监控
在测试之前,时间得同步

B)测试 172.25.25.1/cacti

登陆 用户名:admin 密码:admin
监控
第一次登陆,会提示修改密码
监控
登陆之后,如图:
监控
点击graphs,如图:
监控

[root@sever1 cacti]# cd rra        #采集数据存放的位置

[root@sever1 rra]# ls

等待5分钟之后

[root@sever1 rra]# ls                  #已经有数据了

localhost_load_1min_5.rrd localhost_mem_swap_4.rrd localhost_users_6.rrd

localhost_mem_buffers_3.rrd localhost_proc_7.rrd

查看图像,如图:
监控

利用python探测谷歌搜索可用IP

原理是查询_netblocks.google.com域名的TXT记录,这个记录有大量网段的谷歌IP,再探测443端口开放的IP。不过探测出开放443端口的IP后,可能还要使用curl来检测是不是谷歌搜索的服务器。这一步需要与443端口ssl握手,但验证证书是否一致,使用python暂时写不出来,可以用curl https://www.google.com –resolve www.google.com:443:1.2.3.4,其中1.2.3.4为要探测的谷歌IP。
python脚本:

#!/usr/bin/python
# -*- coding:utf-8 -*-
'''
install modules:
pip install dnspython
'''

import dns.resolver
import struct, socket
import re
import sys
import threading
import Queue

threadLock = threading.Lock()
SHARE_Q = Queue.Queue()  
_WORKER_THREAD_NUM = 10
GLOBAL_COUNTER = 0

class MyThread(threading.Thread) :

    def __init__(self, func) :
        super(MyThread, self).__init__()
        self.func = func

    def run(self) :
        self.func()


def worker() :
    global SHARE_Q
    global GLOBAL_COUNTER
    while not SHARE_Q.empty():
        item = SHARE_Q.get()

        if check_port(item):
            with threadLock:
                print(item)
                GLOBAL_COUNTER += 1
                if GLOBAL_COUNTER >= 100:
                    sys.exit(0)

def get_txt_record(domain):
    answers = dns.resolver.query(domain, 'TXT')
    for rdata in answers:
        return str(rdata)


def get_ip_range_from_txt_record(txt_record):
    ip_range = []
    re_ret = re.findall(r'ip4:([^ ]+)', txt_record)
    for ip_mask in re_ret:
        ip_range.append(ip_mask)

    return ip_range

def get_ip_from_cidr(ip_range):
    ips = []
    for ip_mask in ip_range:
        (ip, cidr) = ip_mask.split('/')
        cidr = int(cidr) 
        host_bits = 32 - cidr
        i = struct.unpack('>I', socket.inet_aton(ip))[0] # note the endianness
        start = (i >> host_bits) << host_bits # clear the host bits
        end = i | ((1 << host_bits) - 1) 

        for i in range(start, end):
            ips.append(socket.inet_ntoa(struct.pack('>I',i)))

    return ips

def check_port(address, port=443):
    s=socket.socket()
    s.settimeout(1)  
    try:
        s.connect((address,port))
        return True
    except socket.error,e:
        return False

def main():
    txt_record = get_txt_record("_netblocks.google.com")
    ip_range = get_ip_range_from_txt_record(txt_record)
    ips = get_ip_from_cidr(ip_range)

    global SHARE_Q
    threads = []
    for task in ips :  
        SHARE_Q.put(task)

    for i in xrange(_WORKER_THREAD_NUM) :
        thread = MyThread(worker)
        thread.start()
        threads.append(thread)
    for thread in threads :
        thread.join()


if __name__ == '__main__':
    main()

shell脚本:


while read ip;do if curl -s -m 3 https://www.google.com.hk --resolve www.google.com.hk:443:$ip -o /dev/null;then echo $ip fi done < ip.txt

使用ps grep awk kill杀掉进程

程序成为僵尸进程以后需要通过进程号来强制终止,因此先需要获取进程的pid

 ps | grep test | awk 'NR==1{print $1}'  

获取test进程的ID,具体形式要按照linux输出的格式来,我的设备中的是第一行的第一列的第一个参数即为test的PID

由于通过管道把PID传给KILL -9无法生效。因此需要使用

ps | grep cwmpd | awk 'NR==1{print $1}' | xargs kill -9 

但是当前嵌入式设备上无法使用xargs 所以我们需要使用如下的方式:

 kill -9 `ps | grep test | awk 'NR==1{print $1}' `  # 注意这里是反单引号

或者:

 kill -9 $(ps | grep test | awk 'NR==1{print $1}') 

使用awk合并空行

[root@localhost ~]#cat urfile
[DEFAULT]
key1=value1
key2=value2
key3=value3


[agent]
key1=value1
key2=value2
key3=value3




[database]
key1=value1
key2=value2
key3=value3


[redis]
key1=value1
key2=value2
key3=value3

  

需求:
文本开头没有空行,section之间的空行行数不定,最后一个section之后也有n行空行,想将section之间的空行压缩成一行

解法一:
PF大神太绝了,直接一个cat -s urfile就搞定了;将多行空行合并成一行

解法二:
awk除去空行awk NF urfile
但没有做过将多行合并成一行,第一反应是用脚本
不过更喜欢awk一行流

[root@localhost ~]#awk -vRS="" '{print $0"n"}' urfile

  

开始对这个不是很理解,只是懂将行分隔符替换成空了

[root@localhost ~]#awk -vRS="" '{print NR $0"n"}' urfile
1[DEFAULT]
key1=value1
key2=value2
key3=value3

2[section1]
key1=value1
key2=value2
key3=value3

3[section2]
key1=value1
key2=value2
key3=value3

4[section3]
key1=value1
key2=value2
key3=value3
[root@localhost ~]#awk -vRS="" '{print $0"END"}' urfile
[DEFAULT]
key1=value1
key2=value2
key3=value3END
[section1]
key1=value1
key2=value2
key3=value3END
[section2]
key1=value1
key2=value2
key3=value3END
[section3]
key1=value1
key2=value2
key3=value3END

  

如果RS被设置为空,那么awk会将连续的空行作为行分隔符,与RS设置成”nn+”有什么区别???
1、忽略文件开头和结尾的空行。且文件不以记录分隔符结束,即最后不是空行,会将最后一个记录的尾n去掉
2、设置RT变量未空
3、影响FS变量
这个怎么理解?对于1、2两点,当作习题留给大家自己测试,3我们下节来讲。

总结下RS的3种情况:
1) 非空字符串
以固定字符串作为行分隔符,同时设置变量RT为固定字符串
2) 正则表达式
以正则表达式作为行分隔符,同时设置变量RT为正则表达式实际匹配到的字符串
3) 空字符
以连续的空行作为行分隔符,如果FS为单个字符,会将n强制加入到FS变量中

理解了RS,再来理解ORS就简单了。RS是awk读取文件时的行分隔符,ORS则是awk输出时的行结束符。
更简单的讲,就是awk在输出时,会在每行记录后面增加一个ORS变量所设定的值。
ORS的值只能设定为字符串,默认情况下,ORS的值是n

awk内置函数sub gensub gsub match等介绍

环境:
[root@MySQL ~]# cat /etc/issue
CentOS release 6.5 (Final)
Kernel r on an m
[root@MySQL ~]# awk –version
GNU Awk 3.1.7

1.asort和asorti

格式:

asort(s [, d])
asorti(s [, d]) 

功能及返回值:
asort:对数组进行排序,如果省略参数d,则修改数组s,如果提供参数d,则将数组s拷贝到d中然后进行排序,数组s不会被修改,排序后数组的下标从1开始;最终返回数组中元素个数

[root@MySQL ~]# awk 'BEGIN{a[0]="a";a[1]="c";a[2]="b";print "before sorting:";for(i in a){print i,a[i]};asort(a);print "after sorting:";for(i in a){print i,a[i]}}'

before sorting:
0 a
1 c
2 b
after sorting:
1 a
2 b
3 c

[root@mysql ~]# awk 'BEGIN{a[0]="a";a[1]="c";a[2]="b";print "before sorting:";for(i in a){print i,a[i]};asort(a,d);print "after sorting:";for(i in a){print i,a[i]};print ;for(i in d){print i,d[i]}}'

before sorting:
0 a
1 c
2 b
after sorting:
0 a
1 c
2 b

1 a
2 b
3 c

2.sub、gensub和gsub函数

格式:

sub(r, s [, t])
gsub(r, s [, t])
gensub(r, s, h [, t])

功能及返回值:
sub:对于t中匹配r的字串,将第一个匹配的子串替换为s,如果t省略,则t为$0;返回值为替换的字符串个数
gsub:对于t中匹配r的字串,将匹配的所有子串替换为s,如果t省略,则t为$0;返回值为替换的字符串个数
gensub:对于t中匹配r的字串,如果h是以”g”或”G”开头的字符串,则将匹配的所有子串替换为s,如果h是数字n,则将第n处匹配进行替换;如果参数t省略,则t为$0
sub及gsub案例

[root@MySQL ~]# awk 'BEGIN{r="or|ll";s="wj";t="hello,world!hello,awk";print sub(r,s,t),t}'

1 hewjo,world!hello,awk

[root@MySQL ~]# awk 'BEGIN{r="or|ll";s="wj";t="hello,world!hello,awk";print gsub(r,s,t),t}'

3 hewjo,wwjld!hewjo,awk

[root@MySQL ~]# echo "hello,world;hello,awk"|awk '{r="or|ll";s="wj";print sub(r,s),$0}'

1 hewjo,world;hello,awk

[root@MySQL ~]# echo "hello,world;hello,awk"|awk '{r="or|ll";s="wj";print gsub(r,s),$0}'

3 hewjo,wwjld;hewjo,awk

注:正则表达式另外一种写法

[root@MySQL ~]# echo "hello,world;hello,awk"|awk '{s="wj";print gsub(/or|ll/,s),$0}'

3 hewjo,wwjld;hewjo,awk

注:sub和gsub函数功能相同,前者指替换匹配的第一个字符串,而后者进行全局替换
gensub案例
省略参数t

[root@MySQL ~]# echo "hello,world!hello,awk!hello Linux!"|awk 'BEGIN{s="ww";r="ll"}{print gensub(r,s,"g")}'

hewwo,world!hewwo,awk!hewwo linux!

参数h以g或G开头

[root@MySQL ~]# awk 'BEGIN{s="ww";t="hello,world!hello,awk!hello linux!";r="ll";print gensub(r,s,"g",t)}'

hewwo,world!hewwo,awk!hewwo linux!

[root@MySQL ~]# awk 'BEGIN{s="ww";t="hello,world!hello,awk!hello linux!";r="ll";print gensub(r,s,"g1",t)}'

hewwo,world!hewwo,awk!hewwo linux!

[root@MySQL ~]# awk 'BEGIN{s="ww";t="hello,world!hello,awk!hello linux!";r="ll";print gensub(r,s,"G1",t)}'

hewwo,world!hewwo,awk!hewwo linux!

[root@MySQL ~]# awk 'BEGIN{s="ww";t="hello,world!hello,awk!hello linux!";r="ll";print gensub(r,s,"g1",t)}'

hewwo,world!hewwo,awk!hewwo linux!

[root@MySQL ~]# awk 'BEGIN{s="ww";t="hello,world!hello,awk!hello linux!";r="ll";print gensub(r,s,"G1",t)}'

hewwo,world!hewwo,awk!hewwo linux!

如果参数h不是数字也不以g或G开头,则替换第一处

[root@MySQL ~]# awk 'BEGIN{s="ww";t="hello,world!hello,awk!hello linux!";r="ll";print gensub(r,s,"a",t)}' 

hewwo,world!hello,awk!hello linux!

参数h是数字

[root@MySQL ~]# awk 'BEGIN{s="ww";t="hello,world!hello,awk!hello linux!";r="ll";print gensub(r,s,"1",t)}'

hewwo,world!hello,awk!hello linux!

[root@MySQL ~]# awk 'BEGIN{s="ww";t="hello,world!hello,awk!hello linux!";r="ll";print gensub(r,s,"3",t)}'

hello,world!hello,awk!hewwo linux!

[root@MySQL ~]# awk 'BEGIN{s="ww";t="hello,world!hello,awk!hello linux!";r="ll";print gensub(r,s,3,t)}'

hello,world!hello,awk!hewwo linux!

[root@MySQL ~]# awk 'BEGIN{s="ww";t="hello,world!hello,awk!hello linux!";r="ll";print gensub(r,s,0,t)}'

awk: warning: gensub: third argument of 0 treated as 1
hewwo,world!hello,awk!hello linux!

3..index函数

格式:

index(s, t)

功能及返回值:
返回字符串t在字符串s中的索引,如果字符串t在字符串s中不存在,则返回0(这表明字符串的索引是从1开始的)

[root@MySQL ~]# awk 'BEGIN{s="hello,world";t="llo";print index(s,t)}'

3

[root@MySQL ~]# awk 'BEGIN{s="hello,world";t="lloo";print index(s,t)}'

0

[root@MySQL ~]# awk 'BEGIN{s="hello,world";t="hello,world!";print index(s,t)}'

0

[root@MySQL ~]# awk 'BEGIN{s="hello,world";t="";print index(s,t)}'

1

注意:当字符串t为空时,返回的索引为1

4.length函数

格式:

length([s])

功能及返回值:
返回字符串s的长度,如果参数s省略,则返回$0的长度;从3.1.5版本开始,作为非标准扩展,如果参数为数组,则返回数组元素个数。

[root@MySQL ~]# awk 'BEGIN{s="hello,world";t="";print index(s,t)}'

1

[root@MySQL ~]# awk 'BEGIN{s="";print length(s)}'

0

[root@MySQL ~]# awk 'BEGIN{s=123;print length(s)}'

3

[root@MySQL ~]# awk 'BEGIN{s="hello world";print length(s)}'

11

[root@MySQL ~]# awk 'BEGIN{print length()}'

0

[root@MySQL ~]# echo "123 345" | awk '{print length()}'

7

5.match函数

格式:

match(s, r [, a])

功能及返回值:
当正则表达式r匹配字符串s中的某一部分时,返回匹配部分的索引,如果匹配不上,返回0,同时设置内置变量RSTART和RLENGTH;如果提供没有省略参数数组a,数组中的第1-n个元素为字符串s匹配正则表达式r中的带括号的子表达式的部分,数组a的第0个元素为字符串s匹配正则表达式r的完整匹配,数组的下标a[n, “start”]和a[n, “length”]分别表示匹配字符串的第一个字符的索引及匹配的字符串的长度。
可能描述地不是很清楚,下面通过例子来讲解
案例一:省略参数数组a

[root@MySQL ~]# awk 'BEGIN{s="hello,world!";r="ll";print match(s,r)}'

匹配ll,索引为3,返回值为3

3

[root@MySQL ~]# awk 'BEGIN{s="hello,world!";r="wj";print match(s,r)}'

匹配wj,没有匹配上,返回值为0
0

案例二:提供参数数组a(正则表达式中没有带括号的子表达式)

[root@MySQL ~]# awk 'BEGIN{s="hello,world!";r="ll";print match(s,r,a);print ;for(i in a){print "subscript:"i"t""valus:"a[i]}}'

3 #返回s中匹配ll的索引,为3

subscript:0 start valus:3 #数组a[0,”start”],值为s中匹配ll的索引,即3
subscript:0 length valus:2 #数组a[0,”length”],值为匹配的字符串的长度,即ll的长度,为2
subscript:0 valus:ll #数组a[0],值为匹配的字符串,即ll

另外一种写法,将正则表达式放在//中,和上面是同样的效果

[root@MySQL ~]# awk 'BEGIN{s="hello,world!";print match(s,/ll/,a);print ;for(i in a){print "subscript:"i"t""valus:"a[i]}}'

3

subscript:0start valus:3
subscript:0length valus:2
subscript:0 valus:ll

案例三:提供参数数组a(正则表达式中有带括号的子表达式)

[root@MySQL ~]# awk 'BEGIN{s="hello,world!";r="(ll).*(or.*d)";print match(s,r,a);print length(a);print ;for(i in a){print "subscript:"i"t""valus:"a[i]}}'

3 #匹配的字符串索引位置
9 #数组a中的元素个数

subscript:0start valus:3
subscript:0length valus:9
subscript:1start valus:3
subscript:2start valus:8
subscript:0 valus:llo,world
subscript:1 valus:ll
subscript:2 valus:orld
subscript:2length valus:4
subscript:1length valus:2

#上面输出数组a的元素顺序有点乱,整理下,如下:

subscript:0 valus:llo,world
subscript:0 start valus:3
subscript:0 length valus:9
subscript:1 valus:ll
subscript:1 start valus:3
subscript:1 length valus:2
subscript:2 valus:orld
subscript:2 start valus:8
subscript:2 length valus:4

当正则表达式中有带括号的子表达式时,数组a中的第0个元素为正则表达式的完整表达式,数组第1-n个元素为正则表达式中子表达式的内容

(ll).(or.d)

对于字符串“hello,world!”来说,

正则表达式(ll).(or.d)的的完整匹配为“llo,world”,所以a[0]的值为“llo,world”,a[0,”start”]为“llo,world”中的起始字符“l”在“hello,world!”中的索引,即3;a[0,”length”]为“llo,world”的长度,即9。

正则表达式(ll).(or.d)中的子表达式分别为(ll)和(or.*d),匹配“hello,world!”时,分别匹配”ll”和“orld”,所以a[1]和a[2]的值分别为”ll”和“orld”,a[n, “start”]和a[n, “length”](n=2,3)分别存储对应的索引和长度

注:
RSTART:match()函数匹配的第一个字符的索引;如果没有匹配,则为0
RLENGTH:match()函数匹配的字符串的长度;如果没有匹配,则为-1
RSTART The index of the first character matched by match(); 0 if no match. (Thisimplies that character indices start at one.)
RLENGTH The length of the string matched by match(); -1 if no match.

6.split函数

格式:

split(s, a [, r])

功能及返回值:将字符串s用正则表达式r作为分隔符进行分割,将分割的多个字段(域)存储到数组a中;如果r省略,用awk内置的FS变量对字符串s进行分割,将将分割的多个字段(域)存储到数组a中。返回分割的字段数也即数组中元素个数。

[root@MySQL ~]# awk 'BEGIN{s="hello,world;hello,awk";r=",";print split(s,a,r);for(i in a){print i,a[i]}}'

3
1 hello
2 world;hello
3 awk

[root@MySQL ~]# awk 'BEGIN{s="hello,world;hello,awk";r="hello";print split(s,a,r);for(i in a){print i,a[i]}}'

3
1
2 ,world;
3 ,awk

[root@MySQL ~]# head -n 1 /etc/passwd|awk 'BEGIN{s="hello,world;hello"}{print split(s,a);for(i in a){print i,a[i]}}'

1
1 hello,world;hello

[root@MySQL ~]# head -n 1 /etc/passwd|awk 'BEGIN{FS=";";s="hello,world;hello"}{print split(s,a);for(i in a){print i,a[i]}}'

2
1 hello,world
2 hello

注:FS变量的赋值也可以放在pattern+action外面

[root@MySQL ~]# head -n 1 /etc/passwd|awk -v FS=";" 'BEGIN{s="hello,world;hello"}{print split(s,a);for(i in a){print i,a[i]}}'

2
1 hello,world
2 hello

7.sprintf函数

对于该函数,后续会单独写一篇文章介绍

8.strtonum函数

格式:

strtonum(str)

功能及返回值:将字符串类型转化为数字类型,如果str以0开头则被转化为8进制,如果str以0x或0X开头则被转换为16进制

[root@MySQL ~]# awk 'BEGIN{s="123";print strtonum(s)}'
123
[root@MySQL ~]# awk 'BEGIN{s="0123";print strtonum(s)}'
83
[root@MySQL ~]# awk 'BEGIN{s="0x123";print strtonum(s)}'
291
[root@MySQL ~]# awk 'BEGIN{s="0X123";print strtonum(s)}'
291
[root@MySQL ~]# awk 'BEGIN{s="a123";print strtonum(s)}'
0
[root@MySQL ~]# awk 'BEGIN{s="12a3";print strtonum(s)}'
12
[root@MySQL ~]# awk 'BEGIN{s="123a";print strtonum(s)}'
123
[root@MySQL ~]# awk 'BEGIN{s="123.456";print strtonum(s)}'
123.456
[root@MySQL ~]# awk 'BEGIN{s="";print strtonum(s)}'
0

9.substr函数

格式:

substr(s, i [, n])

功能及返回值:
substr:返回字符串s中从索引i开始的最大长度为n字符串,如果n省略,则返回从索引i到字符串s末尾的字符串

[root@MySQL ~]# awk 'BEGIN{s="hello,world";print substr(s,2)}'
ello,world
[root@MySQL ~]# awk 'BEGIN{s="hello,world";print substr(s,2,5)}'
ello,
[root@MySQL ~]# awk 'BEGIN{s="hello,world";print substr(s,0)}'
hello,world
[root@MySQL ~]# awk 'BEGIN{s="hello,world";print substr(s,-2)}'
hello,world
[root@MySQL ~]# awk 'BEGIN{s="hello,world";print substr(s,3,-2)}'

[root@MySQL ~]# 

10.tolower和toupper函数

格式:

tolower(str)
toupper(str)

功能及返回值:
tolower:将字符转化为小写字母,非字母则不变
toupper:将字符转换为大写字母,非字母则不变

[root@MySQL ~]# awk 'BEGIN{s="HellO";print tolower(s)}'
hello
[root@MySQL ~]# awk 'BEGIN{s="^He;llO$";print tolower(s)}'
^he;llo$
[root@MySQL ~]# awk 'BEGIN{s="HellO";print toupper(s)}'
HELLO
[root@MySQL ~]# awk 'BEGIN{s="^He;llO$";print toupper(s)}'
^HE;LLO$

使用apt-mirror搭建ubuntu本地仓库

APT本地源的搭建(可用于局域网apt-get源搭建或者本地源)
本文档介绍使用apt-mirror软件搭建apt本地源
需求:内网开发环境由于其特定原因不能上外网,所以需要本地环境下的内网源来方便开发人员下载安装软件
建议:单独使用一块磁盘来存放源文件或者单独一个目录下,避免混淆

服务端配置

1、安装apt-mirror

apt-get install apt-mirror

2、修改apt-mirror配置文件

vim /etc/apt/mirror.list

参考以下配置文件:
清空原有的配置文件,直接使用以下配置文件即可


############# config ################## # 以下注释的内容都是默认配置,如果需要自定义,取消注释修改即可 set base_path /var/spool/apt-mirror # # 镜像文件下载地址 # set mirror_path $base_path/mirror # 临时索引下载文件目录,也就是存放软件仓库的dists目录下的文件(默认即可) # set skel_path $base_path/skel # 配置日志(默认即可) # set var_path $base_path/var # clean脚本位置 # set cleanscript $var_path/clean.sh # 架构配置,i386/amd64,默认的话会下载跟本机相同的架构的源 set defaultarch amd64 # set postmirror_script $var_path/postmirror.sh # set run_postmirror 0 # 下载线程数 set nthreads 20 set _tilde 0 # ############# end config ############## # Ali yun(这里没有添加deb-src的源) deb http://mirrors.aliyun.com/ubuntu/ trusty main restricted universe multiverse deb http://mirrors.aliyun.com/ubuntu/ trusty-security main restricted universe multiverse deb http://mirrors.aliyun.com/ubuntu/ trusty-updates main restricted universe multiverse deb http://mirrors.aliyun.com/ubuntu/ trusty-proposed main restricted universe multiverse deb http://mirrors.aliyun.com/ubuntu/ trusty-backports main restricted universe multiverse clean http://mirrors.aliyun.com/ubuntu

3、开始同步

执行

apt-miiror

然后等待很长时间(该镜像差不多100G左右,具体时间看网络环境),同步的镜像文件目录为/var/spool/apt-mirror/mirror/mirrors.aliyun.com/ubuntu/,当然如果增加了其他的源,在/var/spool/apt-mirror/mirror目录下还有其他的地址为名的目录。

4、安装apache2

apt-get install apache2

由于Apache2的默认网页文件目录位于/var/www/html,因此,可以做个软链接(这样我们就可以直接访问了,无需将其直接导入该目录)

ln -s /var/spool/apt-mirror/mirror/mirrors.aliyun.com/ubuntu /var/www/html/ubuntu

然后就可以通过如下地址访问了
http://[host]:[port]/ubuntu #ip和port是自己本机的,其中端口默认为80
在测试时可能遇到打不开的情况,查看下iptables规则是否限制或者selinux的问题(这点相信大家在学习lanmp的时候都已经了解过了)

客户端配置:

1、编辑/etc/apt/source.list,加入以下内容

# Local Source      #ip和port是自己本机的,其中端口默认为80
deb [arch=amd64] http://[host]:[port]/ubuntu/ trusty main restricted universe multiverse
deb [arch=amd64] http://[host]:[port]/ubuntu/ trusty-security main restricted universe multiverse
deb [arch=amd64] http://[host]:[port]/ubuntu/ trusty-updates main restricted universe multiverse  
deb [arch=amd64] http://[host]:[port]/ubuntu/ trusty-proposed main restricted universe multiverse
deb [arch=amd64] http://[host]:[port]/ubuntu/ trusty-backports main restricted universe multiverse

2、更新apt-get源

apt-update    #这步很重要

Ubuntu apt-cache列出版本列表并apt-get安装指定版本

一、通过apt-get安装指定版本

apt-get install <<package name>>=<<version>>

二、查询指定软件有多少个版本

说明:在Linux用这个查询并不能完全的把所有版本都列举出来,因为每个版本都与系统版本和CPU架构有关,比如一个软件支持Ubuntu系统的16.04的CPU架构为amd64的版本只有1.0和1.2,其余都不支持,所以列举时就只有两款。

列举版本列表:

0、通过网站搜索:

https://packages.ubuntu.com/

1、

apt-cache madison <<package name>>

将列出所有来源的版本。如下输出所示:

apt-cache madison vim
vim | 2:7.3.547-1 | http://debian.mirrors.tds.net/debian/ unstable/main amd64 Packages
vim | 2:7.3.429-2 | http://debian.mirrors.tds.net/debian/ testing/main amd64 Packages
vim | 2:7.3.429-2 | http://http.us.debian.org/debian/ testing/main amd64 Packages
vim | 2:7.3.429-2 | http://debian.mirrors.tds.net/debian/ testing/main Sources
vim | 2:7.3.547-1 | http://debian.mirrors.tds.net/debian/ unstable/main Sources
madison是一个apt-cache子命令,可以通过man apt-cache查询更多用法。

2、

apt-cache policy <<package name>>

将列出所有来源的版本。信息会比上面详细一点,如下输出所示:

apt-cache policy gdb
gdb:
  Installed: 7.7.1-0ubuntu5~14.04.2
  Candidate: 7.7.1-0ubuntu5~14.04.2
  Version table:
 *** 7.7.1-0ubuntu5~14.04.2 0
        500 http://fr.archive.ubuntu.com/ubuntu/ trusty-updates/main amd64 Packages
        100 /var/lib/dpkg/status
     7.7-0ubuntu3 0
        500 http://fr.archive.ubuntu.com/ubuntu/ trusty/main amd64 Packages
        500 http://archive.ubuntu.com/ubuntu/ trusty/main amd64 Packages

policy是一个apt-cache子命令,可以通过man apt-cache查询更多用法。

3、

apt-cache showpkg <<package name>>

4、

apt-get install -s <<package-name>>

说明:这个命令只是模拟安装时会安装哪些软件列表,但不会例举出每个软件有多少个版本

5、

aptitude versions <<package name>>

6、

apt-show-versions -a <<package name>>

说明:列举出所有版本,且能查看是否已经安装。还可以通过apt-show-versions -u <>来查询是否有升级版本。

7、

whohas -d Debian,Ubuntu <<package name>> | tr -s ' ' 't' | cut -f 1-3 | column -t

8、

rmadison -u debian,ubuntu,bpo <<package name>> | cut -d "|" -f 1-3

单个详情:

1、

apt-cache show <<package name>>

说明:查询指定包的详情,不管是否已经安装。

2、

dpkg -l <<package name>>

说明:效果和上面基本一致,但是结果是列表详情展示,会提示是否已经删除了之后还有依赖包没有删除等。

3、

dpkg -s <<package name>>

说明:必须是安装的包才能显示详情。

4、

dpkg-query -s <<package name>>

说明:同上,效果一致。

使用技巧:

1、可以在查询后面带上一些参数来实现筛选

apt-cache show package | grep Version
apt-show-versions | more

设置Apache 301跳转到https和www

一般我会较多的使用WORDPRESS程序,其在安装的时候我们如果直接用WWW打开,或者在后台设置WWW域名则默认会强制301指向WWW站点域名。而这里有使用ZBLOG或者TYPECHO等其他博客程序则不会默认301跳转。理论上从用户体验,还是从搜索引擎,最好是统一要么WWW,要么不带WWW格式的网址。

所以,我准备在Apache中用301跳转强制WWW格式,这里我是用的Apache虚拟主机环境所以直接在根目录的.htaccess文件设置就可以。

第一、强制WWW跳转

RewriteEngine on
RewriteCond %{HTTP_HOST} ^cnbanwagong.com [NC]
RewriteRule ^(.*)$ http://www.cnbanwagong.com/$1 [L,R=301,NC]

添加到伪静态文件中,立即生效。

第二、强制HTTPS格式

因为HTTPS加密格式网址也在陆续的流行和必须,所以我也在考虑和调整添加HTTPS格式的网址,毕竟免费SSL证书也比较多,添加也不复杂,刚才测试后还是可以的,唯独也需要将HTTPS强制跳转,因为HTTP和HTTPS也最好唯一。

RewriteEngine On
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://www.cnbanwagong.com/$1 [R,L]

同样的,可以在.htaccess文件中添加强制HTTPS跳转。

第三、补充301跳转

RewriteEngine On
RewriteCond %{HTTP_HOST} !^cnbanwagong.com$ [NC]
RewriteRule ^(.*)$ https://cnbanwagong.com/$1 [L,R=301]
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://cnbanwagong.com/$1 [L,R=301]

如果我们有朋友喜欢用不带WWW的格式,所以我们也可以强制不带WWW跳转和HTTPS强制不带WWW。