2012年1月31日火曜日

[PostgreSQL] 数据库关闭选项

默认方式, 等待所有客户端连接切断
$ pg_ctl stop -m s
$ pg_ctl stop -m smart

切断所有客户端连接, 回滚事务
$ pg_ctl stop -m f
$ pg_ctl stop -m fast

直接停止服务, 数据不一致, 下次启动要做 crash 恢复
$ pg_ctl stop -m i
$ pg_ctl stop -m immediate

数据库重启动也包括相同的关闭选项
$ pg_ctl restart -m [s, f, i]

[PostgreSQL] 自动提交 AUTOCOMMIT

默认 autocommit 是 on
create table 等 DDL 也可以回滚

1. 设置 (客户端)
$ cat $HOME/.psqlrc
\set AUTOCOMMIT off

=# \echo :AUTOCOMMIT
off

2. 提交
=# commit;
=# end;

3. 回滚
=# rollback;

4. 运行时设置 (服务器端设置)
=# set AUTOCOMMIT TO on;
=# show AUTOCOMMIT;
 autocommit
------------
 on
(1 row)

设置后同时影响本 session
=# \echo :AUTOCOMMIT
on

2012年1月29日日曜日

[LINUX 基础] 文件/目录权限总结

1. 即使具有目录(r)权限, 也不能进入目录, 想要进入目录必须拥有该目录的执行权限(x)

2. 如果具有目录的(x)权限, 就能进入目录, 并且只要存在下面的条件, 就能够读取或复制目录中的文件

2-1. 知道文件名
2-2. 具有文件的读(r)权限

3. 要列出目录中的内容(ls等)并且进入一个目录, 需要拥有目录的(r)和(x)两个权限

4. 只具备目录的写(w)权限, 并不能对目录和其下的文件进行删除修改操作, 需要再具备目录(x)
   只要具备目录(wx)权限, 那么就能够创建/删除/修改该目录中的文件和子目录, 即使是其它人的文件或子目录或不具备任何权限, 也能够操作

5. 如果想在一个目录中创建文件, 必须至少具有所有上级目录的(x)权限和本目录的(wx)权限

2012年1月27日金曜日

[工具使用] ssh 免密码登录远程主机

1. 免密码访问远程主机

1-1. 目标主机上创建 .ssh 文件夹 (没有则创建)
[go@target ~]$ mkdir .ssh
[go@target ~]$ chmod 700 .ssh

1-2. 本地生成密钥对
[go@localhost ~]$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/go/.ssh/id_rsa): <= 回车
Created directory '/home/go/.ssh'.
Enter passphrase (empty for no passphrase): <= 回车
Enter same passphrase again: <= 回车
Your identification has been saved in /home/go/.ssh/id_rsa.
Your public key has been saved in /home/go/.ssh/id_rsa.pub.
The key fingerprint is:
3a:5f:79:80:e5:f2:67:e6:3e:a9:9f:f1:3f:a5:43:f6 go@localhost

1-3. 将公钥上传到目标主机 (文件存在则追加到 authorized_keys 中)
[go@localhost ~]$ scp .ssh/id_rsa.pub go@target:~/.ssh/authorized_keys

1-4. 目标主机上修改认证文件权限 (644)
[go@target ~]$ chmod 644 .ssh/authorized_keys

1-5. 测试
[go@localhost ~]$ ssh go@target ls

2. 免密码多台主机互访

2-1. 在各个主机上生成密钥对
[go@centos56 ~]$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/go/.ssh/id_rsa): <= 回车
Created directory '/home/go/.ssh'.
Enter passphrase (empty for no passphrase): <= 回车
Enter same passphrase again: <= 回车
Your identification has been saved in /home/go/.ssh/id_rsa.
Your public key has been saved in /home/go/.ssh/id_rsa.pub.
The key fingerprint is:
3a:5f:79:80:e5:f2:67:e6:3e:a9:9f:f1:3f:a5:43:f6 go@centos56

[go@centos57 ~]$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/go/.ssh/id_rsa): <= 回车
Created directory '/home/go/.ssh'.
Enter passphrase (empty for no passphrase): <= 回车
Enter same passphrase again: <= 回车
Your identification has been saved in /home/go/.ssh/id_rsa.
Your public key has been saved in /home/go/.ssh/id_rsa.pub.
The key fingerprint is:
59:81:95:b5:59:60:84:bd:4f:17:f5:cd:6e:44:fe:d1 go@centos57

2-2. 在各个主机上拷贝公钥到其他主机
[go@centos56 ~]$ ssh-copy-id -i .ssh/id_rsa.pub go@centos57
15
go@centos57's password:
Now try logging into the machine, with "ssh 'go@centos57'", and check in:

  .ssh/authorized_keys

to make sure we haven't added extra keys that you weren't expecting.

[go@centos57 ~]$ ssh-copy-id -i .ssh/id_rsa.pub go@centos56
15
The authenticity of host 'centos56 (centos56)' can't be established.
RSA key fingerprint is 88:01:a5:f8:af:c9:5a:3d:19:30:5b:fc:d4:19:07:29.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'centos56' (RSA) to the list of known hosts.
go@centos56's password:
Now try logging into the machine, with "ssh 'go@centos56'", and check in:

  .ssh/authorized_keys

to make sure we haven't added extra keys that you weren't expecting.

2-3. 测试
[go@centos56 ~]$ ssh go@centos57 ls
[go@centos57 ~]$ ssh go@centos56 ls

2012年1月21日土曜日

[PostgreSQL] 安装和初始配置

1. 安装 (支持多版本安装)
$ cd /usr/local/src/pgsql912
$ ./configure --prefix=/usr/local/pgsql912 --with-pgport=9120
$ make world
# make install-world

2. 设置环境变量
$ cat ~/settings/postgresql912.profile
PGBASE=/usr/local/pgsql912/
PATH=$PGBASE/bin:$PATH; export PATH
LD_LIBRARY_PATH=$PGBASE/lib; export LD_LIBRARY_PATH
MANPATH=$PGBASE/share/man:$MANPATH export MANPATH
PGDATA=/home/go/data/pgsql912; export PGDATA
PGPORT=9120; export PGPORT
PGSHARE=/usr/local/pgsql912; export PGSHARE

$ source ~/settings/pgsql912.profile

3. 初始化数据库
$ initdb -E EUC_JP --no-locale

4. 初始设置
$ vim $PGDATA/postgresql.conf
listen_addresses = '*'
max_connections = 50
logging_collector = on
log_destination = 'stderr'
log_line_prefix = '%t %p '
log_connections = on
shared_buffers = 32MB (1/4 物理内存)
wal_buffers = 64kB (640kB PostgreSQL 9.1 以上 -1 自动设置)
checkpoint_segments = 3 (10)

$ vim $PGDATA/pg_hba.conf
host dbname username 10.0.0.1/32 md5
host dbname username 0.0.0.0/0 md5

5. 启动关闭
$ pg_ctl start -w
$ pg_ctl stop -mf

6. 自启动设置
# cd /usr/local/src/pgsql912/contrib/start-scripts
# cp linux /etc/rc.d/init.d/pgsql912
# chmod a+rx /etc/rc.d/init.d/pgsql912
# chkconfig --add pgsql912
# runlevel
# chkconfig --list pgsql912
# chkconfig pgsql912 off
# chkconfig --level 5 pgsql912 on

[LINUX 基础] CentOS 设置 sudo

# rpm -qa | grep sudo
sudo-1.7.2p1-10.el5

# visudo
go      ALL=(ALL)       ALL

[LINUX 基础] 修改主机名

1. CentOS
# vim /etc/sysconfig/network
-HOSTNAME=centos57
+HOSTNAME=localhost.localdomain

# vim /etc/hosts
-127.0.0.1   localhost.localdomain localhost.localdomain
+127.0.0.1   localhost localhost

# /sbin/sysctl -a | grep hostname
kernel.hostname = centos57

# hostname
centos57

# cat /etc/sysconfig/network
NETWORKING=yes
NETWORKING_IPV6=no
HOSTNAME=centos57

--------------------------------------------------------------------------------
2.Ubuntu
# vi /etc/hostname
# vi /etc/hosts

2012年1月19日木曜日

[安装配置] 使用 unixODBC 实现 PostgreSQL 与 Oracle 互访

1. 环境
CentOS 5.6 x86_64 (2.6.18-194.32.1.el5.centos.plus)
Oracle 10g XE
Postgresql 8.4.10, 9.0.6, 9.1.2

注意:
在 Oracle 服务器上查看 hsodbc 版本
hsodbc 一般是 32 位的, 需要安装用 32bit 的 unixODBC 和 ODBC 驱动

$ file $ORACLE_HOME/bin/hsodbc
/usr/lib/oracle/xe/app/oracle/product/10.2.0/server/bin/hsodbc: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.2.5, dynamically linked (uses shared libs), for GNU/Linux 2.2.5, stripped
--------------------------------------------------------------------------------
2. 下载
2-1. unixODBC
http://dev.centos.org/centos/5/testing/i386/RPMS/
unixODBC-2.2.12-1.el5s2.i386.rpm
unixODBC-devel-2.2.12-1.el5s2.i386.rpm
unixODBC-kde-2.2.12-1.el5s2.i386.rpm [可选]

http://dev.centos.org/centos/5/testing/x86_64/RPMS/
unixODBC-2.2.12-1.el5s2.x86_64.rpm
unixODBC-devel-2.2.12-1.el5s2.x86_64.rpm
unixODBC-kde-2.2.12-1.el5s2.x86_64.rpm [可选]

2. Oracle Instant Client (客户端免安装版)
http://www.oracle.com/technetwork/jp/topics/linuxx86-64soft-085244-ja.html
basic-10.2.0.5.0-linux-x64.zip
odbc-10.2.0.5.0-linux-x64.zip

3. ODBC-Link
http://www.cybertec.at/en/ressources/postgresql_downloads
ODBC-Link-1.0.5.tar.gz
--------------------------------------------------------------------------------
3. 安装

3-1. 安装 unixODBC RPMS
$ su - root
# rpm -ivh unixODBC-2.2.12-1.el5s2.i386.rpm unixODBC-devel-2.2.12-1.el5s2.i386.rpm
# rpm -ivh unixODBC-2.2.12-1.el5s2.x86_64.rpm unixODBC-devel-2.2.12-1.el5s2.x86_64.rpm
# ldconfig
# odbcinst -j
unixODBC 2.2.12
DRIVERS............: /etc/odbcinst.ini
SYSTEM DATA SOURCES: /etc/odbc.ini
USER DATA SOURCES..: /root/.odbc.ini

3-2. 安装 Oracle Instant Client
如果已经安装过 Oracle 客户端, 则不需要安装
# locate libsqora.so.10.1
/usr/lib/oracle/xe/app/oracle/product/10.2.0/server/lib/libsqora.so.10.1

# su - root
# unzip basic-10.2.0.5.0-linux-x64.zip
# unzip odbc-10.2.0.5.0-linux-x64.zip
# mv instantclient_10_2 /usr/local/src/instantclient_10_2

3-3. 安装 ODBC-Link
不同版本数据库需要重新编译安装, 已确认版本 (8.4.10, 9.0.4, 9.1.2)

# su - root
# pg_config <= 确认 PostgreSQL 9.1.2 配置信息
# tar zxvf ODBC-Link-1.0.5.tar.gz
# mv ODBC-Link-1.0.5 /usr/local/src/ODBC-Link-1.0.5
# cd /usr/local/src/ODBC-Link-1.0.5
# USE_PGXS=1 make clean <= 清除编译信息
# USE_PGXS=1 make
# USE_PGXS=1 make install
# USE_PGXS=1 make uninstall <= 卸载
# su - postgres
$ cd <PostgreSQL 9.1.2 安装路径>/share/contrib
$ psql -f odbclink.sql <db_name>
--------------------------------------------------------------------------------
4. 配置
4-1. 配置 ODBC 驱动
# su - root
# vim /etc/odbcinst.ini (添加)
[PG_ODBC_DRIVER]
Description     = ODBC for PostgreSQL
Driver          = /usr/lib/libodbcpsql.so
Setup           = /usr/lib/libodbcpsqlS.so
FileUsage       = 1

[ORA_ODBC_DRIVER]
Description     = ODBC for Oracle
Driver          = /usr/local/src/instantclient_10_2/libsqora.so.10.1

4-2. 配置数据源
# vim /etc/odbc.ini (添加)
[PG] <= Oracle 端使用
Driver = PG_ODBC_DRIVER
FileUsage = 1
Database = go
Servername = localhost
Port = 9112
Username = go
Password = go
# Trace = Yes
# TraceFile = /tmp/pg91x_odbc.log
# Debug = 0
# CommLog = 1

[ORA] <= PostgreSQL 端使用
Driver = ORA_ODBC_DRIVER
Database = //localhost:1521/XE
Port = 1521
UserID = go
Password = go
# Trace = Yes
# TraceFile = /tmp/ora10g_odbc.log
# Debug = 1
# CommLog = 1

重启 PostgreSQL 数据库
# su - postgres
$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/src/instantclient_10_2
$ export TWO_TASK=//localhost:1521/XE
$ pg_ctl restart -mf

4-3. 配置 Oracle 端
# su - oracle
$ vim $ORACLE_HOME/hs/admin/init<SID>.ora (新建) <= 此处 SID 设置为 PG
HS_FDS_CONNECT_INFO = PG
HS_FDS_TRACE_LEVEL = 0
HS_FDS_TRACE_FILE_NAME = topg.trc
HS_FDS_SHAREABLE_NAME = /usr/lib/libodbc.so
set ODBCINI = /usr/lib/oracle/xe/.odbc.ini
set LD_LIBRARY_PATH = $LD_LIBRARY_PATH:/usr/lib/libodbc.so

$ vim $ORACLE_HOME/network/admin/tnsnames.ora (添加)
PG =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = localhost) (PORT = 1521))
    (CONNECT_DATA =
        (SID = <SID>) <= 此处 SID 设置为 PG
    )
    (HS = OK)
  )

$ vim $ORACLE_HOME/network/admin/tnsnames.ora (添加)
SID_LIST_LISTENER =
  (SID_LIST =
    <-- 开始 -->
    (SID_DESC =
      (SID_NAME = <SID>) <= 此处 SID 设置为 PG
      (ORACLE_HOME = /usr/lib/oracle/xe/app/oracle/product/10.2.0/server)
      (PROGRAM = hsodbc)
    )
    <-- 结束 -->
  )

重启 Oracle 监听
$ lsnrctl stop
$ lsnrctl start
--------------------------------------------------------------------------------
5. 测试
5-1. PostgreSQL to Oracle
# su - postgres
$ psql <db_name>
=# select odbclink.connect('DSN=ORA'); <= 4-2 配置的数据源
 connect
---------
       1
(1 row)

=# select * from odbclink.query(1,'SELECT dummy FROM dual') as (name text);
 name
------
 X
(1 row)

5-2. Oracle to PostgreSQL
# su - oracle
$ sqlplus / as sysdba
SQL> create public database link <db_link_name> connect to "username" identified by "password" using '<DSN>';
# user: PostgreSQL username <= 4-2 中的配置
# pass: PostgreSQL password
# DSN : PostgreSQL 数据源

例:
SQL> create public database link PGLINK connect to "hoge" identified by "hoge" using 'PG';
SQL> select * from "t"@PGLINK;
a
-------
1

1 rows selected.

2012年1月18日水曜日

[LINUX 基础] RPM 相关

1. 64 位系统下查看 rpm 包
rpm -q --qf "%{n}-%{v}-%{r}.%{arch}\n" [包名列表]

2. 删除同名复数个 rpm 包
rpm -e --allmatches [包名列表]

3. 查看安装路径
rpm -ql [包名列表]

4. 安装前查看将要安装的文件和路径
rpm -qlp [包名列表]

--------------------------------------------------------------------------------

RPM命令手册

通用选项

-v 显示附加信息
-vv 显示调试信息
--root 让RPM将指定的路径做为"根目录",这样预安装程序和后安装程序都会安装到这个目录下
--rcfile 设置rpmrc文件为
--dbpath 设置RPM 资料库存所在的路径为

1. 安装
rpm -i ( or --install) options file1.rpm ... fileN.rpm

-h (or --hash) 安装时输出hash记号 (``#'')
--test 只对安装进行测试,并不实际安装。
--percent 以百分比的形式输出安装的进度。
--excludedocs 不安装软件包中的文档文件
--includedocs 安装文档
--replacepkgs 强制重新安装已经安装的软件包
--replacefiles 替换属于其它软件包的文件
--force 忽略软件包及文件的冲突
--noscripts 不运行预安装和后安装脚本
--prefix 将软件包安装到由 指定的路径下
--ignorearch 不校验软件包的结构
--ignoreos 不检查软件包运行的操作系统
--nodeps 不检查依赖性关系
--ftpproxy 用 作为 FTP代理
--ftpport 指定FTP的端口号为

2. 删除
rpm -e ( or --erase) options pkg1 ... pkgN

--test 只执行删除的测试
--noscripts 不运行预安装和后安装脚本程序
--nodeps 不检查依赖性

3. 升级
rpm -U ( or --upgrade) options file1.rpm ... fileN.rpm

-h (or --hash) 安装时输出hash记号 (``#'')
--oldpackage 允许"升级"到一个老版本
--test 只进行升级测试
--excludedocs 不安装软件包中的文档文件
--includedocs 安装文档
--replacepkgs 强制重新安装已经安装的软件包
--replacefiles 替换属于其它软件包的文件
--force 忽略软件包及文件的冲突
--percent 以百分比的形式输出安装的进度。
--noscripts 不运行预安装和后安装脚本
--prefix 将软件包安装到由 指定的路径下
--ignorearch 不校验软件包的结构
--ignoreos 不检查软件包运行的操作系统
--nodeps 不检查依赖性关系
--ftpproxy 用 作为 FTP代理
--ftpport 指定FTP的端口号为

4. 查询
rpm -q ( or --query) options

-p (or ``-'') 查询软件包的文件
-f 查询属于哪个软件包
-a 查询所有安装的软件包
--whatprovides 查询提供了 功能的软件包
-g 查询属于 组的软件包
--whatrequires 查询所有需要 功能的软件包
-i 显示软件包的概要信息
-l 显示软件包中的文件列表
-c 显示配置文件列表
-d 显示文档文件列表
-s 显示软件包中文件列表并显示每个文件的状态
--scripts 显示安装、卸载、校验脚本
--queryformat (or --qf) 以用户指定的方式显示查询信息
--dump 显示每个文件的所有已校验信息
--provides 显示软件包提供的功能
--requires (or -R) 显示软件包所需的功能

5. 校验已安装的软件包
rpm -V ( or --verify, or -y) options

-p Verify against package file
-f 校验所属的软件包
-a Verify 校验所有的软件包
-g 校验所有属于组 的软件包
--noscripts 不运行校验脚本
--nodeps 不校验依赖性
--nofiles 不校验文件属性

6. 校验软件包中的文件
rpm -K ( or --checksig) options file1.rpm ... fileN.rpm

--nopgp 不校验PGP签名

7. 其它RPM选项

--rebuilddb 重建RPM资料库
--initdb 创建一个新的RPM资料库
--quiet 尽可能的减少输出
--help 显示帮助文件
--version 显示RPM的当前版本

2012年1月15日日曜日

[PostgreSQL] COPY

1. \copy 命令
客户端命令, 存取的文件保存在客户端, 默认操作当前目录下的文件
数据库普通用户权限即可操作

1-1. CSV 模式 (共通)
=> \copy t from t.csv CSV
=> \copy t to t.csv CSV

1-1-1. 列值可以用双引号 " 包围, 列值内包含双引号 " 的使用 ("")
"1","aaa" => 1,aaa
"1","a""aa" => 1,a"aa

1-1-2. 指定 QUOTE [AS]
|1|,|aaa| => 1,aaa
|1|,|a""aa| => 1,a""aa
|1|,|a|aa| => error

1-1-3. 指定 ESCAPE [AS]
|1|,|a"aa| => 1,a"aa

1-1-4. 指定 FORCE NOT NULL 列名,... (输入用)
1, => 1,空字符串 (长度为 0, 但不是 NULL)

1-1-5. 指定 FORCE QUOTE 列名,... (输出用)
1,aaa => 1,"aaa"


1-2. 文本模式 (默认是 tab 分隔)
=> \copy t from t.txt
=> \copy t to t.txt
=> \copy t to t.txt DELIMITER ':' (指定分隔符)

1-3. NULL 的处理
=> \copy t to t.csv NULL 'null' (NULL 表示为 null)

2. copy (SQL)
服务器命令, 存取的文件保存在服务器端, 并且使用绝对路径,
只有数据库超级用户权限可操作

2-1. CSV 模式
=# copy t from '/path/to/filename' CSV;

2-2. 文本模式
=# copy t from '/path/to/filename';

2-3. stdin, stdout 模式 (普通用户权限即可)
=> copy t to stdout;
=> copy t to stdout CSV;
=> copy t from stdin; (最后用 \.结束)
=> copy t from stdin CSV;
--------------------------------------------------------------------------------
1. copy 或 prepare statment 比一般 insert 快的原因
1-1. 在一个 trans 中
1-2. sql 只解析一次

2. 调整如下参数
fsync = off (copy 后还原为 on)
wal_buffers = 较大的值 (最大 16MB 足够)
wal_level = minimal
archive_mode = off
checkpoint_segments = 100
synchronous_commit = off
full_page_writes = off
maintenance_work_mem = 增加

3. 8.3 以上, copy 前加 ddl 操作 (不写 wal)
archive_mode = off (on 时无效, 写 wal)
BEGIN;
CREATE TABLE test table...
COPY TABLE ...
COMMIT;
END;

4. 指定 psql 或 pg_restore 选项 -1 之后, 自动加上 begin ... commit

5. 其他
删除对象表的 index 和 约束, copy 后重建
多个表同时进行
数据导入后 analyze

6. pg_bulkload

[PostgreSQL] 执行计划的特点

1. sql 解析的结果和执行计划等, 不能在 session 间共享
2. JDBC 中, 根据连接参数 prepareThreshold (默认 5) 来控制 sql 解析结果的重用次数, 使用org.postgresql.PGStatement 的 setPrepareThreshold 来调整

[PostgreSQL] 测定 SQL 执行时间

1. 客户端向服务器发送 sql
2. 服务器解析 sql
3. 服务器创建执行计划
4. 服务器执行 sql
5. 客户端接收 sql 执行结果

1. linux 命令 (步骤 1-5)
$ time psql -c 'select count(*) pg_class'

real    0m0.018s
user    0m0.001s
sys     0m0.001s

2. \timing (步骤 1-5)
=# \timing
 Timing is on.

=# \timing
 Timing is off.

3. 输出 LOG (步骤 2-4)
设置 postgresql.conf 的 log_min_duration_statement

4. EXPLAIN ANALYZE SELECT ... (步骤 4)

5. pg_stat_statements 模块 (步骤 4)
PostgreSQL 8.4 以后 contrib 模块

=# SELECT query, calls, total_time, rows, total_time/calls AS once_time FROM pg_stat_statements ORDER BY once_time DESC LIMIT 3;

[PostgreSQL] 控制执行计划的方法

1-1. 提高 ANALYZE 频率

1-2. 增加统计信息的直方图记录数 (抽样)

1-2-1. postgresql.conf 设置 (PostgreSQL 8.0 以后)
default_statistics_target = 1000

1-2-2. 特定表的特定列设置 (推荐使用)
ALTER TABLE table_name ALTER col_name SET STATISTICS 1000;

1-3. 调整优化器的参数

=# show enable_
enable_bitmapscan  enable_hashjoin    enable_material    enable_nestloop
enable_sort        enable_hashagg     enable_indexscan   enable_mergejoin
enable_seqscan     enable_tidscan

=# show enable_seqscan;
-[ RECORD 1 ]--+---
enable_seqscan | on

=# BEGIN;
BEGIN

=# set local enable_seqscan to off;
SET

=# show enable_seqscan;
-[ RECORD 1 ]--+----
enable_seqscan | off

=# select ...
=# commit;

2012年1月13日金曜日

[Shell 基础] shell 判断多重启动

1. 采用 lock 文件
--------------------------------------
#!/bin/sh
if ln -s /tmp/checkfile.pid; then
  echo "startup..."
  sleep 10
else
  echo "is running..."
  exit
fi
rm -f checkfile.pid
--------------------------------------

2. 采用 ps 命令

2-1. 运行 shell 脚本
$ sh check.sh

2-2. 判断 check.sh 是否在运行
----------------------------------------------------------------
#!/bin/sh
res=`ps aux | grep "check.sh" | grep -v grep | awk '{print $2}'`
if [ -z "$res" ] ; then
  echo "startup..."
else
  echo "is running..."
fi
----------------------------------------------------------------

2012年1月11日水曜日

[Shell 基础] 测试 shell 的输出

$ cat test.sh
#! /bin/bash
echo aaaaaaa

$ cat result.log
#! /bin/bash
echo aaaaaaa

$ sh -v test.sh 2>&1 | diff -u result.log -
--- result.log  2012-02-02 17:50:41.000000000 +0900
+++ -   2012-02-02 19:12:55.366859000 +0900
@@ -1,2 +1,3 @@
 #! /bin/bash
 echo aaaaaaa
+aaaaaaa

$ cat result.log
#! /bin/bash
echo aaaaaaa
aaaaaaa

$ sh -v test.sh 2>&1 | diff -u result.log -

2012年1月10日火曜日

[工具使用] lv 的使用

1. 显示文件编码方式
CTL + g

2. 转换文件编码方式 (to utf8)
lv -Ou8 old_file > new_file

3. 帮助
lv -h

[Shell 基础] 字符串操作

1. 字符串长度
echo ${#str}

2. 字符串转为数字形式计算
echo $((str-1))

3. 截取指定长度字符串 (下标从 0 开始)
echo ${str:0:3}

4. 字符串比较
4-1.
if [ $str != "" ]; then
# if [ $str = "" ]; then
    echo $str
fi

4-2.
test "abc"  = "abc" ; echo $? # 0
test "abc" != "abc" ; echo $? # 1

4-3. 字符串长度的判断
[ "" ]; echo $? #1
[ "a" ]; echo $? # 0
test -z "";  echo $? # 0
test -z "a"; echo $? # 1
test -n "";  echo $? # 1
test -n "a"; echo $? # 0

5. 字符串连结
str1="a"
str2="b"
str=$str1$str2"c"
echo $str


6. 设置默认值
变量 AAA 未设置时, 使用默认值, 设置时, 使用设置的值
#!bin/sh
#AAA="world"
BBB=${AAA:-"hello"}
echo "AAA="$AAA  # 空
echo "BBB="$BBB  # hello



AAA="world"
BBB=${AAA:-"hello"}
echo "AAA="$AAA  # world

echo "BBB="$BBB  # world

2012年1月7日土曜日

[PostgreSQL] transaction id 重叠现象

1. xid 以 2^32 = 40 亿的数值来存储.

2. xid 以 2^31 = 20 亿 (age = 当前 xid - 冻结 xid) 来判断数据的可见性, 从当前 xid 回溯 20 亿次事务之内的数据作为过去的数据是可见的. 其他的作为未来的事务数据不可见.

3. 如果 age 超过了 20 亿的界限, 则从当前 xid 回溯 20 亿次事务之前的数据将变为不可见. 这个就是 xid 重叠. pgsql 采用冻结 xid (FreezeXID = 2) 来解决此问题. 假设当前 xid 是 15 亿, vacuum 之后 10 亿次事务之前的数据 (5 亿以下) 的 xid 都变为 (FreezeXID), 这些数据的 xid 被永久冻结, 直到被删除.

4. template0 这样的数据库, xid 被冻结并且不发生写入操作的, 不会发生 xid 重叠现象.

5. 查询 xid 信息
SELECT relname, age(relfrozenxid) FROM pg_class WHERE relkind = 'r';
SELECT datname, age(datfrozenxid) FROM pg_database;

 
为了跟踪数据库中最老的 XID 寿命, VACUUM 在系统表 pg_class 和 pg_database 里存储了事务 ID 统计. 一个数据库的 pg_class 行中的 relfrozenxid 字段包含了最后一个 VACUUM 命令使用的冻结终止 XID. 系统保证在该数据库中所有比这个终止 XID 老的普通 XID 都被 FrozenXID 代替. 一个数据库的 pg_database 行中的 datfrozenxid 字段是普通 XID 的下界, 它只是数据库中每个表 relfrozenxid 的最小值. age 字段用于测量从 FrozenXID 到当前事务 XID 的数目. VACUUM 之后. age(relfrozenxid) 应当立即使用稍微大于 vacuum_freeze_min_age 的值 (比 VACUUM 启动之后开始的事务数目稍大). 如果 age(relfrozenxid) 超过 autovacuum_freeze_max_age, 将会很快在表上强制进行自动清理.

2012年1月6日金曜日

[Shell 基础] sed 的使用方法

================================================================================
# sed -e 's/123/1234/' a.txt
将a.txt文件中所有行中的123用1234替换(-e表示命令以命令行的方式执行;参数s,表示执行替换操作)
# sed -e '3,5 a4' a.txt
将a.txt文件中的3行到5行之间所有行的后面添加一行内容为4的行(参数a,表示添加行,参数a后面指定添加的内容)
# sed -e '1 s/12/45/' a.txt
把第一行的12替换成45
sed -i "s/oldstring/newstring/g" `grep oldstring -rl yourdir`
批量处理通过grep搜索出来的所有文档,将这些文档中所有的oldstring用newstring替换(-i参数表示直接对目标文件操作)
$ sed -n 's/^test/mytest/p' example.file
(-n)选项和p标志一起使用表示只打印那些发生替换的行。也就是说,如果某一行开头的test被替换成mytest,就打印它。(^这是正则表达式中表示开头,该符号后面跟的就是开头的字符串)(参数p表示打印行)
$ sed 's/^go/&19850715/' example.file
表示被替换换字符串被找到后,被替换的字符串通过&符号连接给出的字符串组成新字符传替换被替换的字符串,所有以go开头的行都会被替换成它自已加19850715,变成go19850715
$ sed -n 's/\(love\)able/\1rs/p' example.file
love 被标记为1,所有loveable会被替换成lovers,而且替换的行会被打印出来。需要将这条命令分解,s/是表示替换操作,\(love\)表示选中love字符串,\(love\)able/表示包含loveable的行,\(love\)able/\l表示love字符串标记为1,表示在替换过程中不变。rs/表示替换的目标字符串。这条命令的操作含义:只打印替换了的行
$ sed 's#10#100#g' example.file
不论什么字符,紧跟着s命令的都被认为是新的分隔符,所以,“#”在这里是分隔符,代替了默认的“/”分隔符。表示把所有10替换成100。
$ sed -n '/love/,/unlove/p' example.file
只打印包含love字符串行到包含unlove字符串行之间的所有行(确定行的范围就是通过逗号实现的)
$ sed -n '5,/^wang/p' example
只打印从第五行开始到第一个包含以wang开始的行之间的所有行
$ sed '/love/,/unlove/s/$/go/' example.file
对于包含love字符串的行到包含unlove字符串之间的行,每行的末尾用字符串go替换。
字符串$/表示以字符串结尾的行,$/表示每一行的结尾,s/$/go/表示每一行的结尾添加go字符串
$ sed -e '11,53d' -e 's/wang/pan/' example.file
(-e)选项允许在同一行里执行多条命令。如例子所示,第一条命令删除11至53行,第二条命令用pan替换wang。命令的执行顺序对结果有影响。如果两个命令都是替换命令,那么第一个替换命令将影响第二个替换命令的结果。(参数d,表示删除指定的行)
$ sed --expression='s/wang/pan/' --expression='/love/d' example.file
一个比-e更好的命令是--expression。它能给sed表达式赋值。
$ sed '/go/r file' example.file
file里的内容被读进来,显示在与go匹配的行后面,如果匹配多行,则file的内容将显示在所有匹配行的下面。参数r,表示读出文件,后面空格紧跟文件名称
$ sed -n '/test/w file' example.file
在example.file中所有包含test的行都被写入file里。参数w,表示将匹配的行写入到指定的文件file中
$ sed '/^test/a\oh! My god!' example.file
'oh! My god!'被追加到以test开头的行的后面,sed要求参数a后面有一个反斜杠。
$ sed '/test/i\oh! My god!' example.file
'oh! My god!'被追加到包含test字符串行的前面,参数i表示添加指定内容到匹配行的前面,sed要求参数i后面有一个反斜杠
$ sed '/test/{ n; s/aa/bb/; }' example.file
如果test被匹配,则移动到匹配行的下一行,替换这一行的aa,变为bb。参数n,表示读取匹配行的下一个输入行,用下一个命令处理新的行而不是匹配行。Sed要求参数n后跟分号
$ sed '1,10y/abcde/ABCDE/' example.file
把1—10行内所有abcde转变为大写,注意,正则表达式元字符不能使用这个命令。参数y,表示把一个字符翻译为另外的字符(但是不用于正则表达式)
$ sed -i 's/now/right now/g' test_sed_command.txt
表示直接操作文件test_sed_command.txt,将文件test_sed_command.txt中所有的now用right now替换。参数-i,表示直接操作修改文件,不输出。
$ sed -e '/old/h' -e '/girl-friend/G' test_sed_command.txt
首先了解参数h,拷贝匹配成功行的内容到内存中的缓冲区。在了解参数G,获得内存缓冲区的内容,并追加到当前模板块文本的后面。上面命令行的含义:将包含 old字符串的行的内容保存在缓冲区中,然后将缓冲区的内容拿出来添加到包含girl-friend字符串行的后面。隐含要求搜集到缓冲区的匹配行在需要添加行的前面。
$ sed -e '/test/h' -e '/go/x' example.file
将包含test字符串的行的内容保存在缓冲区中,然后再将缓冲区的内容替换包含go字符串的行。参数x,表示行替换操作。隐含要求搜集到缓冲区的匹配行在需要被替换行的前面。
================================================================================


0. 文件内容
$ cat test.log
key1=value1
key2=value2
key3=value3

使用方法
sed [option] filename 或 cat filename | sed [option]


1. 删除行
1-1. 正则表达式
$ cat filename sed [-e] '1,2d' <= 指定行号, 删除第 1, 2 行
$ cat filename sed [-e] '/key1/d' <= 包含 key1 的行被删除
$ cat filename sed [-e] '/^key1/d' <= 以 key1 开头的行被删除
$ cat filename sed [-e] '/value1$/d' <= 以 value1 结尾的行被删除
$ cat filename sed [-e] '/^key1=value1$/d' <= key1=value1 行完全匹配的行被删除
$ cat filename sed [-e] '/^key1$/d' <= 无匹配行, 则不删除
$ cat filename sed [-e] '/key1=value1/,/key2=value2/d' <= 指出删除范围, 加逗号
$ cat filename sed [-e] "/AAA/,/BBB/s/$/TAIL/"  <= 包含AAA到包含BBB的行, 在其末尾添加TAIL
$ cat filename sed [-e] '/^key1/d' -e '/^key2/d' <= 分别指出删除行, 删除多行
$ cat filename sed [-e] '/^key1/d <= 以换行的形式来指定多行
/^key2/d'
$ cat filename sed [-e] '1,/^$/!d;/^$/d' <= 命令连写, 保留从第一行开始到第一个空行结束, 并删除空行
$ sed '/^$/d' file <= 删除空行
$ sed '/^  *$/d' file <= 删除空格行 (两个空格)
$ sed '/^ *$/d' file <= 删除空行与空格行 (一个空格)


2. 替换行内的字符串
2-1. s/: 开头, /: 中间, /g: 结尾 (g: 匹配一行中所有字符)
$ sed 's/AAA/BBB/g'
$ sed 's/  */ /g' file (两个空格) <= 替换所有连续空格为一个空格
$ sed 's/  *//g' file (两个空格) <= 删除所有空格
$ sed 's/ */ /g' file (一个空格) <= 每个字符用一个空格隔开
$ sed 's/^/HEAD/;s/$/TAIL/' file <= 在行首行尾添加字符
$ sed 's/^,//' file <= 去掉行首 , 号
$ sed '1 s/AAA/BBB/' filename  <= 替换第 1 行
$ sed '1,2 s/AAA/BBB/' filename  <= 替换第 1, 2 行
$ sed [-i] "s/error/ERROR/g" `grep "error" -rl logs` <= 指定某文件夹下所有文件
$ sed -n "1,2 s/key//p" <= -n p 同时使用表示只打印被替换的行
$ sed "s/key/&->/" <= 用原字符串加附加的字符串的结果替换原字符串
$ sed "s#10#100#g"  <= # 来替换 / 做分隔符

$ sed "s/\(love\)able/\1rs/" filename
love被标记为1, 所有loveable会被替换成lovers
s/是表示替换操作, \(love\)表示选中love字符串, \(love\)able/表示包含loveable的行
\(love\)able/\1表示love字符串标记为1, 来引用love字符串, 表示在替换过程中不变, rs/表示替换的目标字符串

2-2. 使用变量替换字符串
使用变量时, 要用双引号 sed "", 其他形式可以用单引号 ''
OLD="abcde"
STR="|"
NEW=$(echo $OLD | sed "s/bcd/$STR/g") # abcde -> a|e


3. 输出
3-1. 直接修改本文件
$ sed -i '/^$/d' filename

3-2. 导出到其他文件
$ sed '/^$/d' > filename

4. 插入行
$ sed '/key/i ###' filename <= 在行前插入
$ sed '/key/a ###' filename <= 在行后插入
$ sed '1,3 i###' filename <= 在第 1 3 行之间所有行前插入
$ sed '1,3 a###' filename <= 在第 1 3 行之间所有行后插入

5. 打印
$ sed -n "/AAA/,/BBB/p" filename <= 打印 AAA 到 BBB 之间所有行
$ sed -n "1,/BBB/p" filename <= 打印第 1 行到 BBB 之间所有行
$ sed -n "2,5p" filename <= 打印第 2 行到第 5 行之间所有行
$ sed "2q" filename <= 打印开头 2 行

================================================================================
X. sed 替换文本内容

X-1. shell 脚本
------------------------------------------------------
#!/bin/bash

REPLACE_TXT=${REPLACE_TXT:-replace_database.txt}
TMP_FILE=${TMP_FILE:-/tmp/replace_database.sh.tmp}

for x in $* ; do
  cat $x | sed -e '/########## DATABASE/,/##########/d
/^oracle_conn/d
/^pg_conn_/d' > $TMP_FILE
  cat $REPLACE_TXT $TMP_FILE > $x
done

rm -f $TMP_FILE
------------------------------------------------------

X-2. 被替换的原文件
$ cat file_1.txt
########## DATABASE
oracle_conn=jdbc:oracle:thin:username/psw@localhost:1521/XE
pg_conn_0=jdbc:postgresql://localhost:1234/db1?user=username&password=psw
pg_conn_1=jdbc:postgresql://localhost:5678/db2?user=username&password=psw
##########

X-3. 替换的内容
$ cat replace_database.txt
########## DATABASE
oracle_conn=jdbc:oracle:thin:username/psw@localhost:1521/XE
pg_conn_0=jdbc:postgresql://localhost:1111/db3?user=username&password=psw
pg_conn_1=jdbc:postgresql://localhost:2222/db4?user=username&password=psw
##########

X-4. 执行方法:
$ ./replace_database.sh file_*.txt
================================================================================