bash 字符串处理

[精华] bash 编程
http://www.chinaunix.net 作者:jiupima 发表于:2005-07-22 16:29:17

Bash 编程

一. Bash特殊字符

1. 通配符:
:匹配任何字符串
?:匹配任何单个字符*
集合运算符:用一些单个字、一个连续范围或断续的字符集合作为通配符
[set]:用字符集合作通配符匹配单个字符,如:[aeiou],[a-o],[a-h, w-z]
[!set]:除了集合外的所有字符组成的集合作通配符

2. 花括号展开式(可以嵌套):
格式:[前导字符串]{字符串1[{嵌套字符串1…}] [, 字符传2…]}[后继字符串]
**如:c{a{r, t, n}, b{r, t, n}}s 就等于 cars cats cans cbrs cbts cbns

3. 其它特殊字符:
( :子shell开始,子shell继承父shell部分环境变量
) :子shell结束
{ :命令块开始,由当前shell执行,保留所有环境变量
} :命令块结束
\ :引用后面的单个字符
‘ :强引用字符串,不解释特殊字符
“ :弱引用字符串,解释所有特殊字符
` :命令替换
; :命令分隔符(命令终止符),运行在一行里执行多条命令
# :行注释
$ :变量表达式
& :在后台执行命令

二. Bash变量

1. 自定义变量

用户自定义的变量由字母、数字和下划线组成,并且变量名的第一个字符不能为数字,且变量名大小写敏感。
varname=value 注意bash不能在等号两侧留空格
shell语言是非类型的解释型语言,给一个变量赋值实际上就是定义了变量,而且可以赋不同类型的值。引用变量有两种方式,$varname和${varname},为防止变量在字符串中产生歧义建议使用第二种方式,引用未定义的变量其值为空。
为一个变量赋值一个串,需要用到引号,注意`、’、”的不同,“相当于$()
为了使变量可以在其它进程中使用,需要将变量导出:export varname

2. 环境变量

可以用set命令给变量赋值或查看环境变量值,使用unset命令清除变量值,使用export导出变量将可以使其它进程访问到该环境变量。可以把设置保存到.bashrc中,成为永久的环境变量

3. 位置变量

位 置变量对应于命令行参数,其中$0为脚本名称,$1为第一个参数,依次类推,参数超过9个必须使用${}引用变量。shell保留这些变量,不允许用户以 另外的方式定义它们,传给脚本或函数的位置变量是局部和只读的,而其余变量为全局的(可以用local关键字声明为局部)。

4. 其它变量

$? :保存前一个命令的返回码
$- :在Shell启动或使用set命令时提供选项
$$ :当前shell的进程号
$! :上一个子进程的进程号
$# :传给脚本或函数的参数个数,即位置变量数减1,不含脚本名称
$* :传给脚本或函数的参数组成的单个字符串,即除脚本名称后从第一个参数开始的字符串,每个参数以$IFS分隔(一般内部域分隔符$IFS为1空格)。形同”…”
$@ :传给脚本或函数的参数列表,这些参数被表示为多个字符串。形同”” “” “”…。

$和$@之间的不同方便使用两种方法处理命令行参数,但是在打印时参数外观没有区别。
如: #vi posparm.sh
function cutparm
{echo –e “inside cntparm: $# parms: $
\n”}
cntparm “$*”
cntparm “$@”
#./posparm.sh abc bca cab
inside cntparm: 1 parms: abc bca cab
inside cntparm: 3 parms: abc bca cab

三. Bash操作符

1. 字符串操作符(替换操作符)

${var:-word} 如果var存在且不为空,返回它的值,否则返回word
${var:=word} 如果var存在且不为空,返回它的值,否则将word赋给var, 返回它的值
${var:+word} 如果var存在且不为空,返回word,否则返回空
${var:?message} 如果var存在且不为空,返回它的值,
否则显示“bash2:$var:$message”,然后退出当前命令或脚本
${var:offset[]} 从offset位置开始返回var的一个长为length的子串,
若没有length,则默认到var串末尾

2. 模式匹配操作符

${var#pattern} 从var头部开始,删除和pattern匹配的最短模式串,然后返回 剩余串
${var##pattern} 从var头部开始,删除和pattern匹配的最长模式串,然后返回 剩余串,basename path=${path##/}
${var%pattern} 从var尾部开始,删除和pattern匹配的最短模式串,然后返回 剩余串,dirname path=${path%/
}
${var%%pattern} 从var尾部开始,删除和pattern匹配的最长模式串,然后返回 剩余串
${var/pattern/string} 用string替换var中和pattern匹配的最长模式串

四. Shell中条件和test命令

Bash可以使用[ … ]结构或test命令测试复杂条件
格式:[ expression ] 或 test expression
返回一个代码,表明条件为真还是为假,返回0为真,否则为假。
注:左括号后和右括号前空格是必须的语法要求

1. 文件测试操作符

-d file file存在并且是一个目录
-e file file存在
-f file file存在并且是一个普通文件
-g file file存在并且是SGID(设置组ID)文件
-r file 对file有读权限
-s file file存在并且不为空
-u file file存在并且是SUID(设置用户ID)文件
-w file 对file有写权限
-x file 对file有执行权限,如果是目录则有查找权限
-O file 拥有file
-G file 测试是否是file所属组的一个成员
-L file file为符号链接
file1 –nt file2 file1比file2新
file1 –ot file2 file1比file2旧

2. 字符串操作符

str1=str2 str1和str2匹配
str1!=str2 str1和str2不匹配
str1>str2 str1大于str2
-n str str的长度大于0(不为空)
-z str str的长度为0(空串)

3. 整数操作符

var1 –eq var2 var1等于var2
var1 –ne var2 var1不等于var2
var1 –ge var2 var1大于等于var2
var1 –gt var2 var1大于var2
var1 –le var2 var1小于等于var2
var1 –lt var2 var1小于var2

4. 逻辑操作符

!expr 对expr求反
expr1 && expr2 对expr1与expr2求逻辑与,当expr1为假时不再执行expr2
expr1 || expr2 对expr1与expr2求逻辑或,当expr1为真时不再执行expr2
注:另一种逻辑操作符 逻辑与expr1 –a expr2 逻辑或expr1 –o expr2

五. Shell流控制

1. 条件语句:if

if 条件 IFS=:
then for dir in $PATH
语句 do
[elif 条件 if [ -O dir ]; then
语句] echo –e “\tYou own $dir”
[else else
语句] echo –e “\tYou don’t own $dir”
fi fi

2. 确定性循环:for done

for value in list for docfile in /etc/* /usr/etc/*
do do
statements using $value cp $docfile ${docfile%.doc}.txt
done done
注:for var;… 相当于for var in “$@”;…

3. 不确定性循环:while和until

while 条件 until 条件
do do
语句 语句
done done

count=1 count=1
while [ -n “$*” ] until [ -z “$*” ]
do do
echo “parameter $count” echo “parameter $count”
shift shift
count=’expr $count + 1′ count=’expr $count + 1′
done done
条件为真执行循环体 条件为假执行循环体
注:整数变量的定义与算法
declare –i idx 定义整数变量 使用$(())无需定义
idx=1
while [ $idx!=150 ]
do
cp somefile somefile.$idx
idx=$idx+1 整数算法 idx=$(( $idx+1 ))
done
另一种算法 echo $(( 100/3 )) 将加减乘除表达式放入$(())中

4. 选择结构:case和select

case 表达式 in 表达式和模式依次比较,执行第一个匹配的模式
模式1) ;;使程序控制流跳到esac后执行,相当于break
语句;; 允许表达式和含有通配符的模式进行匹配
模式2)
语句;;
……
[*)
语句]
esac

select value [ in list ] 按list列表自动生成菜单
do 若没有list则默认为位置变量
statements using $value
done
如:IFS=: 设置域分隔符为:号
PS3=”choice>;” 改变select默认提示符
clear
select dir in $PATH
do
if [ $dir ]; then
cnt=$(ls –Al $dir | wc -l)
echo “$cnt files in $dir”
else
echo “No such choice !”
fi
echo –e “\npress ENTER to continue, CTRL-C to quit”
read 使程序按回车继续,ctrl+c退出
clear
done

5. 命令shift

将存放在位置变量中的命令行参数依次向左传递
shift n 命令行参数向左传递n个串

六. Shell函数

定义: function fname fname ()
{ {
commands commands
} }
调用:fname [ parm1 parm2 parm3 … ]
说明: 函数在使用前定义,两种定义功能相同
函数名和调用函数参数成为函数的位置变量
函数中的变量应该使用local声明为局部变量

七. 输入输出

限于篇幅,这里不讨论所有输入输出操作符和功能
1.I/O重定向
< :输入重定向 >; :输出重定向(没有文件则创建,有则覆盖)

;>; :输出重定向(没有则创建,有则追加到文件尾部)
« :输入重定向(here文档)
格式: command « label
input…
label
说明: 使一个命令的输入为一段shell脚本(input…),直到标号(label)结束
如: cat < $HOME/.profile >; out
echo “add to file end !” >;>; $HOME/.profile
ftp:USER=anonymous
PASS=YC@163.com
ftp –i –n « END -i:非交互模式 -n:关闭自动登录
open ftp.163.com
user $USER $PASS
cd /pub
close
END

END标记输入结束
2.字符串I/O操作
字符串输出:echo
命令选项: -e:启动转义序列 -n:取消输出后换行
转义序列:

\a:Alt/Ctrl+G(bell)

\b:退格Backspace/Ctrl+H

\c:取消输出后换行

\f:Formfeed/Ctrl+J

\r:Return/Ctrl+M

\v:Vertical tab

\n:八进制ASCII字符

\:单个\字符

\t:Tab制表符
字符串输入:read
可以用于用户交互输入,也可以用来一次处理文本文件中的一行

命令选项:

-a:将值读入数组,数组下标从0开始
-e:使用GNU的readline库进行读入,允许bash的编辑功能
-p:在执行读入前打印提示
如: IFS=:
read –p “start read from file . filename is : \c” filename
while read name pass uid gid gecos home shell < filename do echo –e “name : $name\npass : $pass\n” done 说明:如果行的域数大于变量表的变量数,则后面的域全部追加给最后的变量

八. 命令行处理 命令行处理命令:

getopts 有两个参数,第一个为字母和冒号组成的选项列表字符串,第二个为一个变量名

选项列表字符串以冒号开头的选项字母排列组成,如果一选项需要一个参数则该选项字母后跟一个冒号

getopts分解第一参数,依次将选项摘取出来赋给第二个参数变量

如果某选项有参数,则读取参数到内置变量OPTARG中 内置变量OPTIND保存着将被处理的命令行参数(位置参数)的数值 选项列表处理完毕getopts返回1,否则返回0 如:

while getopts “:xy:z:” opt do case $opt in x) xopt=’-x set’ ;; y) yopt=”-y set and called with $OPTARG” ;; z) zopt=”-z set and called with $OPTARG” ;; \?) echo ‘USAGE: getopts.sh [-x] [-y arg] [-z arg] file…’ exit 1 esac done shift ($OPTING-1) 将处理过的命令行参数移去 echo ${xopt: -‘did not use –x‘} echo ${yopt: -‘did not use –y‘} echo ${zopt: -‘did not use –z‘} echo “Remaining command-line arguments are :” for f in “$@” do echo –e “\t$f\n” done

九. 进程和作业控制

信号处理命令:trap 格式:trap command sig1 sig2 … trap可以识别30多种信号,如中断(Ctrl+c)、挂起(Ctrl+z)等,

可以使用kill -l查看信号清单 当脚本接受到信号sig1、sig2等,

trap就执行命令command,command完成后脚本重新执行 信号可以通过名称或数字来标识

作业控制命令:bg、fg

bg:显示后台进程,即用Ctrl+z挂起或‘命令 &’执行的进程

fg:将后台进程转到前台执行

kill –9 %n:杀掉第n个后台进程

附录:

一. Bash支持的命令行参数

-a 将所有变量输出

-c “string”从string中读取命令

-e 使用非交互式模式

-f 禁止shell文件名产生

-h 定义

-i 交互式模式

-k 为命令的执行设置选项

-n 读取命令但不执行

-r 受限模式

-s 命令从标准输入读取

-t 执行一命令,然后退出shell

-u 在替换时,使用未设置的变量将会出错

-v 显示shell的输入行

-x 跟踪模式,显示执行的命令 许多模式可以组合起来用,使用set可以设置或取消shell的选项来改变shell环境。

打开选项用”-”,关闭选项用”+”,

若显示Shell中已经设置的选项,执行: $echo $-

二. .profile中shell的环境变量意思如下:

CDPATH 执行cd命令时使用的搜索路径

HOME 用户的home目录

IFS 内部的域分割符,一般为空格符、制表符、或换行符

MAIL 指定特定文件(信箱)的路径,有UNIX邮件系统使用 PATH 寻找命令的搜索路径(同dos的config.sys的 path)

PS1 主命令提示符,默认是”$” PS2 从命令提示符,默认是”>;”
TERM 使用终端类型
================================================================================
from: http://unix-cd.com/unixcd12/article_view.asp?id=4440

字符串长度

%x=”abcd”
** #方法一**
** %expr length $x**
** 4**
** # 方法二**
** %echo ${#x}**
** 4**
** # 方法三**
** %expr “$x” : “.*”**
4
# expr 的帮助
# STRING : REGEXP anchored pattern match of REGEXP in STRING

查找子串

%expr index $x “b”
2
%expr index $x “a”
1
%expr index $x “b”
2
%expr index $x “c”
3
%expr index $x “d”
4
得到子字符串

# 方法一
# expr startpos length
%expr substr “$x” 1 3
abc
%expr substr “$x” 1 5
abcd
%expr substr “$x” 2 5
bcd
# 方法二
# ${x:pos:lenght}
%echo ${x:1}
bcd
%echo ${x:2}
cd
%echo ${x:0}

abcd
%echo ${x:0:2}
ab
%pos=1
%len=2
%echo ${x:$pos:$len}
bc
匹配正则表达式

# 打印匹配长度
%expr match $x “.”
1
%expr match $x “abc”
3
%expr match $x “bc”
0

字符串的掐头去尾

%x=aabbaarealwwvvww
%echo “${x%ww}”
aabbaarealwwvv
%echo “${x%%w
w}”
aabbaareal
%echo “${x##aa}”
lwwvvww
%echo “${x#a
a}”
bbaarealwwvvww
其中 , # 表示掐头, 因为键盘上 # 在 $ 的左面。
其中 , % 表示%, 因为键盘上 % 在 $ 的右面。
单个的表示最小匹配,双个表示最大匹配。
也就是说,当匹配的有多种方案的时候,选择匹配的最大长度还是最小长度。

字符串的替换

%x=abcdabcd
%echo ${x/a/b} # 只替换一个
bbcdabcd
%echo ${x//a/b} # 替换所有

bbcdbbcd

不可以使用 regexp , 只能用 * ? 的文件扩展方式。

——————————————————————————-

</p>

Bash String Processing

</center>

Introduction

Over the years, the bash shell has acquired lots of new bells and whistles. Some of these are very useful in shell scripts; but they don’t seem well known. This page mostly discusses the newer ones, especially those that modify strings. In some cases, they provide useful alternatives to such old standbys as tr and sed, with gains in speed. The general theme is avoiding pipelines.

In the examples below, I’ll assume that string is a shell variable that contains some character string. It might be as short as a single character, or it might be the contents of a whole document.

Case Conversions

One of the obscure enhancements that can be discovered by reading the man page for bashis the case-conversion pair:

	newstring=${string^^}	# the string, converted to UPPER CASE
	newstring=${string,,}	# the string, converted to lower case

(You can also convert just the first letter by using a single ^ or , .) Notice that the original variable, string, is not changed.

Normally, we think of doing this by using the tr command:

	newstring=`echo "$string" | tr '[a-z]' '[A-Z]'`
	newstring=`echo "$string" | tr '[A-Z]' '[a-z]'`

Of course, that involves spawning a new process. Actually, as the man page for trtells you, this isn’t optimal; depending on your locale setting, you might get unexpected results. It’s safer to say

	newstring=`echo "$string" | tr '[:lower:]' '[:upper:]'`
	newstring=`echo "$string" | tr '[:upper:]' '[:lower:]'`

Using tris certainly more readable; but it also takes a lot longer to type. How about execution time?

Timing tests

Here’s a code snippet that does nothing, a hundred thousand times:

	str1=X

	i=0
	time (
	while [ $i -lt 100000 ]
	do
		let i++
	done
	)

On my machine — currently, a 3 GHz (6000 bogomips) dual-core Pentium box — that takes about 1.57 seconds. That’s the bashoverhead for running the useless loop. Nearly all of that is “user” time; the “sys” time is only a few dozen milliseconds.

Now let’s add the line

	str2=${str1^^}

to the loop, just after the letstatement. The execution time jumps to about 2.3 seconds; so executing the added line 100,000 times took about 0.7 second. That’s about 7 microseconds per execution.

Now, let’s try putting the line

	str2=`echo "$str1" | tr '[:lower:]' '[:upper:]'`

inside the loop instead. The execution time is now a whopping 1m 33s of real time — but only 3 seconds of user and 7 sec of system time! Apparently, the system gives both bash and tra thousand one-millisecond time-slices a second, and then takes a vacation until the next round millisecond comes up.

If we try to even things up a bit by making the initial string longer, we find practically the same times for the version using tr, but about 0.2 second longer than before for the all-shell version, if the string to convert is "Hello, world!". Clearly, we need a really big string to measure bash‘s speed accurately.

So let’s initialize the original string with the line

	str1=`cat /usr/share/dict/american-english`

which is a text file of 931708 characters. For this big file, a single cycle through the loop is enough: it takes bash about 45.7 seconds, all but a few milliseconds of which is “user” time. On the other hand, the trversion takes only 0.24 seconds to process the big text file.

Clearly, there’s a trade-off here that depends on the size of the string to be converted. Evidently, the context switch required to invoke tr is the bottleneck when the string is short; but tr is so much more efficient than bash in converting big strings that it’s faster when the string exceeds a few thousand characters. I find my machine takes about 1.55 milliseconds to process a string about 4100 characters long, regardless of which method is used. (About a quarter of a millisecond is used by the system when tr is invoked; presumably, that’s the time required to set up the pipeline and make the context switch.)

sed-like Substitutions

Likewise, you can often make bash act enough like sedto avoid using a pipeline. The syntax is

	newstring=${oldstring/pattern/replacement}

Notice that there is no trailing slash, as in sed or vi: the closing brace terminates the substitution string.

The catch is that only shell-type patterns (like those used in pathname expansion) can be used, not the elaborate regular expressions recognized by sed. Also, only a single replacement normally occurs; but you can simulate a “global” replacement by using two slashes before the pattern:

	newstring=${oldstring//pattern/replacement}

A handy use for this trick is in sanitizing user input. For example, you might want to convert a filename into a form that’s safe to use as (part of) a shell-variable name: filenames can contain hyphens and other special characters that are not allowed in variable names, which can only be alphanumeric. So, to clean up a dirty string:

	clean=${dirty//[-+=.,]/_}

If we had set dirty='a,b.c=d-e+f', the line above converts the dangerous characters to underscores, forming the clean string: a_b_c_d_e_f, which can be used safely in a shell script.

And you can omit the replacement string, thereby deleting the offensive parts entirely. So, for example,

	cleaned=${dirty//[-+=.,]}

is equivalent to

	cleaned=`echo $dirty | sed -e 's/[-+=.,]//g'`

or

	cleaned=`echo $dirty | tr -d '+=.,-'`

where we have to put the hyphen last so trwon’t think it’s an option.

Be careful: sed and tr allow the use of ranges like 'A-Z' and '0-9' ; but bash requires you to either enumerate these, or to use character classes like [:upper:] or [:digit:] within the brackets that define the pattern list.

You can even force the pattern to appear at the beginning or the end of the string being edited, by prefixing pattern with # (for the start) or % (for the end).

Faking basename and dirname

This use of # to mark the beginning of an edited string, and % for the end, can also be used to simulate the basename and dirnamecommands in shell scripts:

	dirpath=${path%/*}

extracts the part of the path variable beforethe last slash; and

	base=${path##*/}

yields the part after the last slash. CAUTION: Notice that the asterisk goes between the slash and the ##, but after the %.

That’s because

	${varname#pattern}

trims the shortest prefix from the contents of the shell variable varname that matches the shell-pattern pattern ; and

	${varname##pattern}

trims the longest prefixthat matches the pattern from the contents of the shell variable. Likewise,

	${varname%pattern}

trims the shortest suffix from the contents of the shell variable varname that matches the shell-pattern pattern ; and

	${varname%%pattern}

trims the longest suffix that matches the pattern from the contents of the shell variable. You can see that the general rule here is: a single # or % to match the shortest part; or a double ## or %% to match the longestpart.

But be careful. If you just feed a bare filename instead of a pathname to dirname, you get just a dot [.]; but if there are no slashes in the variable you process with the hack above, you get the filename back, unaltered: because there were no slashes in it, nothing got removed. So this trick isn’t a complete replacement for dirname.

Another use of basename is to remove a suffix from a filename. We often need to do this in shell scripts when we want to generate an output file with the same basename but a different extension from an input file. For example, to convert file.old to file.new, you could use

	newname=`basename $oldname .old`.new

so that, if you had set oldname to file.old , newname would be set to file.new . But it’s faster to say

	newname=${oldname%.old}.new

(Notice that we have to use the % operation here, even though the generic replacement for basename given above uses the ##operation. That’s because we’re trimming off a suffix rather than a prefix, in this case.) If you didn’t know the old file extension, you could still replace it by saying

	newname=${oldname%.*}.new

This way of trimming off a prefix or a suffix is also useful for separating numbers that contain a decimal point into the integer and fractional parts. For example, if we set DECIMAL=123.4567, we can get the part before the decimal as

	INTEGER=${DECIMAL%.*}

and the digits of the fraction as

	FRACT=${DECIMAL#*.}

Numerical operations

Speaking of digits, you can also perform simple integer arithmetic in bash without having to invoke another process, such as expr. Remember that the letoperation automatically invokes arithmetic evaluation on its operands. So

	let sum=5+2

will store 7 in sum. Of course, the operands on the right side can just as well be shell variables; so, if x and yare numerical, you could

	let sum=x+y

which is both more compact and faster than

	sum=`expr $x + $y`

If you want to space the expression out for better readability, you can say

	let "sum = x + y"

and bash will do the right thing. (You have to use quotes so that lethas just a single argument. If you don’t like the quotes, you can say

	sum=$(( x + y ))

but then you can’t have spaces around the =sign.)

This way of doing arithmetic is a lot more readable than using expr — especially when you’re doing multiplications, because expr has to have its arguments separated by whitespace, so the asterisk [*] has to be quoted:

	product=`expr $x \* $y`

Yuck. Pretty ugly, compared to

	let "product = x * y"

Finally, when you need to increment a counter, you can say

	let i++

or

	let j+=2

which is cleaner, faster, and more readable than invoking expr.

Sub-strings

In addition to truncating prefixes and suffixes, bashcan extract sub-strings. To get the 2 characters that follow the first 5 in a string, you can say

	${string:5:2}

for example.

This can save a lot of work when parsing replies to shell-script questions. If the shell script asks a yes/no question, you only need to check the first letter of the reply. Then

	init=${string:0:1}

is what you want to test. (This gives you 1 character, starting at position 0 — in other words, the first character of the string.)

If the “offset” parameter is −1, the substring begins at the last character of the string; so

	last=${string: −1:1}

gives you just the last character. (Note the space that’s needed to separate the colon from the minus sign; this is required to avoid confusion with the colon-minus sequence used in specifying a default value.)

To get the last 2 characters, you should specify

	last2=${string: −2:2} ;

note that

	penult=${string: −2:1}

gives you the next-to-last character.

Replacing wc

Many invocations of wc can be avoided, especially when the object to be measured is small. Of course, you should avoid operating on a file directly with wcin constructions like

	size=`wc -c somefile`

because this captures the user-friendly repetition of the filename in the output. Instead, you want to re-direct the input to wc:

	size=`wc -c < somefile`

But if the operand is already in a shell variable, you certainly don’t want to do this:

	size=`echo -n "$string" | wc -c`

— particularly if the string is short — because bashcan do the job itself:

	size=${#string}

It’s even possible to make bash fake wc -w, if you don’t mind sacrificing the positional parameters:

	set $string
	nwords=$#
http://mintaka.sdsu.edu/GF/bibliog/latex/debian/bash.html
CHENTONG
版权声明:本文为博主原创文章,转载请注明出处。
alipay.png WeChatPay.png

CHENTONG

CHENTONG
积微,月不胜日,时不胜月,岁不胜时。凡人好敖慢小事,大事至,然后兴之务之。如是,则常不胜夫敦比于小事者矣!何也?小事之至也数,其悬日也博,其为积也大。大事之至也希,其悬日也浅,其为积也小。故善日者王,善时者霸,补漏者危,大荒者亡!故,王者敬日,霸者敬时,仅存之国危而后戚之。亡国至亡而后知亡,至死而后知死,亡国之祸败,不可胜悔也。霸者之善著也,可以时托也。王者之功名,不可胜日志也。财物货宝以大为重,政教功名者反是,能积微者速成。诗曰:德如毛,民鲜能克举之。此之谓也。

生信宝典文章集锦

### 程序学习心得* [生物信息之程序学习](http://mp.weixin.qq.com/s?__biz=MzI5MTcwNjA4NQ==&mid=2247483927&idx=1&sn=23adf2b9d13400f2081f790e674e...… Continue reading

R统计绘图 - 柱状图

Published on August 12, 2017

R 学习 - 维恩图

Published on August 01, 2017