老司机种菜


  • 首页

  • 分类

  • 关于

  • 归档

  • 标签

  • 公益404

  • 搜索

l-python-env

发表于 2019-06-17

pip install -r requirements.txt conda install –yes –file requirements.txt

pip批量导出包含环境中所有组件的requirements.txt文件

1
pip freeze > requirements.txt

pip批量安装requirements.txt文件中包含的组件依赖

1
pip install -r requirements.txt

conda批量导出包含环境中所有组件的requirements.txt文件

1
conda list -e > requirements.txt

pip批量安装requirements.txt文件中包含的组件依赖

1
conda install --yes --file requirements.txt

使用sphinx自动提取python中的注释成为接口文档

发表于 2019-06-16 | 分类于 language

写好了代码,交付给他人使用的时候,查看代码固然可以了解各类和函数的功能细节,但接口文档能更方便的查找和说明功能。所以,一价与代码同步的接口文档是很有必要的。sphinx可以根据python中的注释,自动的生成接口文档,这样有利于保证文档和代码功能的同步。让我们来了解如何自动生成文档。

1
2
3
4
5
6
7
8
9
10
class A:
'''
你好!
'''
@staticmethod
def Aa():
'''
你也好!
'''
fun1()

看到类和函数中,都加入了注释。

  1. 安装shpinx
    1
    pip install sphinx -i https://pypi.doubanio.com/simple --trusted-host pypi.doubanio.com

使用国内的镜像安装比较快。

  1. 配置shpinx
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    $ cd myproject
    $ sphinx-quickstart
    Enter the root path for documentation.
    > Root path for the documentation [.]: doc
    > Project name: XXX
    > Author name(s): XXX
    > Project version []: 1.0
    > Project release [1.0]:
    > Project language [en]: zh_CN #如果注释中有中文,这里必须设置。否则生成接口文档出错。
    > autodoc: automatically insert docstrings from modules (y/n) [n]: y
    其它项都选择默认

完成之后,会在当前目录创建 doc 目录,所有sphinx相关的文件都在 doc目录下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$ ls doc/
_build conf.py index.rst Makefile _static _templates
$ vi doc/conf.py #修改文件内容
sys.path.insert(0, os.path.abspath('.'))
sys.path.insert(0, os.path.abspath('..')) # 缺少此行会导致在make html时提示 __import__出错,找不到module。 所以必须把上一级目录(即代码所在目录)include进来

$ sphinx-apidoc -o doc/ .
Creating file doc/a.rst.
Creating file doc/modules.rst

# 把生成的 doc/modules.rst添加到index.rst
$ vi doc/index.rst

Contents:
.. toctree::
:maxdepth: 2

modules.rst

生成html页面
$ cd doc
$ make html

生成的html文档,在doc/_build/html里。

sphinx对仅工作在python2.7 或python3上。当文件中有中文时,可能会报错:’ascii’ codec can’t decode byte 0xe2 in position xxx。可以在报错的地方加入:

1
2
3
import sys
reload(sys)
sys.setdefaultencoding('utf-8')

db-redis

发表于 2019-06-16

MAC环境安装

安装

  1. 首先是官网下载redis,下载 stable 版本,稳定版本。
  2. 安装与编译:
  • 解压:tar zxvf redis-4.0.10.tar.gz
  • 移动到: mv redis-4.0.10 /usr/local/
  • 切换到:cd /usr/local/redis-4.0.10/
  • 编译测试 sudo make test,如果在第5步测试时报如下错:Executing test client: couldn’t execute “src/redis-benchmark”: no such file or directory.则执行以下两个步骤 sudo make distclean和sudo make
  • 编译安装 sudo make install
  1. 安装成功测试:输入redis-server启动redis
  2. 测试redis:新建一个终端窗口,输入命令行redis-cli

处理异常

在长时间不操作redis数据库,再次进行set key 值时,会报错误 (error) MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for details about the error.

(错误)misconf redis被配置以保存数据库快照,但misconf redis目前不能在硬盘上持久化。用来修改数据集合的命令不能用,请使用日志的错误详细信息。

解决方案如下: 运行 config set stop-writes-on-bgsave-error no命令,关闭配置项stop-writes-on-bgsave-error解决该问题。

redis的配置

Redis 的配置文件位于 Redis 安装目录下,文件名为 redis.conf。

你可以通过 修改redis.conf配置和使用CONFIG SET 命令设置配置项。

1
redis 127.0.0.1:6379> CONFIG SET CONFIG_SETTING_NAME NEW_CONFIG_VALUE
1
2
3
4
5
6
redis 127.0.0.1:6379> CONFIG SET loglevel "notice"
OK
redis 127.0.0.1:6379> CONFIG GET loglevel

1) "loglevel"
2) "notice"

参数说明

redis.conf 配置项说明如下:

  1. Redis默认不是以守护进程的方式运行,可以通过该配置项修改,使用yes启用守护进程

    1
    daemonize no
  2. 当Redis以守护进程方式运行时,Redis默认会把pid写入/var/run/redis.pid文件,可以通过pidfile指定

    1
    pidfile /var/run/redis.pid
  3. 指定Redis监听端口,默认端口为6379,作者在自己的一篇博文中解释了为什么选用6379作为默认端口,因为6379在手机按键上MERZ对应的号码,而MERZ取自意大利歌女Alessia Merz的名字

    1
    port 6379
  4. 绑定的主机地址

    1
    bind 127.0.0.1

5.当 客户端闲置多长时间后关闭连接,如果指定为0,表示关闭该功能

1
timeout 300
  1. 指定日志记录级别,Redis总共支持四个级别:debug、verbose、notice、warning,默认为verbose

    1
    loglevel verbose
  2. 日志记录方式,默认为标准输出,如果配置Redis为守护进程方式运行,而这里又配置为日志记录方式为标准输出,则日志将会发送给/dev/null

    1
    logfile stdout
  3. 设置数据库的数量,默认数据库为0,可以使用SELECT <dbid>命令在连接上指定数据库id

    1
    databases 16
  4. 指定在多长时间内,有多少次更新操作,就将数据同步到数据文件,可以多个条件配合

    1
    2
    3
    4
    5
    6
    save <seconds> <changes>
    Redis默认配置文件中提供了三个条件:
    save 900 1
    save 300 10
    save 60 10000
    分别表示900秒(15分钟)内有1个更改,300秒(5分钟)内有10个更改以及60秒内有10000个更改。
  5. 指定存储至本地数据库时是否压缩数据,默认为yes,Redis采用LZF压缩,如果为了节省CPU时间,可以关闭该选项,但会导致数据库文件变的巨大

    1
    rdbcompression yes
  6. 指定本地数据库文件名,默认值为dump.rdb

    1
    dbfilename dump.rdb
  7. 指定本地数据库存放目录

    1
    dir ./
  8. 设置当本机为slav服务时,设置master服务的IP地址及端口,在Redis启动时,它会自动从master进行数据同步

    1
    slaveof <masterip> <masterport>
  9. 当master服务设置了密码保护时,slav服务连接master的密码

    1
    masterauth <master-password>
  10. 设置Redis连接密码,如果配置了连接密码,客户端在连接Redis时需要通过AUTH <password>命令提供密码,默认关闭

    1
    requirepass foobared
  11. 设置同一时间最大客户端连接数,默认无限制,Redis可以同时打开的客户端连接数为Redis进程可以打开的最大文件描述符数,如果设置 maxclients 0,表示不作限制。当客户端连接数到达限制时,Redis会关闭新的连接并向客户端返回max number of clients reached错误信息

    1
    maxclients 128
  12. 指定Redis最大内存限制,Redis在启动时会把数据加载到内存中,达到最大内存后,Redis会先尝试清除已到期或即将到期的Key,当此方法处理 后,仍然到达最大内存设置,将无法再进行写入操作,但仍然可以进行读取操作。Redis新的vm机制,会把Key存放内存,Value会存放在swap区

    1
    maxmemory <bytes>
  13. 指定是否在每次更新操作后进行日志记录,Redis在默认情况下是异步的把数据写入磁盘,如果不开启,可能会在断电时导致一段时间内的数据丢失。因为 redis本身同步数据文件是按上面save条件来同步的,所以有的数据会在一段时间内只存在于内存中。默认为no

    1
    appendonly no
  14. 指定更新日志文件名,默认为appendonly.aof

    1
    appendfilename appendonly.aof
  15. 指定更新日志条件,共有3个可选值:

    • no:表示等操作系统进行数据缓存同步到磁盘(快)
    • always:表示每次更新操作后手动调用fsync()将数据写到磁盘(慢,安全)
    • everysec:表示每秒同步一次(折衷,默认值)

    appendfsync everysec

  16. 指定是否启用虚拟内存机制,默认值为no,简单的介绍一下,VM机制将数据分页存放,由Redis将访问量较少的页即冷数据swap到磁盘上,访问多的页面由磁盘自动换出到内存中(在后面的文章我会仔细分析Redis的VM机制)

    1
    vm-enabled no
  17. 虚拟内存文件路径,默认值为/tmp/redis.swap,不可多个Redis实例共享

    1
    vm-swap-file /tmp/redis.swap
  18. 将所有大于vm-max-memory的数据存入虚拟内存,无论vm-max-memory设置多小,所有索引数据都是内存存储的(Redis的索引数据 就是keys),也就是说,当vm-max-memory设置为0的时候,其实是所有value都存在于磁盘。默认值为0

    1
    vm-max-memory 0
  19. Redis swap文件分成了很多的page,一个对象可以保存在多个page上面,但一个page上不能被多个对象共享,vm-page-size是要根据存储的 数据大小来设定的,作者建议如果存储很多小对象,page大小最好设置为32或者64bytes;如果存储很大大对象,则可以使用更大的page,如果不 确定,就使用默认值

    1
    vm-page-size 32
  20. 设置swap文件中的page数量,由于页表(一种表示页面空闲或使用的bitmap)是在放在内存中的,,在磁盘上每8个pages将消耗1byte的内存。

    1
    vm-pages 134217728
  21. 设置访问swap文件的线程数,最好不要超过机器的核数,如果设置为0,那么所有对swap文件的操作都是串行的,可能会造成比较长时间的延迟。默认值为4

    1
    vm-max-threads 4
  22. 设置在向客户端应答时,是否把较小的包合并为一个包发送,默认为开启

    1
    glueoutputbuf yes
  23. 指定在超过一定的数量或者最大的元素超过某一临界值时,采用一种特殊的哈希算法

    1
    2
    3
    hash-max-zipmap-entries 64

    hash-max-zipmap-value 512
  24. 指定是否激活重置哈希,默认为开启(后面在介绍Redis的哈希算法时具体介绍)

    1
    activerehashing yes
  25. 指定包含其它的配置文件,可以在同一主机上多个Redis实例之间使用同一份配置文件,而同时各个实例又拥有自己的特定配置文件

    1
    include /path/to/local.conf

参考

http://www.runoob.com/redis/redis-tutorial.html

Centos环境安装

下载地址:https://redis.io/download

下载安装

下载源码,解压缩到 /usr/local/ 重命名成 redis,编译安装

1
2
3
4
5
6
wget http://download.redis.io/releases/redis-5.0.5.tar.gz
cd /usr/local
tar xzf /root/redis-5.0.5.tar.gz
mv redis-5.0.5 redis
cd redis
make && make install

复制配置文件到 /etc

1
cp redis.conf /etc/

参数查看

1
redis-server --help

版本参看

1
redis-server -v

启动Redis服务器

1
redis-server /etc/redis.conf

注:此命令仅有一个启动参数,指定/path/to/redis.conf目录下的配置文件,不加参数执行默认配置。

退出关闭按 ctlr+c

设置后台运行,进入etc

1
vim /etc/redis.conf

修改 daemonize no 为 daemonize yes,这样就可以默认启动就后台运行

测试启动,返回PONG,启动成功。

1
2
redis-server /etc/redis.conf
redis-cli ping
1
2
[root@localhost redis-4.0.1]# netstat -tulnp | grep 6379 
tcp 0 0 127.0.0.1:6379 0.0.0.0:* LISTEN 7949/redis-server 1

停止Redis

关闭服务

1
2
redis-cli shutdown
netstat -tulnp | grep 6379
1
redis-cli ping

Could not connect to Redis at 127.0.0.1:6379: Connection refused

注:可指定端口:redis-cli -p <port> shutdown

连接Redis

两种链接redis的方法: 方法一、

1
2
3
redis-cli      #也可以指定ip,端口号启动redis(redis-cli -h 192.168.1.2 -p 6379) 
127.0.0.1:6379>
127.0.0.1:6379> quit

方法二、

1
2
3
4
5
6
7
telnet 192.168.1.2 6379 
Trying 192.168.1.2...
Connected to 192.168.1.2.
Escape character is '^]'.
quit
+OK
Connection closed by foreign host

设置开机启动

设置 /etc/redis.conf 中 daemonize 为 yes,确保守护进程开启,也就是在后台可以运行.(设置为yes后,启动时好像没有redis的启动界面,不知道为什么) 编写脚本

1
vim /etc/init.d/redis

复制下面代码到脚本中(注意要修改里面redis的安装路径,以 /usr/local/redis 路径为例)(这段代码就是redis根目录 /utils/redis_init_script 启动脚本的代码)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#!/bin/sh
# chkconfig: 2345 10 90
# description: Start and Stop redis

REDISPORT=6379
EXEC=/usr/local/redis/src/redis-server
CLIEXEC=/usr/local/redis/src/redis-cli

PIDFILE=/var/run/redis_${REDISPORT}.pid
CONF="/etc/redis.conf"

case "$1" in
start)
if [ -f $PIDFILE ]
then
echo "$PIDFILE exists, process is already running or crashed"
else
echo "Starting Redis server..."
$EXEC $CONF &
fi
;;
stop)
if [ ! -f $PIDFILE ]
then
echo "$PIDFILE does not exist, process is not running"
else
PID=$(cat $PIDFILE)
echo "Stopping ..."
$CLIEXEC -p $REDISPORT shutdown
while [ -x /proc/${PID} ]
do
echo "Waiting for Redis to shutdown ..."
sleep 1
done
echo "Redis stopped"
fi
;;
restart)
"$0" stop
sleep 3
"$0" start
;;
*)
echo "Please use start or stop or restart as first argument"
;;
esac

保存退出,设置权限

1
chmod 777 /etc/init.d/redis

启动redis

1
service redis start

设置开机启动

1
chkconfig redis on

测试开机启动

1
reboot

开机完成测试redis是否打开

1
redis-cli ping

db-mongo

发表于 2019-06-16

Mongo之安装

参考

Centos

1.下载安装包

远程安装mongodb压缩包

1
wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-3.4.9.tgz
2.解压缩安装包

在/opt下创建modules文件夹

1
mkdir modules

然后解压到这里:

1
2
cd ~
tar -xzvf mongodb-linux-x86_64-3.4.9.tgz -C /opt/modules/

进入modules文件夹

1
cd /opt/modules/

重命名为mongodb

1
2
mv mongodb-linux-x86_64-3.4.9 mongodb 
cd mongodb/
3.创建数据库存放目录和日志存放目录

将服务的数据存放在/opt/data目录下,需要创建db目录用于存放数据库文件,logs目录存放日志文件:

1
2
3
4
mkdir -p /opt/data/mongodb/data 
mkdir -p /opt/data/mongodb/data/db
mkdir -p /opt/data/mongodb/data/logs
touch /opt/data/mongodb/data/logs/mogodb.log
4.创建MongoDB配置文件mongodb.conf

mongodb.conf主要配置MongoDB的监听端口,数据库目录,日志存放位置,日志输出方式以及是否开启后台运行等:

1
2
cd /opt/data/mongodb/data/ 
vim mongodb.conf

mongodb.conf 具体配置信息如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 端口号 
port=27017
# 数据库路径
dbpath=/opt/data/mongodb/data/db
# 日志输出文件路径
logpath=/opt/data/mongodb/data/logs/mongodb.log
pidfilepath=/opt/data/mongodb/data/mongo.pid
# 设置后台运行
fork=true
# 日志输出方式
logappend=true
# 启动http界面,端口号为28017
httpinterface=true
5.启动MongoDB服务

执行以下命令启动MongoDB服务:

1
2
cd /opt/modules/mongodb/ 
bin/mongod --config /opt/data/mongodb/data/mongodb.conf

会打印下面信息:about to fork child process, waiting until server is ready for connections. forked process: 20913 child process started successfully, parent exiting

6.验证MongoDB服务是否启动成功
1
lsof -i:27017

成功打印COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME mongod 20913 root 7u IPv4 376964 0t0 TCP *:27017 (LISTEN) 可以通过ip访问,http://你的公网ip:28017/, 显示数据库一些信息,说明启动成功了 It looks like you are trying to access MongoDB over HTTP on the native driver port.

ubuntu环境

ubunut下安装

步骤
  1. Update Homebrew’s package database. In a system shell ,issue the following command:

    brew update

  2. Install MongoDB. You can install MongoDB via brew with several different options.Use one of the following operations:

    • Install the MongoDB binaries To install the MongoDB binaries ,issue the following command in system shell:

      brew install mongodb

    • Install the MongoDB Binaries with TLS/SSL Support To install the MongoDB binaries that have TLS/SSL suport ,issue the following from a system shell:

      brew install mongodb –with-openssl

    • Install the Lastest Development Release of MongoDB To install the lastest development release for use in testing and development,issue the following command in a system shell:

      brew install mongodb –devel

  3. Install MongoDB Community Edition Manually. Only install MongoDB Community Edition using this procedure if you cannot use homebrew.

    • Download the binary files for the desired release of MongoDB
      Download the binaries from https://www.mongodb.org/downloads.
      For example, to download the latest release through the shell, issue the following:

      curl -O https://fastdl.mongodb.org/osx/mongodb-osx-x86_64-3.2.6.tgz

    • Extract the files from the downloaded archive.
      For example, from a system shell, you can extract through the tar command:

      tar -zxvf mongodb-osx-x86_64-3.2.6.tgz

    • Copy the extracted archive to the target directo
      Copy the extracted folder to the location from which MongoDB will run.

      mkdir -p mongodb

      cp -R -n mongodb-osx-x86_64-3.2.6/ mongodb
    • Ensure the location of the binaries is in the PATH variable.
      The MongoDB binaries are in the bin/ directory of the archive. To ensure that the binaries are in your PATH, you can modify your PATH.
      For example, you can add the following line to your shell’s rc file (e.g. ~/.bashrc):

      export PATH=/bin:$PATH

Replace with the path to the extracted MongoDB archive.

brew 安装结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
brew install mongodb
==> Installing dependencies for mongodb: openssl
==> Installing mongodb dependency: openssl
==> Downloading https://homebrew.bintray.com/bottles/openssl-1.0.2h_1.el_capitan
######################################################################## 100.0%
==> Pouring openssl-1.0.2h_1.el_capitan.bottle.tar.gz
==> Caveats
A CA file has been bootstrapped using certificates from the system
keychain. To add additional certificates, place .pem files in
/usr/local/etc/openssl/certs

and run
/usr/local/opt/openssl/bin/c_rehash

This formula is keg-only, which means it was not symlinked into /usr/local.

Apple has deprecated use of OpenSSL in favor of its own TLS and crypto libraries

Generally there are no consequences of this for you. If you build your
own software and it requires this formula, you'll need to add to your
build variables:

LDFLAGS: -L/usr/local/opt/openssl/lib
CPPFLAGS: -I/usr/local/opt/openssl/include

==> Summary
🍺 /usr/local/Cellar/openssl/1.0.2h_1: 1,691 files, 12M
==> Installing mongodb
==> Downloading https://homebrew.bintray.com/bottles/mongodb-3.2.6.el_capitan.bo
######################################################################## 100.0%
==> Pouring mongodb-3.2.6.el_capitan.bottle.tar.gz
==> Caveats
To have launchd start mongodb now and restart at login:
brew services start mongodb
Or, if you don't want/need a background service you can just run:
mongod --config /usr/local/etc/mongod.conf
==> Summary
🍺 /usr/local/Cellar/mongodb/3.2.6: 17 files, 263.8M
Run MongoDB

1.Create the data directory Before you start MongoDB for the first time ,create the directory to which the mongod process will write data.By default ,the mongod process uses the /data/db/directory.If you create a directory other than this one ,you must specify that directory in the dbpath option when starting the mongod proecss later in this peocedure. The following example command creates the default /data/db directory:

1
mkdir -p /data/db

2.Set permissions for the data direcory. Before running mongod for the first time,ensure that the user account running mongod has read and write permissions for the directory. 3.Run MongoDB. To run MongoDB,run the mongod process at the system prompt.If necessary,specify the path the mongod or the data directory.See the following examples.

  • Run without specifying paths If your system Path variable includes the location of the mongod binary and if you use the default data directory(i.e.,/data/db),simply enter mongod at the system prompt:

    1
    mongod
  • Specify the path of the mongod If your PATH does not include the location of the mongod binary,enter the full path to the mongod binary at the system prompt:

    1
    <path to binary>/mongod
  • Specify the path of the data directory If you do not use the defautl data directory (i.i.,/data/db),specify the path to the data directory using the –dbpath option:

    1
    mongod --dbpath <path to data directory>
  • Begin using MongoDB. mongod 默认数据保存路径:/data/db/ 默认端口:27017 修改默认路径:–dbpath 修改默认端口:–port 启动后台服务:–fork(必须使用–logpath自动创建日志输出目录)

注意事项

1.启动

  • mongod 启动mongo服务
  • mongo 启动客户端

2.停止服务

  • 方法一 ps -ef | grep mongodb 找到你要查找的进程号 kill - 2 pid 杀掉

  • 方法二 进入mongo数据库里面进行操作

    1
    2
    3
    mongo
    use admin
    db.shutdownServer();
  • 错误 在linux下大家停止很多服务喜欢直接kill -9 PID,但是对于MongoDB如果执行了kill - 9 PID,在下次启动时可能提示错误,导致服务无法启动,这个时候可以通过执行:rm -f path/db/mongod.lock,也即删除指定数据目录下的mongod.lock问价即可.

错误

I’ve just installed MOngoDB via homebrew und want to start it via command line mongod.

When I do that, i’ll get this message:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2016-03-05T19:23:55.763+0100 I CONTROL  [initandlisten] MongoDB starting : pid=52426 port=27017 dbpath=/data/db 64-bit host=Matthias-MBP
2016-03-05T19:23:55.764+0100 I CONTROL [initandlisten] db version v3.2.3
2016-03-05T19:23:55.764+0100 I CONTROL [initandlisten] git version: b326ba837cf6f49d65c2f85e1b70f6f31ece7937
2016-03-05T19:23:55.764+0100 I CONTROL [initandlisten] allocator: system
2016-03-05T19:23:55.764+0100 I CONTROL [initandlisten] modules: none
2016-03-05T19:23:55.764+0100 I CONTROL [initandlisten] build environment:
2016-03-05T19:23:55.764+0100 I CONTROL [initandlisten] distarch: x86_64
2016-03-05T19:23:55.764+0100 I CONTROL [initandlisten] target_arch: x86_64
2016-03-05T19:23:55.764+0100 I CONTROL [initandlisten] options: {}
2016-03-05T19:23:55.765+0100 I - [initandlisten] Detected data files in /data/db created by the 'wiredTiger' storage engine, so setting the active storage engine to 'wiredTiger'.
2016-03-05T19:23:55.765+0100 I STORAGE [initandlisten] wiredtiger_open config: create,cache_size=4G,session_max=20000,eviction=(threads_max=4),config_base=false,statistics=(fast),log=(enabled=true,archive=true,path=journal,compressor=snappy),file_manager=(close_idle_time=100000),checkpoint=(wait=60,log_size=2GB),statistics_log=(wait=0),
2016-03-05T19:23:56.483+0100 I CONTROL [initandlisten]
2016-03-05T19:23:56.483+0100 I CONTROL [initandlisten] ** WARNING: soft rlimits too low. Number of files is 256, should be at least 1000
2016-03-05T19:23:56.486+0100 I NETWORK [HostnameCanonicalizationWorker] Starting hostname canonicalization worker
2016-03-05T19:23:56.486+0100 I FTDC [initandlisten] Initializing full-time diagnostic data capture with directory '/data/db/diagnostic.data'
2016-03-05T19:23:56.488+0100 I NETWORK [initandlisten] waiting for connections on port 27017
2016-03-05T19:23:56.513+0100 W NETWORK [HostnameCanonicalizationWorker] Failed to obtain address information for hostname Matthias-MBP: nodename nor servname provided, or not known

The last line doesn’t sound correct. What is the problem? The first line of logs says

1
MongoDB starting : pid=52426 port=27017 dbpath=/data/db 64-bit host=Matthias-MBP".

Notice that host name is Matthias-MBP, so you can add 127.0.0.1 Matthias-MBP in /etc/hosts file. After Ctrl-C and re-run mongod, the error message will disappear.

操作相关

数据库

  1. Help查看命令提示

    1
    2
    3
    4
    5
    help
    db.help();
    db.yourColl.help();
    db.youColl.find().help();
    rs.help();
  2. 切换/创建数据库

    1
    2
    >use yourDB;
    当创建一个集合(table)的时候会自动创建当前数据库
  3. 查询所有数据库

    1
    show dbs;
  4. 删除当前使用数据库

    1
    db.dropDatabase();
  5. 从指定主机上克隆数据库

    1
    2
    db.cloneDatabase(“127.0.0.1”);
    将指定机器上的数据库的数据克隆到当前数据库
  6. 从指定的机器上复制指定数据库数据到某个数据库

    1
    2
    db.copyDatabase("mydb", "temp", "127.0.0.1");
    将本机的mydb的数据复制到temp数据库中
  7. 修复当前数据库

    1
    db.repairDatabase();
  8. 查看当前使用的数据库

    1
    2
    3
    db.getName();
    db;
    db和getName方法是一样的效果,都可以查询当前使用的数据库
  9. 显示当前db状态

    1
    db.stats();
  10. 当前db版本

    1
    db.version();
  11. 查看当前db的链接机器地址

    1
    db.getMongo();

Collection聚集集合

  1. 创建一个聚集集合(table)

    1
    db.createCollection(“collName”, {size: 20, capped: 5, max: 100});
  2. 得到指定名称的聚集集合(table)

    1
    db.getCollection("account");
  3. 得到当前db的所有聚集集合

    1
    db.getCollectionNames();
  4. 显示当前db所有聚集索引的状态

    1
    db.printCollectionStats();

用户相关

  1. 添加一个用户
    1
    2
    db.addUser("name");
    db.addUser("userName", "pwd123", true);

添加用户、设置密码、是否只读

  1. 数据库认证、安全模式

    1
    db.auth("userName", "123123");
  2. 显示当前所有用户

    1
    show users;
  3. 删除用户

    1
    db.removeUser("userName");

其他

  1. 查询之前的错误信息

    1
    db.getPrevError();
  2. 清除错误记录

    1
    db.resetError();

Collection聚合集合操作

###查看聚集集合基本信息

  1. 查看帮助

    1
    db.yourColl.help();
  2. 查询当前集合的数据条数

    1
    db.yourColl.count();
  3. 查看数据空间大小

    1
    db.userInfo.dataSize();
  4. 得到当前聚集集合所在的db

    1
    db.userInfo.getDB();
  5. 得到当前聚集的状态

    1
    db.userInfo.stats();
  6. 得到聚集集合总大小

    1
    db.userInfo.totalSize();
  7. 聚集集合储存空间大小

    1
    db.userInfo.storageSize();
  8. Shard版本信息

    1
    db.userInfo.getShardVersion()
  9. 聚集集合重命名

    1
    db.userInfo.renameCollection("users");

将userInfo重命名为users

  1. 删除当前聚集集合
    1
    db.userInfo.drop();

聚集集合查询

  1. 查询所有记录
    1
    db.userInfo.find();

相当于:select * from userInfo; 默认每页显示20条记录,当显示不下的情况下,可以用it迭代命令查询下一页数据。注意:键入it命令不能带“;” 但是你可以设置每页显示数据的大小,用DBQuery.shellBatchSize = 50;这样每页就显示50条记录了。

  1. 查询去掉后的当前聚集集合中的某列的重复数据
    1
    db.userInfo.distinct("name");

会过滤掉name中的相同数据 相当于:select distict name from userInfo;

  1. 查询age = 22的记录 db.userInfo.find({"age": 22}); 相当于: select * from userInfo where age = 22;

  2. 查询age > 22的记录 db.userInfo.find({age: {$gt: 22}}); 相当于:select * from userInfo where age > 22;

  3. 查询age < 22的记录 db.userInfo.find({age: {$lt: 22}}); 相当于:select * from userInfo where age < 22;

  4. 查询age >= 25的记录 db.userInfo.find({age: {$gte: 25}}); 相当于:select * from userInfo where age >= 25;

  5. 查询age <= 25的记录 db.userInfo.find({age: {$lte: 25}});

  6. 查询age >= 23 并且 age <= 26 db.userInfo.find({age: {$gte: 23, $lte: 26}});

  7. 查询name中包含 mongo的数据 db.userInfo.find({name: /mongo/}); //相当于%% select * from userInfo where name like ‘%mongo%’;

  8. 查询name中以mongo开头的 db.userInfo.find({name: /^mongo/}); select * from userInfo where name like ‘mongo%’;

  9. 查询指定列name、age数据 db.userInfo.find({}, {name: 1, age: 1}); 相当于:select name, age from userInfo; 当然name也可以用true或false,当用ture的情况下河name:1效果一样,如果用false就是排除name,显示name以外的列信息。

12、查询指定列name、age数据, age > 25 db.userInfo.find({age: {$gt: 25}}, {name: 1, age: 1}); 相当于:select name, age from userInfo where age > 25;

  1. 按照年龄排序 升序:db.userInfo.find().sort({age: 1}); 降序:db.userInfo.find().sort({age: -1});

  2. 查询name = zhangsan, age = 22的数据 db.userInfo.find({name: 'zhangsan', age: 22}); 相当于:select * from userInfo where name = ‘zhangsan’ and age = ‘22’;

  3. 查询前5条数据 db.userInfo.find().limit(5); 相当于:select top 5 * from userInfo;

  4. 查询10条以后的数据 db.userInfo.find().skip(10); 相当于:select * from userInfo where id not in ( select top 10 * from userInfo );

  5. 查询在5-10之间的数据 db.userInfo.find().limit(10).skip(5); 可用于分页,limit是pageSize,skip是第几页*pageSize

  6. or与 查询 db.userInfo.find({$or: [{age: 22}, {age: 25}]}); 相当于:select * from userInfo where age = 22 or age = 25;

  7. 查询第一条数据 db.userInfo.findOne(); 相当于:select top 1 * from userInfo; db.userInfo.find().limit(1);

  8. 查询某个结果集的记录条数 db.userInfo.find({age: {$gte: 25}}).count(); 相当于:select count(*) from userInfo where age >= 20;

  9. 按照某列进行排序 db.userInfo.find({sex: {$exists: true}}).count(); 相当于:select count(sex) from userInfo;

索引

  1. 创建索引

    1
    2
    db.userInfo.ensureIndex({name: 1});
    db.userInfo.ensureIndex({name: 1, ts: -1});
  2. 查询当前聚集集合所有索引 db.userInfo.getIndexes();

  3. 查看总索引记录大小 db.userInfo.totalIndexSize();

  4. 读取当前集合的所有index信息 db.users.reIndex();

  5. 删除指定索引 db.users.dropIndex("name_1");

  6. 删除所有索引索引 db.users.dropIndexes();

修改、添加、删除集合数据

  1. 添加 db.users.save({name: ‘zhangsan’, age: 25, sex: true}); 添加的数据的数据列,没有固定,根据添加的数据为准

  2. 修改 db.users.update({age: 25}, {$set: {name: 'changeName'}}, false, true); 相当于:update users set name = ‘changeName’ where age = 25;

db.users.update({name: 'Lisi'}, {$inc: {age: 50}}, false, true); 相当于:update users set age = age + 50 where name = ‘Lisi’;

db.users.update({name: 'Lisi'}, {$inc: {age: 50}, $set: {name: 'hoho'}}, false, true); 相当于:update users set age = age + 50, name = ‘hoho’ where name = ‘Lisi’;

  1. 删除 db.users.remove({age: 132});

  2. 查询修改删除

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    db.users.findAndModify({
    query: {age: {$gte: 25}},
    sort: {age: -1},
    update: {$set: {name: 'a2'}, $inc: {age: 2}},
    remove: true
    });

    db.runCommand({ findandmodify : "users",
    query: {age: {$gte: 25}},
    sort: {age: -1},
    update: {$set: {name: 'a2'}, $inc: {age: 2}},
    remove: true
    });

update 或 remove 其中一个是必须的参数; 其他参数可选。 |参数|详解|默认值| |—|—|—| |query|查询过滤条件|{}| |sort|如果多个文档符合查询过滤条件,将以该参数指定的排列方式选择出排在首位的对象,该对象将被操作|{}| |remove|若为true,被选中对象将在返回前被删除|N/A| |update|一个 修改器对象|N/A| |new|若为true,将返回修改后的对象而不是原始对象。在删除操作中,该参数被忽略。|false| |fields|参见Retrieving a Subset of Fields (1.5.0+)|All fields| |upsert|创建新对象若查询结果为空。 示例 (1.5.4+)|false|

语句块操作

  1. 简单Hello World print("Hello World!"); 这种写法调用了print函数,和直接写入”Hello World!”的效果是一样的;

  2. 将一个对象转换成json

    1
    2
    tojson(new Object());
    tojson(new Object('a'));
  3. 循环添加数据

    1
    2
    3
    > for (var i = 0; i < 30; i++) {
    ... db.users.save({name: "u_" + i, age: 22 + i, sex: i % 2});
    ... };

这样就循环添加了30条数据,同样也可以省略括号的写法

1
> for (var i = 0; i < 30; i++) db.users.save({name: "u_" + i, age: 22 + i, sex: i % 2});

也是可以的,当你用db.users.find()查询的时候,显示多条数据而无法一页显示的情况下,可以用it查看下一页的信息;

  1. find 游标查询
    1
    2
    3
    4
    >var cursor = db.users.find();
    > while (cursor.hasNext()) {
    printjson(cursor.next());
    }

这样就查询所有的users信息,同样可以这样写

1
2
var cursor = db.users.find();
while (cursor.hasNext()) { printjson(cursor.next); }

同样可以省略{}号

  1. forEach迭代循环

    1
    2
    db.users.find().forEach(printjson);
    forEach中必须传递一个函数来处理每条迭代的数据信息
  2. 将find游标当数组处理

    1
    2
    var cursor = db.users.find();
    cursor[4];

取得下标索引为4的那条数据 既然可以当做数组处理,那么就可以获得它的长度:cursor.length();或者cursor.count(); 那样我们也可以用循环显示数据

1
for (var i = 0, len = c.length(); i < len; i++) printjson(c[i]);
  1. 将find游标转换成数组
    1
    2
    > var arr = db.users.find().toArray();
    > printjson(arr[2]);

用toArray方法将其转换为数组

  1. 定制我们自己的查询结果 只显示age <= 28的并且只显示age这列数据
    1
    2
    db.users.find({age: {$lte: 28}}, {age: 1}).forEach(printjson);
    db.users.find({age: {$lte: 28}}, {age: true}).forEach(printjson);

排除age的列

1
db.users.find({age: {$lte: 28}}, {age: false}).forEach(printjson);
  1. forEach传递函数显示信息
    1
    db.things.find({x:4}).forEach(function(x) {print(tojson(x));});

上面介绍过forEach需要传递一个函数,函数会接受一个参数,就是当前循环的对象,然后在函数体重处理传入的参数

env-centos-gitlab

发表于 2019-05-26 | 分类于 env

一、 安装并配置必要的依赖关系

在CentOS系统上安装所需的依赖:ssh,防火墙,postfix(用于邮件通知) ,wget,以下这些命令也会打开系统防火墙中的HTTP和SSH端口访问。

  1. 安装ssh: sudo yum install -y curl policycoreutils-pythonopenssh-server

  2. 将SSH服务设置成开机自启动,安装命令:sudo systemctl enable sshd

  3. 启动SSH服务,安装命令:sudo systemctl start sshd

  4. 安装防火墙(如果已经安装了防火墙并且已经在运行状态,则可直接进行第6步):yum install firewalld systemd -y

  5. 开启防火墙,安装命令:service firewalld start

  6. 添加http服务到firewalld,pemmanent表示永久生效,若不加–permanent系统下次启动后就会失效。

    1
    2
    3
    4
    5
    6
    #开放ssh、http服务
    sudo firewall-cmd --add-service=ssh --permanent
    sudo firewall-cmd --add-service=http --permanent

    #重载防火墙规则
    sudo firewall-cmd --reload
  7. 接下来,安装Postfix以发送通知邮件,安装命令:sudo yum install postfix

  8. 将postfix服务设置成开机自启动,安装命令:sudo systemctl enable postfix

  9. 启动postfix,安装命令:sudo systemctl start postfix 遇到问题:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    Job for postfix.service failed because the control process exited with error code. See "systemctl status postfix.service" and "journalctl -xe" for details.
    (cmdb) [root@node1 ~]# journalctl -xe
    Jan 21 16:30:01 node1.cn systemd[1]: Starting Session 764 of user root.
    -- Subject: Unit session-764.scope has begun start-up
    -- Defined-By: systemd
    -- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel

    ▽ Unit session-764.scope has begun starting up.
    Jan 21 16:30:01 node1.cn CROND[5943]: (root) CMD (/usr/lib64/sa/sa1 1 1)
    Jan 21 16:30:21 node1.cn polkitd[450]: Registered Authentication Agent for unix-process:5950:36693241 (system bus name :1.1600 [/usr/bin/pkttyagent --notify-fd 5 --fallback], object path /org
    Jan 21 16:30:21 node1.cn systemd[1]: Reloading.
    Jan 21 16:30:21 node1.cn systemd[1]: Configuration file /usr/lib/systemd/system/eni.service is marked world-inaccessible. This has no effect as configuration data is accessible via APIs witho
    Jan 21 16:30:21 node1.cn polkitd[450]: Unregistered Authentication Agent for unix-process:5950:36693241 (system bus name :1.1600, object path /org/freedesktop/PolicyKit1/AuthenticationAgent,
    Jan 21 16:30:28 node1.cn polkitd[450]: Registered Authentication Agent for unix-process:5967:36693923 (system bus name :1.1601 [/usr/bin/pkttyagent --notify-fd 5 --fallback], object path /org
    Jan 21 16:30:28 node1.cn systemd[1]: Starting Postfix Mail Transport Agent...
    -- Subject: Unit postfix.service has begun start-up
    -- Defined-By: systemd
    -- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
    --
    -- Unit postfix.service has begun starting up.
    Jan 21 16:30:28 node1.cn aliasesdb[5973]: /usr/sbin/postconf: fatal: parameter inet_interfaces: no local interface found for ::1
    Jan 21 16:30:29 node1.cn postfix/sendmail[5975]: fatal: parameter inet_interfaces: no local interface found for ::1
    Jan 21 16:30:29 node1.cn aliasesdb[5973]: newaliases: fatal: parameter inet_interfaces: no local interface found for ::1
    Jan 21 16:30:29 node1.cn postfix[5978]: fatal: parameter inet_interfaces: no local interface found for ::1
    Jan 21 16:30:30 node1.cn systemd[1]: postfix.service: control process exited, code=exited status=1
    Jan 21 16:30:30 node1.cn systemd[1]: Failed to start Postfix Mail Transport Agent.
    -- Subject: Unit postfix.service has failed
    -- Defined-By: systemd
    -- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel

解决方法: 修改 /etc/postfix/main.cf的设置

1
2
inet_protocols = ipv4
inet_interfaces = all

重新启动postfix即可

1
systemctl start postfix.service

二、 安装

1、YUM安装gitlab

添加GitLab社区版Package

1
curl https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.rpm.sh | sudo bash

安装GitLab社区版

1
sudo yum install -y gitlab-ce

2、配置GitLab站点Url

GitLab默认的配置文件路径是/etc/gitlab/gitlab.rb

默认的站点Url配置项是: external_url ‘http://gitlab.example.com:8082'

这里我将GitLab站点Url修改为http://git.wodekouwei.com 也可以用IP代替域名,这里根据自己需求来即可

1
2
3
4
5
#修改配置文件
sudo vi /etc/gitlab/gitlab.rb

#配置首页地址(大约在第15行)
external_url 'http://git.wodekouwei.com:8082'

2、配置端口号

修改nginx端口sudo vi /etc/gitlab/gitlab.rb:

1
2
nginx['listen_port'] = 8083
unicorn['port'] = 8092

修改/var/opt/gitlab/gitlab-rails/etc/unicorn.rb

1
listen "127.0.0.1:8092", :tcp_nopush => true

sudo vi /var/opt/gitlab/nginx/conf/gitlab-http.conf:

1
2
server {
listen *:8083;

修改unicorn端口sudo vi /etc/gitlab/gitlab.rb:

1
unicorn['port'] = 8092

保存配置,重启

1
2
3
sudo gitlab-ctl reconfigure
sudo gitlab-ctl restart
sudo gitlab-ctl status

sudo gitlab-ctl tail

如果还是想从80端口访问gitlab,我们可以用监听在80端口的nginx做一个反向代理。

1
service nginx restart

后可以正常访问。

1
2
3
4
5
6
7
8
9
server {
listen 80;
server_name gitlab.123.123.cn;

location / {
#rewrite ^(.*) http://127.0.0.1:8082;
proxy_pass http://127.0.0.1:8082;
}
}

3、配置smtp邮件发送

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ sudo vi /etc/gitlab/gitlab.rb                            
# Change the external_url to the address your users will type in their browser
external_url 'http://xxhost.com'

#Sending application email via SMTP
gitlab_rails['smtp_enable'] = true
gitlab_rails['smtp_address'] = "smtp.163.com"
gitlab_rails['smtp_port'] = 25
gitlab_rails['smtp_user_name'] = "xxuser@163.com"
gitlab_rails['smtp_password'] = "xxpassword"
gitlab_rails['smtp_domain'] = "163.com"
gitlab_rails['smtp_authentication'] = :login
gitlab_rails['smtp_enable_starttls_auto'] = true

##修改gitlab配置的发信人
gitlab_rails['gitlab_email_from'] = "xxuser@163.com"
user["git_user_email"] = "xxuser@163.com"

4、启动并访问GitLab

启动GitLab

1
2
3
4
5
6
7
#重新配置并启动
sudo gitlab-ctl reconfigure

#完成后将会看到如下输出
Running handlers complete
Chef Client finished, 432/613 resources updated in 03 minutes 43 seconds
gitlab Reconfigured!

访问GitLab 将设置的域名DNS解析到服务器IP,或者修改本地host将域名指向服务器IP。 访问:http://git.wodekouwei.com:8082

三、GitLab常用配置

1、禁用创建组权限

GitLab默认所有的注册用户都可以创建组。但对于团队来说,通常只会给Leader相关权限。 虽然可以在用户管理界面取消权限,但毕竟不方便。我们可以通过配置GitLab默认禁用创建组权限。

1
2
3
4
5
6
7
8
9
#修改配置文件
sudo vi /etc/gitlab/gitlab.rb

#开启gitlab_rails['gitlab_default_can_create_group'] 选项,并将值设置为false
### GitLab user privileges
gitlab_rails['gitlab_default_can_create_group'] = false

#保存后,重新配置并启动GitLab
sudo gitlab-ctl reconfigure

2、gitlab-ctl常用命令介绍

命令 说明
check-config 检查在gitlab中是否有任何配置。在指定版本中删除的rb
deploy-page 安装部署页面
diff-config 将用户配置与包可用配置进行比较
remove-accounts 删除所有用户和组
upgrade 升级
service-list 查看所有服务
once 如果GitLab服务停止了就启动服务,如果已启动就不做任何操作
restart 重启GitLab服务
start 如果GitLab服务停止了就启动服务,如果已启动就重启服务
stop 停止GitLab服务
status 查看GitLab服务状态
reconfigure reconfigure重新配置GitLab并启动

tips-res1

发表于 2019-05-13

关于我

  • 区长
  • 区长的独立博客
  • CSDN博客-区长
  • github博客
  • 新浪微博-_区长
  • 知乎-区长
  • 邮箱-li330324@gmail.com

扔物线(凯哥)的 HenCoder

  • 给 Android 开发者的 RxJava 详解
  • hencoder
  • HenCoder:给高级 Android 工程师的进阶手册
  • Android 开发进阶: 自定义 View 1-1 绘制基础
  • Android 开发进阶: 自定义 View 1-2 Paint 详解
  • Android 开发进阶: 自定义 View 1-3 文字的绘制
  • Android 开发进阶: 自定义 View 1-4 Canvas 对绘制的辅助

Docker

  • awesome-docker

机器学习

  • 当 Android 开发者遇见 TensorFlow
  • 莫烦Python
  • TensorFlow练习
  • Tencent/ncnn

输入法

  • Creating an Input Method
  • Image Keyboard Support
  • 谷歌拼音输入法Android Studio工程
  • 谷歌示例代码-全键盘输入法例子
  • android-keyboard-keys-background
  • how-to-change-key-background-of-any-key-in-android-soft-keyboard
  • setting-keyboard-key-background-image/
  • how-to-change-background-color-of-key-for-android-soft-keyboard
  • how-to-change-background-color-or-theme-of-keys-dynamically-in-custom-keyboard-a
  • Keyboard.Key
  • how-to-set-different-background-of-keys-for-android-custom-keyboard
  • building-a-custom-android-keyboard
  • android-emoji-keyboard
  • creating-a-softkeyboard-with-multiple-alternate-characters-per-key
  • 禁用预览

Emoji

  • wiki Emoji
  • emoji-cheat-sheet
  • emoji
  • full-emoji-list

网络栈

  • Chromium网络栈 WolfcsTech
  • chromium-net-for-android
  • CurlForAndroid
  • chromium src
  • libuv中文教程

交叉编译

  • cmake 交叉编译
  • Android Gradle Plugin 源码解析之 externalNativeBuild
  • NDK 交叉编译常用变量
  • Chromium 网络栈的编译与使用
  • CURL NDK 交叉编译
  • Android NDK 内存泄露检测
  • libuv NDK 交叉编译
  • openssl NDK 交叉编译
  • libnghttp2 NDK 交叉编译
  • Android Studio Library 模块中 Native 代码进行 debug 的一些坑
  • Android 在 NDK 层使用 OpenSSL 进行 RSA 加密

Sping Boot

  • Spring Boot文档
  • spring-boot-samples
  • Spring Boot Examples

微信小程序

  • awesome-wechat-weapp
  • 文档
  • ide破解

HTTP2.0

  • Https&Http2.0&HttpDNS 的那些事
  • 测试是否支持http2.0,需翻墙
  • httpvshttps
  • chrome 插件HTTP/2 and SPDY indicator
  • HTTP/2 资料汇总
  • HTTP 2.0的那些事
  • http2-spec
  • 从启用 HTTP/2 导致网站无法访问说起
  • Header Compression for HTTP/2
  • Hypertext Transfer Protocol Version 2

Android 性能优化

  • Android性能优化视频,文档以及工具
  • 胡凯-性能优化
  • Android最佳性能实践(1):合理管理内存
  • Android最佳性能实践(2):分析内存的使用情况
  • Android最佳性能实践(3):高性能编码优化
  • Android最佳性能实践(4):布局优化技巧
  • blockcanary-轻松找出Android App界面卡顿元凶
  • Android Splash页秒开 Activity白屏 Activity黑屏

Android Hybrid&JSBridge技术

  • 浅谈Hybrid技术的设计与实现
  • 谈谈App混合开发
  • 在WebView中如何让JS与Java安全地互相调用
  • WebView中接口隐患与手机挂马利用
  • Android JSBridge的原理与实现

React Native 与 Weex 专题

  • weex
  • 深入源码探索 ReactNative 通信机制
  • React Native首屏白屏优化
  • React Native专题系列文章更新ing(涉及基础,组件,进阶以及开源项目)
  • React-native-Android-热更新
  • React-Native学习指南
  • Facebook的react-native
  • React Native: 配置和起步
  • React Native: Android 的打包
  • React Native For Android初体验
  • JianDan-React-Native
  • React Native For Android 架构初探
  • react-native-viewpager
  • React Native for Android 实践 – 实现知乎日报客户端
  • 【React Native for Android】jsBridge实现原理
  • 其实没那么复杂!探究react-native通信机制

Android插件化开发与动态加载

  • 360的RePlugin
  • 360的DroidPlugin
  • 滴滴的VirtualAPK
  • 手淘的Atlas
  • Small
  • 携程DynamicAPK
  • 掌阅-最简单易懂的Android插件补丁框架
  • OpenAtlas,已改名为ACDD,可以在手机淘宝中见到踪影
  • dynamic-load-apk
  • 美团分包
  • 微信/手Q加载方案
  • Android博客周刊专题之《插件化开发》
  • Fast load dex in memory
  • Android Plugin Framework 插件开发框架及示例程序,原理介绍等
  • 获取主dex
  • 应用双开VirtualApp
  • Android Dex分包之旅
  • ANROID动态加载技术 系列索引

Android 热更新

  • dexposed
  • AndFix
  • QQ空间热修复
  • QQ空间热修复实现方案
  • Nuwa 女娲
  • Android HotPatch从入门到“放弃”
  • Android Patch 方案与持续交付
  • Android N混合编译与对热补丁影响解析
  • 微信Android热补丁实践演进之路
  • Android热更新之so库的热更新
  • Android aapt实现资源分区(补充携程aapt源码)
  • Android 热修复使用Gradle Plugin1.5改造Nuwa插件
  • Android 热修复Nuwa的原理及Gradle插件源码解析
  • Tinker_imitator
  • ZeusPlugin插件框架热修复gradle插件源码
  • RocooFix
  • Android Classloader热修复技术之百家齐放
  • 从Instant-Run出发,谈谈Android上的热修复
  • Android热修复与增量升级,基于微信Tinker原理
  • 美团Android热更新方案Robust
  • 腾讯Tinker
  • 美团Robust

Android 加固与反编译

  • android反编译工具的合集
  • Apktool
  • dex2jar
  • DecompileApk
  • Android APK加固技术方案调研
  • Android apk包res 资源混淆工具
  • 微信资源混淆
  • 美团Android资源混淆保护实践
  • 美团Android资源混淆实现方案
  • Apk脱壳圣战之—如何脱掉“360加固”的壳
  • Android脱壳圣战之—如何脱掉”爱加密”家的保护壳
  • 一键生成项目混淆代码插件
  • Android逆向之旅—SO(ELF)文件格式详解
  • Android逆向之旅—解析编译之后的AndroidManifest文件格式
  • Android逆向之旅—解析编译之后的Resource.arsc文件格式
  • Android逆向之旅—解析编译之后的Dex文件格式

Android Studio专题

  • 查看依赖关系的插件
  • IntelliJ IDEA 简体中文专题教程
  • Android Studio 你不知道的调试技巧
  • Android打包的那些事
  • idea-live-templates 模板
  • 方法数统计插件,可用于统计是否达到65536个方法
  • Android-Drawable-Importer插件
  • GsonFormat Json对应的Bean快速生成插件
  • android-selector-chapek Selector生成插件
  • 快速生成butterknife注解插件
  • android-material-design-icon-generator图标插件
  • Retrolambda 在java 6 7中使用 lambda表达式插件
  • Gradle依赖自动补齐插件
  • idea-markdown编辑器插件
  • 从布局中生成View的声明插件
  • codota代码片段搜索,支持Chrome和Android Studio
  • 布局文件分组插件
  • DPI计算插件
  • gradle-publish 发布库插件
  • 发布lib到jcenter
  • vysor 这个是Chrome的插件,电脑操作手机
  • android-studio-tips-tricks-moving-around/
  • http://www.developerphil.com/android-studio-tips-of-the-day-roundup-1/
  • http://www.developerphil.com/android-studio-tips-of-the-day-roundup-2/
  • http://www.developerphil.com/android-studio-tips-of-the-day-roundup-3/
  • http://www.developerphil.com/android-studio-tips-of-the-day-roundup-4/
  • http://www.developerphil.com/android-studio-tips-of-the-day-roundup-5/
  • http://www.developerphil.com/android-studio-tips-of-the-day-roundup-6/
  • Android Studio插件开发
  • Android SDK镜像服务器搭建
  • Android Studio 插件整理 48 个

RxJava&&RxAndroid&&agera学习资源

  • RxJava Github地址
  • RxAndroid Github地址
  • RxJava中文文档翻译
  • Awesome-RxJava
  • 在正确的线程上观察
  • 给 Android 开发者的 RxJava 详解
  • 谜之RxJava (一) —— 最基本的观察者模式
  • 谜之RxJava (二) —— Magic Lift
  • 迷之RxJava (三)—— 线程切换
  • 迷之RxJava (三)update —— 线程切换(二)
  • 迷之RxJava (三)update 2 —— subscribeOn 和 observeOn 的区别
  • 迷之RxJava(四)—— Retrofit和RxJava的基情
  • android-agera
  • agera
  • RxJava 与 Retrofit 结合的最佳实践

Gradle

  • 又掌握了一项新技能 - 断点调试 Gradle 插件
  • Android Gradle Plugin 源码解析之 externalNativeBuild
  • Android Gradle Plugin 源码阅读与编译
  • Gradle 函数复用的一点实践
  • Gradle for Android
  • 谷歌Gradle官方文档
  • Android Gradle 构建系统·初探
  • Gradle系列之从init.gradle说起
  • 深入理解Android之Gradle

Android 开发中值得看的优秀内容和工具

  • 多渠道 v2签名 walle
  • androidcat
  • ADB 用法大全
  • 使用 CheckStyle 检查代码
  • 图解 Retrofit - ServiceMethod
  • OkHttp3源码分析-综述
  • Android进程保活招式大全
  • 08/07 北京 GDG Android Meetup 活动回顾,讲义,照片
  • Java源码生成(Square JavaWriter)
  • 安卓架构文章合集(a collection of android Architecture)
  • OS X 下使用 Hexo 和 Coding Pages 搭建静态博客
  • Android系统源码查看,支持在线跟踪引用
  • 贾吉鑫
  • TraceView性能优化工具使用
  • network-connection-class
  • 阿里巴巴技术文章
  • Android打包的那些事
  • InfoQAndroid周报
  • 开发技术前线
  • 美团Android DEX自动拆包及动态加载简介
  • Android官方培训课程中文版
  • 一个定期翻译国外Android优质的技术、开源库、软件架构设计、测试等文章的开源项目
  • Android Guides
  • Android 开源项目源码解析
  • Android 图像处理教学
  • Android 开源项目分类汇总
  • 开发过程中遇到的坑
  • Android 开源交流
  • Android 著名开源库的简版实现
  • Android 问题交流讨论,大部分是面试题
  • android 设计模式
  • Android 全国职位列表
  • fuck-2014-flirt-2015
  • AndroidDevTools开发相关资料下载
  • android-best-practices最佳实践
  • java设计模式
  • Android最佳实践示例
  • Android 中 Java 与JavaScript 交互最详尽的总结
  • 如何为drawable着色
  • Drawable 着色的后向兼容方案
  • Awesome-MaterialDesign
  • Android 面试题InterviewQuestion
  • awesome-android
  • Retrofit相关文章
  • Lite Android
  • Bugly Blog
  • 掘金

安卓网络层(包含图片)

  • okhttp
  • retrofit
  • picasso
  • Volley
  • fresco
  • Android-Universal-Image-Loader
  • robospice
  • android-async-http
  • Fast-Android-Networking

安卓orm框架,用得比较多的就GreenDao,Ormlite

  • greenDAO
  • ORMLite
  • ActiveAndroid
  • SugarORM
  • Siminov
  • androrm
  • cupboard
  • realm

安卓Json解析

  • Gson,用法简单,速度慢
  • fastjson,号称最快
  • jackson

Android 单元测试

  • 使用Mockito和Roboletric进行Android单元测试
  • Robolectric

Android 开源软件

  • 一个第三方开源微博
  • android相关的干货(文摘,名博,github等等)
  • 第三方github客户端
  • 开源中国的系列软件
  • 体重档案
  • Simplifyreader
  • 西源坊

Android 开发辅助工具

  • Charles 从入门到精通
  • Google Play APK下载器
  • slideshare
  • codota代码片段搜索,支持Chrome和Android Studio
  • vysor 这个是Chrome的插件,电脑操作手机
  • Browser extension to display GitHub code in tree format
  • google hosts翻墙,有vpn的忽略
  • 开源中国在线工具
  • 百度ApiStore
  • Vim插件
  • 强迫症的 Mac 设置指南
  • Linux-Tutorial
  • Markdown-Syntax-CN
  • insight chrome 代码查看插件

Android 推送(含IM)

  • 环信,支持即时音视频
  • 腾讯云通讯,支持即时音视频
  • 极光推送和IM
  • 个推
  • 小米推送,在MIUI上属于系统服务框架,共享系统级长连接
  • 百度云推送,部分机型收不到推送,如小米,Bug是否修复未知
  • 腾讯信鸽推送
  • 友盟推送
  • leancloud
  • bmob云推送,含IM
  • 蘑菇街TeamTalk
  • Openfire+Smack开源Xmpp解决方案

Android后端等服务

  • parse,缺点是服务器在国外,速度慢
  • leancloud,国内的,仿parse
  • Bmob后端云
  • 七牛云存储
  • apicloud

Android 应用内测平台

  • 蒲公英,内测应用
  • Fir.im,内测应用

Android社会化分享,短信验证,意见反馈,支付等相关

  • 友盟,社会化分析,意见反馈
  • Sharesdk,社会化分析
  • Ping++,支付
  • bmob支付,Bmob为广大开发人员提供的统一、正规的收费手段,让没有企业认证的个人开发者,也能通过支付宝和微信向用户收费
  • 容联云通讯

安卓开发值得关注的库

  • 定时任务&计划任务-印象笔记android-job
  • AndroidHttpCapture 手机上抓包
  • 方法自动生成
  • Android上的一个蛛网评分控件
  • ReLinker 安全加载so库的方式
  • SugarTask
  • sync adapter
  • Android Weak Handler防止内存泄露
  • Android Priority Job Queue 异步任务调度
  • android-priority-jobqueue
  • Android对话框
  • 扩展的RecyclerView,拥有添加头、底等多种操作
  • MaterialDesign相关库
  • 右滑返回SwipeBackLayout
  • 百分比布局
  • EventBus
  • ObservableScrollView
  • 工具库less code, more efficient for android
  • 通用适配器
  • android-log
  • NineOldAndroids
  • BadgeView
  • CircleImageView
  • CustomShapeImageView
  • SweetAlert for Android, a beautiful and clever alert dialog
  • android-pulltorefresh
  • SlidingMenu
  • ViewPagerIndicator
  • 一个动画集合库
  • FontAwesome for Android
  • RecyclerView made simple
  • jsoup库(java)
  • android-wheel
  • xUtils
  • android-common
  • zxing
  • Android开发常用整理
  • 左滑粒子删除效果
  • JSON Server:零编码快速“伪造” REST API
  • owncloud
  • Android_Data (Android 学习资料收集)

安卓资源相关

  • 安卓每个版本的Drawable图标
  • FontAwesome字体图标安卓字符串
  • 色系
  • 颜色库
  • IconFinder图标资源
  • 阿里巴巴矢量图
  • icomoon
  • AndroidAssetStudio
  • Android Holo颜色生成器
  • Android Action Bar Style Generator
  • 在线.9.png图片生成器
  • 安卓button在线制作工具
  • Theme.xml属性
  • 移动APP云计算平台Parse

git

  • Git教程
  • 用 Git Hooks 进行自动部署
  • Git工作流指南:Forking工作流

Android NoSql

  • realm-java
  • couchbase-lite-android
  • SimpleNoSQL
  • SnappyDB

设计网站,可以寻找一些酷炫的设计稿

  • https://dribbble.com/
  • http://pttrns.com/
  • http://capptivate.co/

国外个人博客

  • Jakewharton
  • Romain Guy
  • Cyril Mottier
  • Mark Allison
  • Daniel Lew
  • Ravi Tamada
  • Chris Nash
  • juhani@fatrobot.io
  • Wolfram Rittmeyer
  • Rich Hyndman

国外的一些优秀网站

  • androidweekly.net
  • Android Developers Blog
  • vogella
  • tutorialspoint
  • tutsplus
  • oderzheaven
  • thenewcircle
  • coreservlets
  • Droid-Blog
  • coursera.org
  • commonsware.com
  • http://android.amberfog.com/
  • anddev

Ibeacon与蓝牙4.0相关

  • 一个ibeacon交互库
  • AprilBeacon-Android-sdk
  • Estimote SDK
  • 蓝牙4.0相关

WEB与前端相关

  • yii
  • yiibooster
  • wechat-php-sdk
  • php_sae_storage
  • Bootstrap
  • Font-Awesome字体图标
  • sublime浏览器前缀插件
  • 一个手势库
  • bootstrap-filestyle
  • 基于Codeigniter的CMS系统

env-unix

发表于 2019-05-06

POSIX表示可移植操作系统接口(Portable Operating System Interface of UNIX,缩写为 POSIX ),POSIX标准定义了操作系统应该为应用程序提供的接口标准,是IEEE为要在各种UNIX操作系统上运行的软件而定义的一系列API标准的总称,其正式称呼为IEEE 1003,而国际标准名称为ISO/IEC 9945。 POSIX标准意在期望获得源代码级别的软件可移植性。换句话说,为一个POSIX兼容的操作系统编写的程序,应该可以在任何其它的POSIX操作系统(即使是来自另一个厂商)上编译执行。 POSIX 并不局限于 UNIX。许多其它的操作系统,例如 DEC OpenVMS 支持 POSIX 标准,尤其是 IEEE Std. 1003.1-1990(1995 年修订)或 POSIX.1,POSIX.1 提供了源代码级别的 C 语言应用编程接口(API)给操作系统的服务程序,例如读写文件。POSIX.1 已经被国际标准化组织(International Standards Organization,ISO)所接受,被命名为 ISO/IEC 9945-1:1990 标准。

UNIX和类Unix操作系统 UNIX System V家族

  • A/UX
  • AIX
  • HP-UX
  • IRIX
  • LynxOS
  • SCO OpenServer
  • Tru64
  • Xenix
  • Solaris
  • OS/2
    BSD UNIX-386BSD家族
  • BSD/OS
  • FreeBSD
  • NetBSD
  • NEXTSTEP
  • Mac OS X
  • iOS
  • OpenBSD
  • SUN OS
  • OpenSolaris
    UNIX-Like
  • GNU
  • Linux
  • Android
  • Debian
  • Ubuntu
  • Red Hat
  • Linux Mint
  • Minix
  • QNX
  • GNU/Linux
  • GNU/Hurd
  • Debian GNU/Hurd
  • GNU/kFreeBSD
  • StartOS
    其他
  • DOS
  • MS-DOS
  • Windows
  • React OS

Linux sed命令

发表于 2019-05-03 | 分类于 linux管理

Linux sed命令是利用script来处理文本文件。 sed可依照script的指令,来处理、编辑文本文件。 Sed主要用来自动编辑一个或多个文件;简化对文件的反复操作;编写转换程序等。

语法

1
sed [-hnV][-e<script>][-f<script文件>][文本文件]

参数说明:

  • -e<script>或--expression=<script> 以选项中指定的script来处理输入的文本文件。
  • -f<script文件>或--file=<script文件> 以选项中指定的script文件来处理输入的文本文件。
  • -h或–help 显示帮助。
  • -n或–quiet或–silent 仅显示script处理后的结果。
  • -V或–version 显示版本信息。

动作说明:

  • a :新增, a 的后面可以接字串,而这些字串会在新的一行出现(目前的下一行)~
  • c :取代, c 的后面可以接字串,这些字串可以取代 n1,n2 之间的行!
  • d :删除,因为是删除啊,所以 d 后面通常不接任何咚咚;
  • i :插入, i 的后面可以接字串,而这些字串会在新的一行出现(目前的上一行);
  • p :打印,亦即将某个选择的数据印出。通常 p 会与参数 sed -n 一起运行~
  • s :取代,可以直接进行取代的工作哩!通常这个 s 的动作可以搭配正规表示法!例如 1,20s/old/new/g 就是啦!

    实例

    在testfile文件的第四行后添加一行,并将结果输出到标准输出,在命令行提示符下输入如下命令:
    1
    sed -e 4a\newLine testfile

首先查看testfile中的内容如下:

1
2
3
4
5
$ cat testfile #查看testfile 中的内容  
HELLO LINUX!
Linux is a free unix-type opterating system.
This is a linux testfile!
Linux test

使用sed命令后,输出结果如下:

1
2
3
4
5
6
$ sed -e 4a\newline testfile #使用sed 在第四行后添加新字符串  
HELLO LINUX! #testfile文件原有的内容
Linux is a free unix-type opterating system.
This is a linux testfile!
Linux test
newline

以行为单位的新增/删除

将 /etc/passwd 的内容列出并且列印行号,同时,请将第 2~5 行删除!

1
2
3
4
5
[root@www ~]# nl /etc/passwd | sed '2,5d'
1 root:x:0:0:root:/root:/bin/bash
6 sync:x:5:0:sync:/sbin:/bin/sync
7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
.....(后面省略).....

sed 的动作为 ‘2,5d’ ,那个 d 就是删除!因为 2-5 行给他删除了,所以显示的数据就没有 2-5 行罗~ 另外,注意一下,原本应该是要下达 sed -e 才对,没有 -e 也行啦!同时也要注意的是, sed 后面接的动作,请务必以 ‘’ 两个单引号括住喔!

只要删除第 2 行

1
nl /etc/passwd | sed '2d'

要删除第 3 到最后一行

1
nl /etc/passwd | sed '3,$d'

在第二行后(亦即是加在第三行)加上『drink tea?』字样!

1
2
3
4
5
6
[root@www ~]# nl /etc/passwd | sed '2a drink tea'
1 root:x:0:0:root:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
drink tea
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
.....(后面省略).....

那如果是要在第二行前

1
nl /etc/passwd | sed '2i drink tea'

如果是要增加两行以上,在第二行后面加入两行字,例如 Drink tea or ….. 与 drink beer?

1
2
3
4
5
6
7
8
[root@www ~]# nl /etc/passwd | sed '2a Drink tea or ......\
> drink beer ?'
1 root:x:0:0:root:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
Drink tea or ......
drink beer ?
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
.....(后面省略).....

每一行之间都必须要以反斜杠『 \ 』来进行新行的添加喔!所以,上面的例子中,我们可以发现在第一行的最后面就有 \ 存在。

以行为单位的替换与显示

将第2-5行的内容取代成为『No 2-5 number』呢?

1
2
3
4
5
[root@www ~]# nl /etc/passwd | sed '2,5c No 2-5 number'
1 root:x:0:0:root:/root:/bin/bash
No 2-5 number
6 sync:x:5:0:sync:/sbin:/bin/sync
.....(后面省略).....

透过这个方法我们就能够将数据整行取代了! 仅列出 /etc/passwd 文件内的第 5-7 行

1
2
3
4
[root@www ~]# nl /etc/passwd | sed -n '5,7p'
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
6 sync:x:5:0:sync:/sbin:/bin/sync
7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown

可以透过这个 sed 的以行为单位的显示功能, 就能够将某一个文件内的某些行号选择出来显示。

数据的搜寻并显示

搜索 /etc/passwd有root关键字的行

1
2
3
4
5
6
7
8
nl /etc/passwd | sed '/root/p'
1 root:x:0:0:root:/root:/bin/bash
1 root:x:0:0:root:/root:/bin/bash
2 daemon:x:1:1:daemon:/usr/sbin:/bin/sh
3 bin:x:2:2:bin:/bin:/bin/sh
4 sys:x:3:3:sys:/dev:/bin/sh
5 sync:x:4:65534:sync:/bin:/bin/sync
....下面忽略

如果root找到,除了输出所有行,还会输出匹配行。

使用-n的时候将只打印包含模板的行。

1
2
nl /etc/passwd | sed -n '/root/p'
1 root:x:0:0:root:/root:/bin/bash

数据的搜寻并删除

删除/etc/passwd所有包含root的行,其他行输出

1
2
3
4
5
nl /etc/passwd | sed  '/root/d'
2 daemon:x:1:1:daemon:/usr/sbin:/bin/sh
3 bin:x:2:2:bin:/bin:/bin/sh
....下面忽略
#第一行的匹配root已经删除了

数据的搜寻并执行命令

搜索/etc/passwd,找到root对应的行,执行后面花括号中的一组命令,每个命令之间用分号分隔,这里把bash替换为blueshell,再输出这行:

1
2
nl /etc/passwd | sed -n '/root/{s/bash/blueshell/;p;q}'    
1 root:x:0:0:root:/root:/bin/blueshell

最后的q是退出。

数据的搜寻并替换

除了整行的处理模式之外, sed 还可以用行为单位进行部分数据的搜寻并取代。基本上 sed 的搜寻与替代的与 vi 相当的类似!他有点像这样:

1
sed 's/要被取代的字串/新的字串/g'

先观察原始信息,利用 /sbin/ifconfig 查询 IP

1
2
3
4
5
6
[root@www ~]# /sbin/ifconfig eth0
eth0 Link encap:Ethernet HWaddr 00:90:CC:A6:34:84
inet addr:192.168.1.100 Bcast:192.168.1.255 Mask:255.255.255.0
inet6 addr: fe80::290:ccff:fea6:3484/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
.....(以下省略).....

本机的ip是192.168.1.100。将 IP 前面的部分予以删除

1
2
[root@www ~]# /sbin/ifconfig eth0 | grep 'inet addr' | sed 's/^.*addr://g'
192.168.1.100 Bcast:192.168.1.255 Mask:255.255.255.0

接下来则是删除后续的部分,亦即: 192.168.1.100 Bcast:192.168.1.255 Mask:255.255.255.0 将 IP 后面的部分予以删除

1
2
[root@www ~]# /sbin/ifconfig eth0 | grep 'inet addr' | sed 's/^.*addr://g' | sed 's/Bcast.*$//g'
192.168.1.100

多点编辑

一条sed命令,删除/etc/passwd第三行到末尾的数据,并把bash替换为blueshell

1
2
3
nl /etc/passwd | sed -e '3,$d' -e 's/bash/blueshell/'
1 root:x:0:0:root:/root:/bin/blueshell
2 daemon:x:1:1:daemon:/usr/sbin:/bin/sh

-e表示多点编辑,第一个编辑命令删除/etc/passwd第三行到末尾的数据,第二条命令搜索bash替换为blueshell。

直接修改文件内容(危险动作)

sed 可以直接修改文件的内容,不必使用管道命令或数据流重导向! 不过,由於这个动作会直接修改到原始的文件,所以请你千万不要随便拿系统配置来测试! 我们还是使用文件 regular_express.txt 文件来测试看看吧!

regular_express.txt 文件内容如下:

1
2
3
4
5
6
7
[root@www ~]# cat regular_express.txt 
runoob.
google.
taobao.
facebook.
zhihu-
weibo-

利用 sed 将 regular_express.txt 内每一行结尾若为 . 则换成 !

1
2
3
4
5
6
7
8
[root@www ~]# sed -i 's/\.$/\!/g' regular_express.txt
[root@www ~]# cat regular_express.txt
runoob!
google!
taobao!
facebook!
zhihu-
weibo-

:q:q 利用 sed 直接在 regular_express.txt 最后一行加入 # This is a test:

1
2
3
4
5
6
7
8
9
[root@www ~]# sed -i '$a # This is a test' regular_express.txt
[root@www ~]# cat regular_express.txt
runoob!
google!
taobao!
facebook!
zhihu-
weibo-
# This is a test

由于 $ 代表的是最后一行,而 a 的动作是新增,因此该文件最后新增 # This is a test! sed 的 -i 选项可以直接修改文件内容,这功能非常有帮助!举例来说,如果你有一个 100 万行的文件,你要在第 100 行加某些文字,此时使用 vim 可能会疯掉!因为文件太大了!那怎办?就利用 sed 啊!透过 sed 直接修改/取代的功能,你甚至不需要使用 vim 去修订!

mac中sed -i 需要带一个字符串,用来备份源文件,这个字符串加在源文件名后面组成备份文件名。 如果这个字符串长度为0,就是说是个空串,那么不备份。

1
sed -i "bs" 's/Atl/Dog/g' example.txt

这样会生成一个example.txtbs的备份文件。 如果不备份,直接给个空

1
sed -i "" 's/Atl/Dog/g' example.txt

使用正则表达式提取子串

现在有如下一串字符串:”asdfkjasldjkf”shiner”df 需求:需要提取出shiner子字符串。 命令如下:

1
2
[root@localhost /]$  echo "asdfkjasldjkf\"shiner\"df" | sed 's/\(.*\)"\(.*\)"\(.*\)/\2/g'
shiner

命令解释

  • s: 表示替换命令
  • \(.*\)" : 表示第一个引号前的内容
  • "\(.*\)":表示两引号之间的内容
  • )"\(.*\):表示引号后的内容
  • \2: 表示第二对括号里面的内容 括号里的表达式匹配的内容,可以用\1,\2等进行引用,第n个括号对内的内容,就用\n引用。

注意事项

  • sed正则中的空格就用空格表示,而不是\s,补充:可以用\s
  • sed正则中的数字只能用[0-9],而不能用\d表示
  • sed正则中的1或者多个,只能用+,而不能用+,区别就是加了转义字符
  • sed正则中的()前要加转义字符,变成\(\)
  • number=xxx这条赋值语句的等号两边不能有空格,如果赋值语句有空格,linux系统会认为number是一个命令

mmap分析

发表于 2019-04-30 | 分类于 tips

mmap基础概念

mmap是一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。实现这样的映射关系后,进程就可以采用指针的方式读写操作这一段内存,而系统会自动回写脏页面到对应的文件磁盘上,即完成了对文件的操作而不必再调用read,write等系统调用函数。相反,内核空间对这段区域的修改也直接反映用户空间,从而可以实现不同进程间的文件共享。如下图所示

tips-android-mmap-201943018165

由上图可以看出,进程的虚拟地址空间,由多个虚拟内存区域构成。虚拟内存区域是进程的虚拟地址空间中的一个同质区间,即具有同样特性的连续地址范围。上图中所示的text数据段(代码段)、初始数据段、BSS数据段、堆、栈和内存映射,都是一个独立的虚拟内存区域。而为内存映射服务的地址空间处在堆栈之间的空余部分。

linux内核使用vm_area_struct结构来表示一个独立的虚拟内存区域,由于每个不同质的虚拟内存区域功能和内部机制都不同,因此一个进程使用多个vm_area_struct结构来分别表示不同类型的虚拟内存区域。各个vm_area_struct结构使用链表或者树形结构链接,方便进程快速访问,如下图所示:

tips-android-mmap-2019430181614

vm_area_struct结构中包含区域起始和终止地址以及其他相关信息,同时也包含一个vm_ops指针,其内部可引出所有针对这个区域可以使用的系统调用函数。这样,进程对某一虚拟内存区域的任何操作需要用要的信息,都可以从vm_area_struct中获得。mmap函数就是要创建一个新的vm_area_struct结构,并将其与文件的物理磁盘地址相连。具体步骤请看下一节。

mmap内存映射原理

mmap内存映射的实现过程,总的来说可以分为三个阶段:

一.进程启动映射过程,并在虚拟地址空间中为映射创建虚拟映射区域

  1. 进程在用户空间调用库函数mmap,原型:void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
  2. 在当前进程的虚拟地址空间中,寻找一段空闲的满足要求的连续的虚拟地址
  3. 为此虚拟区分配一个vm_area_struct结构,接着对这个结构的各个域进行了初始化
  4. 将新建的虚拟区结构(vm_area_struct)插入进程的虚拟地址区域链表或树中

    二.调用内核空间的系统调用函数mmap(不同于用户空间函数),实现文件物理地址和进程虚拟地址的一一映射关系

  5. 为映射分配了新的虚拟地址区域后,通过待映射的文件指针,在文件描述符表中找到对应的文件描述符,通过文件描述符,链接到内核“已打开文件集”中该文件的文件结构体(struct file),每个文件结构体维护着和这个已打开文件相关各项信息。
  6. 通过该文件的文件结构体,链接到file_operations模块,调用内核函数mmap,其原型为:int mmap(struct file *filp, struct vm_area_struct *vma),不同于用户空间库函数。
  7. 内核mmap函数通过虚拟文件系统inode模块定位到文件磁盘物理地址。
  8. 通过remap_pfn_range函数建立页表,即实现了文件地址和虚拟地址区域的映射关系。此时,这片虚拟地址并没有任何数据关联到主存中。

三.进程发起对这片映射空间的访问,引发缺页异常,实现文件内容到物理内存(主存)的拷贝

注:前两个阶段仅在于创建虚拟区间并完成地址映射,但是并没有将任何文件数据的拷贝至主存。真正的文件读取是当进程发起读或写操作时。

  1. 进程的读或写操作访问虚拟地址空间这一段映射地址,通过查询页表,发现这一段地址并不在物理页面上。因为目前只建立了地址映射,真正的硬盘数据还没有拷贝到内存中,因此引发缺页异常。
  2. 缺页异常进行一系列判断,确定无非法操作后,内核发起请求调页过程。
  3. 调页过程先在交换缓存空间(swap cache)中寻找需要访问的内存页,如果没有则调用nopage函数把所缺的页从磁盘装入到主存中。
  4. 之后进程即可对这片主存进行读或者写的操作,如果写操作改变了其内容,一定时间后系统会自动回写脏页面到对应磁盘地址,也即完成了写入到文件的过程。

注:修改过的脏页面并不会立即更新回文件中,而是有一段时间的延迟,可以调用msync()来强制同步, 这样所写的内容就能立即保存到文件里了。

mmap和常规文件操作的区别

对linux文件系统不了解的朋友,请参阅我之前写的博文《从内核文件系统看文件读写过程》,我们首先简单的回顾一下常规文件系统操作(调用read/fread等类函数)中,函数的调用过程:

  1. 进程发起读文件请求。
  2. 内核通过查找进程文件符表,定位到内核已打开文件集上的文件信息,从而找到此文件的inode。
  3. inode在address_space上查找要请求的文件页是否已经缓存在页缓存中。如果存在,则直接返回这片文件页的内容。
  4. 如果不存在,则通过inode定位到文件磁盘地址,将数据从磁盘复制到页缓存。之后再次发起读页面过程,进而将页缓存中的数据发给用户进程。

总结来说,常规文件操作为了提高读写效率和保护磁盘,使用了页缓存机制。这样造成读文件时需要先将文件页从磁盘拷贝到页缓存中,由于页缓存处在内核空间,不能被用户进程直接寻址,所以还需要将页缓存中数据页再次拷贝到内存对应的用户空间中。这样,通过了两次数据拷贝过程,才能完成进程对文件内容的获取任务。写操作也是一样,待写入的buffer在内核空间不能直接访问,必须要先拷贝至内核空间对应的主存,再写回磁盘中(延迟写回),也是需要两次数据拷贝。

而使用mmap操作文件中,创建新的虚拟内存区域和建立文件磁盘地址和虚拟内存区域映射这两步,没有任何文件拷贝操作。而之后访问数据时发现内存中并无数据而发起的缺页异常过程,可以通过已经建立好的映射关系,只使用一次数据拷贝,就从磁盘中将数据传入内存的用户空间中,供进程使用。

总而言之,常规文件操作需要从磁盘到页缓存再到用户主存的两次数据拷贝。而mmap操控文件,只需要从磁盘到用户主存的一次数据拷贝过程。说白了,mmap的关键点是实现了用户空间和内核空间的数据直接交互而省去了空间不同数据不通的繁琐过程。因此mmap效率更高。

mmap优点总结

由上文讨论可知,mmap优点共有一下几点:

  1. 对文件的读取操作跨过了页缓存,减少了数据的拷贝次数,用内存读写取代I/O读写,提高了文件读取效率。
  2. 实现了用户空间和内核空间的高效交互方式。两空间的各自修改操作可以直接反映在映射的区域内,从而被对方空间及时捕捉。
  3. 提供进程间共享内存及相互通信的方式。不管是父子进程还是无亲缘关系的进程,都可以将自身用户空间映射到同一个文件或匿名映射到同一片区域。从而通过各自对映射区域的改动,达到进程间通信和进程间共享的目的。同时,如果进程A和进程B都映射了区域C,当A第一次读取C时通过缺页从磁盘复制文件页到内存中;但当B再读C的相同页面时,虽然也会产生缺页异常,但是不再需要从磁盘中复制文件过来,而可直接使用已经保存在内存中的文件数据。
  4. 可用于实现高效的大规模数据传输。内存空间不足,是制约大数据操作的一个方面,解决方案往往是借助硬盘空间协助操作,补充内存的不足。但是进一步会造成大量的文件I/O操作,极大影响效率。这个问题可以通过mmap映射很好的解决。换句话说,但凡是需要用磁盘空间代替内存的时候,mmap都可以发挥其功效。

mmap相关函数

函数原型

1
void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);

返回说明

成功执行时,mmap()返回被映射区的指针。失败时,mmap()返回MAP_FAILED[其值为(void *)-1], error被设为以下的某个值:

1
2
3
4
5
6
7
8
9
10
11
12
13
EACCES:访问出错
EAGAIN:文件已被锁定,或者太多的内存已被锁定
EBADF:fd不是有效的文件描述词
EINVAL:一个或者多个参数无效
ENFILE:已达到系统对打开文件的限制
ENODEV:指定文件所在的文件系统不支持内存映射
ENOMEM:内存不足,或者进程已超出最大内存映射数量
EPERM:权能不足,操作不允许
ETXTBSY:已写的方式打开文件,同时指定MAP_DENYWRITE标志
SIGSEGV:试着向只读区写入
SIGBUS:试着访问不属于进程的内存区

返回错误类型

参数

  • start:映射区的开始地址

  • length:映射区的长度

  • prot:期望的内存保护标志,不能与文件的打开模式冲突。是以下的某个值,可以通过or运算合理地组合在一起

    1
    2
    3
    4
     PROT_EXEC :页内容可以被执行
    2 PROT_READ :页内容可以被读取
    3 PROT_WRITE :页可以被写入
    4 PROT_NONE :页不可访问
  • flags:指定映射对象的类型,映射选项和映射页是否可以共享。它的值可以是一个或者多个以下位的组合体

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    MAP_FIXED //使用指定的映射起始地址,如果由start和len参数指定的内存区重叠于现存的映射空间,重叠部分将会被丢弃。如果指定的起始地址不可用,操作将会失败。并且起始地址必须落在页的边界上。
    MAP_SHARED //与其它所有映射这个对象的进程共享映射空间。对共享区的写入,相当于输出到文件。直到msync()或者munmap()被调用,文件实际上不会被更新。
    MAP_PRIVATE //建立一个写入时拷贝的私有映射。内存区域的写入不会影响到原文件。这个标志和以上标志是互斥的,只能使用其中一个。
    MAP_DENYWRITE //这个标志被忽略。
    MAP_EXECUTABLE //同上
    MAP_NORESERVE //不要为这个映射保留交换空间。当交换空间被保留,对映射区修改的可能会得到保证。当交换空间不被保留,同时内存不足,对映射区的修改会引起段违例信号。
    MAP_LOCKED //锁定映射区的页面,从而防止页面被交换出内存。
    MAP_GROWSDOWN //用于堆栈,告诉内核VM系统,映射区可以向下扩展。
    MAP_ANONYMOUS //匿名映射,映射区不与任何文件关联。
    MAP_ANON //MAP_ANONYMOUS的别称,不再被使用。
    MAP_FILE //兼容标志,被忽略。
    MAP_32BIT //将映射区放在进程地址空间的低2GB,MAP_FIXED指定时会被忽略。当前这个标志只在x86-64平台上得到支持。
    MAP_POPULATE //为文件映射通过预读的方式准备好页表。随后对映射区的访问不会被页违例阻塞。
    MAP_NONBLOCK //仅和MAP_POPULATE一起使用时才有意义。不执行预读,只为已存在于内存中的页面建立页表入口。

    > http://manpages.ubuntu.com/manpages/xenial/man2/mmap.2freebsd.html

MAP_NOSYNC Causes data dirtied via this VM map to be flushed to physical media only when necessary (usually by the pager) rather than gratuitously. Typically this prevents the update daemons from flushing pages dirtied through such maps and thus allows efficient sharing of memory across unassociated processes using a file-backed shared memory map. Without this option any VM pages you dirty may be flushed to disk every so often (every 30-60 seconds usually) which can create performance problems if you do not need that to occur (such as when you are using shared file- backed mmap regions for IPC purposes). Note that VM/file system coherency is maintained whether you use MAP_NOSYNC or not. This option is not portable across UNIX platforms (yet), though some may implement the same behavior by default.

WARNING!  Extending a file with ftruncate(2), thus creating a big hole,
and then filling the hole by modifying a shared mmap() can lead to severe
file fragmentation.  In order to avoid such fragmentation you should
always pre-allocate the file's backing store by write()ing zero's into
the newly extended area prior to modifying the area via your mmap().  The
fragmentation problem is especially sensitive to MAP_NOSYNC pages,
because pages may be flushed to disk in a totally random order.

The same applies when using MAP_NOSYNC to implement a file-based shared
memory store.  It is recommended that you create the backing store by
write()ing zero's to the backing file rather than ftruncate()ing it.  You
can test file fragmentation by observing the KB/t (kilobytes per
transfer) results from an “iostat 1” while reading a large file
sequentially, e.g. using “dd if=filename of=/dev/null bs=32k”.

The fsync(2) system call will flush all dirty data and metadata
associated with a file, including dirty NOSYNC VM data, to physical
media.  The sync(8) command and sync(2) system call generally do not
flush dirty NOSYNC VM data.  The msync(2) system call is usually not
needed since BSD implements a coherent file system buffer cache.
However, it may be used to associate dirty VM pages with file system
buffers and thus cause them to be flushed to physical media sooner rather
than later.
1
2

flag
  • fd:有效的文件描述词。如果MAP_ANONYMOUS被设定,为了兼容问题,其值应为-1
  • offset:被映射对象内容的起点

相关函数

int munmap( void * addr, size_t len )

成功执行时,munmap()返回0。失败时,munmap返回-1,error返回标志和mmap一致;

该调用在进程地址空间中解除一个映射关系,addr是调用mmap()时返回的地址,len是映射区的大小;

当映射关系解除后,对原来映射地址的访问将导致段错误发生。

int msync( void *addr, size_t len, int flags )

一般说来,进程在映射空间的对共享内容的改变并不直接写回到磁盘文件中,往往在调用munmap()后才执行该操作。

可以通过调用msync()实现磁盘上文件内容与共享内存区的内容一致。

mmap使用细节

  1. 使用mmap需要注意的一个关键点是,mmap映射区域大小必须是物理页大小(page_size)的整倍数(32位系统中通常是4k字节)。原因是,内存的最小粒度是页,而进程虚拟地址空间和内存的映射也是以页为单位。为了匹配内存的操作,mmap从磁盘到虚拟地址空间的映射也必须是页。
  2. 内核可以跟踪被内存映射的底层对象(文件)的大小,进程可以合法的访问在当前文件大小以内又在内存映射区以内的那些字节。也就是说,如果文件的大小一直在扩张,只要在映射区域范围内的数据,进程都可以合法得到,这和映射建立时文件的大小无关。具体情形参见“情形三”。
  3. 映射建立之后,即使文件关闭,映射依然存在。因为映射的是磁盘的地址,不是文件本身,和文件句柄无关。同时可用于进程间通信的有效地址空间不完全受限于被映射文件的大小,因为是按页映射。

在上面的知识前提下,我们下面看看如果大小不是页的整倍数的具体情况:

情形一:一个文件的大小是5000字节,mmap函数从一个文件的起始位置开始,映射5000字节到虚拟内存中。

分析:因为单位物理页面的大小是4096字节,虽然被映射的文件只有5000字节,但是对应到进程虚拟地址区域的大小需要满足整页大小,因此mmap函数执行后,实际映射到虚拟内存区域8192个 字节,5000~8191的字节部分用零填充。映射后的对应关系如下图所示: tips-android-mmap-2019430182326

此时:

  1. 读/写前5000个字节(0~4999),会返回操作文件内容。
  2. 读字节50008191时,结果全为0。写50008191时,进程不会报错,但是所写的内容不会写入原文件中 。
  3. 读/写8192以外的磁盘部分,会返回一个SIGSECV错误。

情形二:一个文件的大小是5000字节,mmap函数从一个文件的起始位置开始,映射15000字节到虚拟内存中,即映射大小超过了原始文件的大小。

分析:由于文件的大小是5000字节,和情形一一样,其对应的两个物理页。那么这两个物理页都是合法可以读写的,只是超出5000的部分不会体现在原文件中。由于程序要求映射15000字节,而文件只占两个物理页,因此8192字节~15000字节都不能读写,操作时会返回异常。如下图所示: tips-android-mmap-201943018260

此时:

  1. 进程可以正常读/写被映射的前5000字节(0~4999),写操作的改动会在一定时间后反映在原文件中。
  2. 对于5000~8191字节,进程可以进行读写过程,不会报错。但是内容在写入前均为0,另外,写入后不会反映在文件中。
  3. 对于8192~14999字节,进程不能对其进行读写,会报SIGBUS错误。
  4. 对于15000以外的字节,进程不能对其读写,会引发SIGSEGV错误。

情形三:一个文件初始大小为0,使用mmap操作映射了1000*4K的大小,即1000个物理页大约4M字节空间,mmap返回指针ptr。

分析:如果在映射建立之初,就对文件进行读写操作,由于文件大小为0,并没有合法的物理页对应,如同情形二一样,会返回SIGBUS错误。

但是如果,每次操作ptr读写前,先增加文件的大小,那么ptr在文件大小内部的操作就是合法的。例如,文件扩充4096字节,ptr就能操作ptr ~ [ (char)ptr + 4095]的空间。只要文件扩充的范围在1000个物理页(映射范围)内,ptr都可以对应操作相同的大小。

这样,方便随时扩充文件空间,随时写入文件,不造成空间浪费。

mmap 的回写时机:

  • 内存不足
  • 进程 crash
  • 调用 msync 或者 munmap
  • 不设置 MAP_NOSYNC 情况下 30s-60s(仅限FreeBSD)

Android下mmap

Linux的内存分用户空间跟内核空间,同时页表有也分两类,用户空间页表跟内核空间页表,每个进程有一个用户空间页表,但是系统只有一个内核空间页表。而Binder mmap的关键是:更新用户空间对应的页表的同时也同步映射内核页表,让两个页表都指向同一块地址,这样一来,数据只需要从A进程的用户空间,直接拷贝拷贝到B所对应的内核空间,而B多对应的内核空间在B进程的用户空间也有相应的映射,这样就无需从内核拷贝到用户空间了。

普通文件mmap原理 普通文件的访问方式有两种:第一种是通过read/write系统调访问,先在用户空间分配一段buffer,然后,进入内核,将内容从磁盘读取到内核缓冲,最后,拷贝到用户进程空间,至少牵扯到两次数据拷贝;同时,多个进程同时访问一个文件,每个进程都有一个副本,存在资源浪费的问题。 另一种是通过mmap来访问文件,mmap()将文件直接映射到用户空间,文件在mmap的时候,内存并未真正分配,只有在第一次读取/写入的时候才会触发,这个时候,会引发缺页中断,在处理缺页中断的时候,完成内存也分配,同时也完成文件数据的拷贝。并且,修改用户空间对应的页表,完成到物理内存到用户空间的映射,这种方式只存在一次数据拷贝,效率更高。同时多进程间通过mmap共享文件数据的时候,仅需要一块物理内存就够了。 共享内存中mmap的使用 共享内存是在普通文件mmap的基础上实现的,其实就是基于tmpfs文件系统的普通mmap,

Android NDK备忘

发表于 2019-04-25 | 分类于 tips

Android NDK Crash 日志抓取及定位

NDK-STACK 定位 NDK Crash 位置

只要执行如下代码就行:

1
adb logcat | ndk-stack -sym /yourProjectPath/obj/local/armeabi-v7a

PS: 必须是带symbols的so,也就是在’\app\src\main\obj\local\下面的so’, 否则行号打印出来降是??.??

使用 arm-linux-androideabi-addr2line 定位 NDK Crash

1
#11 pc 00032493  /data/app/com.pic.livefilters-1/lib/arm/libhairUtils.so (detectHairByOpenCV+1930)

执行

1
arm-linux-androideabi-addr2line -e /yourProjectPath/src/main/obj/local/armeabi-v7a/libhairUtils.so 00032493

将pc地址转换为行号 aarch64-linux-android-addr2line工具地址

1
ndk-bundle/toolchains/aarch64-linux-android-4.9/prebuilt/darwin-x86_64/bin/aarch64-linux-android-addr2line
123…19
轻口味

轻口味

190 日志
27 分类
63 标签
RSS
GitHub 微博 豆瓣 知乎
友情链接
  • SRS
© 2015 - 2019 轻口味
京ICP备17018543号
本站访客数 人次 本站总访问量 次