随笔-284  评论-198  文章-0  trackbacks-0
  2016年9月18日

所谓BOM,全称是Byte Order Mark,它是一个Unicode字符,通常出现在文本的开头,用来标识字节序(Big/Little Endian),除此以外还可以标识编码(UTF-8/16/32),如果出现在文本中间,则解释为zero width no-break space。 注:Unicode相关知识的详细介绍请参考UTF-8, UTF-16, UTF-32 & BOM

对于UTF-8/16/32而言,它们名字中的8/16/32指的是编码单位是多少位的,也就是说,它们的编码单位分别是8/16/32位,换算成字节就
是1/2/4字节,如果是多字节,就要牵扯到字节序,UTF-8以单字节为编码单位,所以不存在字节序。
UTF-8主要的优点是可以兼容ASCII,但如果使用BOM的话,这个好处就荡然无存了,除此以外,BOM的存在还可能引发一些问题,比如下面错误便都
有可能是BOM导致的:



  • Shell: No such file or directory
  • PHP: Warning: Cannot modify header information – headers already sent

在详细讨论UTF-8编码中BOM的检测与删除问题前,不妨先通过一个例子热热身:


shell> curl -s http://phone.10086.cn/ | head -1 | sed -n l
\357\273\277<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional\
//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\r$

如上所示,前三个字节分别是357、273、277,这就是八进制的BOM。


shell> curl -s http://phone.10086.cn/ | head -1 | hexdump -C
00000000 ef bb bf 3c 21 44 4f 43 54 59 50 45 20 68 74 6d |...<!DOCTYPE htm|
00000010 6c 20 50 55 42 4c 49 43 20 22 2d 2f 2f 57 33 43 |l PUBLIC "-//W3C|
00000020 2f 2f 44 54 44 20 58 48 54 4d 4c 20 31 2e 30 20 |//DTD XHTML 1.0 |
00000030 54 72 61 6e 73 69 74 69 6f 6e 61 6c 2f 2f 45 4e |Transitional//EN|
00000040 22 20 22 68 74 74 70 3a 2f 2f 77 77 77 2e 77 33 |" "http://www.w3|
00000050 2e 6f 72 67 2f 54 52 2f 78 68 74 6d 6c 31 2f 44 |.org/TR/xhtml1/D|
00000060 54 44 2f 78 68 74 6d 6c 31 2d 74 72 61 6e 73 69 |TD/xhtml1-transi|
00000070 74 69 6f 6e 61 6c 2e 64 74 64 22 3e 0d 0a |tional.dtd">..|

如上所示,前三个字节分别是EF、BB、BF,这就是十六进制的BOM。 注:用到了第三方网站的页面,不能保证例子始终可用。
实际做项目开发时,可能会面对成百上千个文本文件,如果有几个文件混入了BOM,那么很难察觉,如果没有带BOM的UTF-8文本文件,可以用vi杜撰几
个,相关命令如下:


设置UTF-8编码:


:set fileencoding=utf-8

添加BOM:


:set bomb

删除BOM:


:set nobomb

查询BOM:


:set bomb?

如何检测UTF-8编码中的BOM呢?


shell> grep -r -I -l $'^\xEF\xBB\xBF' /path

如何删除UTF-8编码中的BOM呢?


shell> grep -r -I -l $'^\xEF\xBB\xBF' /path | xargs sed -i 's/^\xEF\xBB\xBF//;q'

推荐:如果你使用SVN的话,可以在pre-commit钩子里加上相关代码用以杜绝BOM。


#!/bin/bash

REPOS="$1"
TXN="$2"

SVNLOOK=/usr/bin/svnlook

for FILE in $($SVNLOOK changed -t "$TXN" "$REPOS" | awk '/^[AU]/ {print $NF}'); do
if $SVNLOOK cat -t "$TXN" "$REPOS" "$FILE" | grep -q $'^\xEF\xBB\xBF'; then
echo "Byte Order Mark be found in $FILE" 1>&2
exit 1
fi
done

本文用到了很多shell命令,篇幅所限,恕不详述,如果有不明白的就请自己搜索吧。

posted @ 2016-09-18 09:38 xzc 阅读(84) | 评论 (0)编辑 收藏

当我们需要把二进制转成c语言中使用的16进制字符数组时,命令xxd是很有用的。

xxd 帮助信息如下:关键选项标黑。

[root@localhost ]# xxd --help
Usage:
       xxd [options] [infile [outfile]]
    or
       xxd -r [-s [-]offset] [-c cols] [-ps] [infile [outfile]]
Options:
    -a          toggle autoskip: A single '*' replaces nul-lines. Default off.
    -b          binary digit dump (incompatible with -p,-i,-r). Default hex.
    -c cols     format <cols> octets per line. Default 16 (-i: 12, -ps: 30).
    -E          show characters in EBCDIC. Default ASCII.
    -g          number of octets per group in normal output. Default 2. 每个goup的字节数,默认为2,可设置。
    -h          print this summary.
    -i          output in C include file style. :输出为c包含文件的风格,数组方式存在。
    -l len      stop after <len> octets.        :转换到len个字节后停止转换。
    -ps         output in postscript plain hexdump style.
    -r          reverse operation: convert (or patch) hexdump into binary.
    -r -s off   revert with <off> added to file positions found in hexdump.
    -s [+][-]seek start at <seek> bytes abs. (or +: rel.) infile offset.
   -u          use upper case hex letters. : 字节大写方式
    -v          show version: "xxd V1.10 27oct98 by Juergen Weigert".

比如运行:

> xxd -g 1 -i -u -l 10000000 nm.ts > xxd_test.txt

生成的文本显示:

unsigned char __0513_1634_ch32_666_10_ts[] = {
0X47, 0X02, 0X03, 0X13, 0XF8, 0X5A, 0XC5, 0X40, 0X26, 0XE4, 0XD0, 0XDE,
0XAD, 0XB8, 0X76, 0X89, 0X85, 0X23, 0X06, 0X04, 0X6E, 0X05, 0X8B, 0X09,
0XC0, 0X5C, 0X96, 0X4F, 0X18, 0X51, 0X41, 0XC8, 0X40, 0X9F, 0X06, 0X93,
0X38, 0XC1, 0XBB, 0X1A, 0XBC, 0XAC, 0X47, 0XFF, 0X5E, 0X54, 0XEB, 0XA7,
0X14, 0X36, 0X85, 0X8A, 0X90, 0X14, 0X17, 0XA2, 0X9D, 0XC0, 0X84, 0X56,
0XCB, 0X97, 0X78, 0XC8, 0X57, 0X15, 0X3E, 0X61, 0X6F, 0XFE, 0XC9, 0X39,
0XEF, 0XD3, 0XB6, 0X6A, 0XD2, 0XE4, 0XFB, 0X4C, 0X05, 0XF6, 0X03, 0XED,
0X50, 0XB3, 0XE7, 0X46, 0X57, 0X24, 0X71, 0X16, 0X38, 0X45, 0X53, 0X19,
0X56, 0X25, 0X3C, 0X8D, 0X4C, 0XA9, 0X28, 0X9A, 0XB2, 0X99, 0X76, 0X52,
0X28, 0XE9, 0XD6, 0XD6, 0X11, 0X94, 0X89, 0X19, 0X4D, 0XEA, 0X68, 0X76,
0X53, 0XC6, 0XAA, 0X3A, 0XD4, 0XA1, 0X25, 0XA5, 0X03, 0XB0, 0X73, 0XA0,
0XAE, 0X11, 0XC9, 0XBD, 0X37, 0X17, 0X11, 0X5F, 0X30, 0X34, 0X34, 0X0B

.....

};

unsigned int nm.ts_len = 10000000;

另外,在vim中也可以把文件转换为16进制来显示:

:%!xxd

返回正常显示:

:%!xxd -r

 

linux下查看二进制文件
以十六进制格式输出:
od [选项] 文件
od -d 文件  十进制输出
   -o 文件  八进制输出
   -x 文件  十六进制输出
xxd 文件  输出十六进制

在vi命令状态下:
:%!xxd   :%!od    将当前文本转化为16进制格式
:%!xxd -c 12 每行显示12个字节
:%!xxd -r    将当前文本转化回文本格式

posted @ 2016-09-18 09:38 xzc 阅读(114) | 评论 (0)编辑 收藏
  2016年4月1日

一、IFS 介绍

     Shell 脚本中有个变量叫 IFS(Internal Field Seprator) ,内部域分隔符。完整定义是The shell uses the value stored in IFS, which is the space, tab, and newline characters by default, to delimit words for the read and set commands, when parsing output from command substitution, and when performing variable substitution.

     Shell 的环境变量分为 set, env 两种,其中 set 变量可以通过 export 工具导入到 env 变量中。其中,set 是显示设置shell变量,仅在本 shell 中有效;env 是显示设置用户环境变量 ,仅在当前会话中有效。换句话说,set 变量里包含了 env 变量,但 set 变量不一定都是 env 变量。这两种变量不同之处在于变量的作用域不同。显然,env 变量的作用域要大些,它可以在 subshell 中使用。

     而 IFS 是一种 set 变量,当 shell 处理"命令替换"和"参数替换"时,shell 根据 IFS 的值,默认是 space, tab, newline 来拆解读入的变量,然后对特殊字符进行处理,最后重新组合赋值给该变量。

二、IFS 简单实例

1、查看变量 IFS 的值。

  1. $ echo $IFS  
  2.   
  3. $ echo "$IFS" | od -b  
  4. 0000000 040 011 012 012  
  5. 0000004  
$ echo $IFS  $ echo "$IFS" | od -b 0000000 040 011 012 012 0000004

直接输出IFS是看不到的,把它转化为二进制就可以看到了,"040"是空格,"011"是Tab,"012"是换行符"\n" 。最后一个 012 是因为 echo 默认是会换行的。

2、$* 和 $@ 的细微差别
     从下面的例子中可以看出,如果是用冒号引起来,表示这个变量不用IFS替换!!所以可以看到这个变量的"原始值"。反之,如果不加引号,输出时会根据IFS的值来分割后合并输出! $* 是按照IFS中的第一个值来确定的!下面这两个例子还有细微的差别!

  1. $ IFS=:;  
  2. $ set x y z  
  3. $ echo $*  
  4. x y z  
  5. $ echo "$*"  
  6. x:y:z  
  7. $ echo $@  
  8. x y z  
  9. $ echo "$@"  
  10. x y z  
$ IFS=:; $ set x y z $ echo $* x y z $ echo "$*" x:y:z $ echo $@ x y z $ echo "$@" x y z
 上例 set 变量其实是3个参数,而下面这个例子实质是2个参数,即 set "x y z"  和 set x y z 是完全不同的。
  1. $ set "x" "y z"  
  2. $ echo $*  
  3. x y z  
  4. $ echo "$*"  
  5. x:y z  
  6. $ echo $@  
  7. x y z  
  8. $ echo "$@"  
  9. x y z  
  10. $ echo $* |od -b  
  11. 0000000 170 040 171 040 172 012  
  12. 0000006  
  13. $ echo "$*" |od -b  
  14. 0000000 170 072 171 040 172 012  
  15. 0000006  
$ set "x" "y z" $ echo $* x y z $ echo "$*" x:y z $ echo $@ x y z $ echo "$@" x y z $ echo $* |od -b 0000000 170 040 171 040 172 012 0000006 $ echo "$*" |od -b 0000000 170 072 171 040 172 012 0000006

小结:$* 会根据 IFS 的不同来组合值,而 $@ 则会将值用" "来组合值!

3、for 循环中的奇怪现象

  1. $ for x in $var ;do echo $x |od -b ;done  
  2. 0000000 012  
  3. 0000001  
  4. 0000000 040 141 012  
  5. 0000003  
  6. 0000000 142 012  
  7. 0000002  
  8. 0000000 012  
  9. 0000001  
  10. 0000000 143 012  
  11. 0000002  
$ for x in $var ;do echo $x |od -b ;done 0000000 012 0000001 0000000 040 141 012 0000003 0000000 142 012 0000002 0000000 012 0000001 0000000 143 012 0000002

 

先暂且不解释 for 循环的内容!看下面这个输出!IFS 的值同上! var=": a:b::c:"
  1. $ echo $var |od -b  
  2. 0000000 040 040 141 040 142 040 040 143 012  
  3. 0000011  
  4. $ echo "$var" |od -b  
  5. 0000000 072 040 141 072 142 072 072 143 072 012  
  6. 0000012  
$ echo $var |od -b 0000000 040 040 141 040 142 040 040 143 012 0000011 $ echo "$var" |od -b 0000000 072 040 141 072 142 072 072 143 072 012 0000012

"$var"的值应该没做替换,所以还是 ": a:b::c:" (注 "072" 表示冒号),但是$var 则发生了变化!注意输出的最后一个冒号没有了,也没有替换为空格!Why?

 

使用 $var 时是经历了这样一个过程!首先,按照这样的规则 [变量][IFS][变量][IFS]……根据原始 var 值中所有的分割符(此处是":")划分出变量,如果IFS的值是有多个字符组成,如IFS=":;",那么此处的[IFS]指的是IFS中的任意一个字符($* 是按第一个字符来分隔!),如 ":" 或者 ";" ,后面不再对[IFS]做类似说明!(注:[IFS]会有多个值,多亏 #blackold 的提醒);然后,得到类似这样的 list, ""   " a"   "b"  ""   "c"  。如果此时 echo $var,则需要在这些变量之间用空格隔开,也就是""  [space]   "  a"  [space]  "b" [space]  "" [space]  "c" ,忽略掉空值最终输出是 [space][space]a[space]b[space][space]c

如果最后一个字符不是分隔符,如 var="a:b",那么最后一个分隔符后的变量就是最后一个变量!

这个地方要注意下!!如果IFS就是空格,那么类似于" [space][space]a[space]b[space][space]c "会合并重复的部分,且去头空格,去尾空格,那么最终输出会变成类似 a[space]b[space]c ,所以,如果IFS是默认值,那么处理的结果就很好算出来,直接合并、忽略多余空格即可!

另外,$* 和 $@ 在函数中的处理过程是这样的(只考虑"原始值"!)!"$@",就是像上面处理后赋值,但是 "$*" 却不一样!它的值是用分隔符(如":")而不是空格隔开!具体例子见最后一个例子!

好了,现在来解释 for 循环的内容。for 循环遍历上面这个列表就可以了,所以 for 循环的第一个输出是空!("012"是echo输出的换行符 )。。。。后面的依次类推!不信可以试试下面这个例子,结果是一样的!

  1. $ for x in "" " a" "b" "" "c" ;do echo $x |od -b ;done  
  2. 0000000 012  
  3. 0000001  
  4. 0000000 040 141 012  
  5. 0000003  
  6. 0000000 012  
  7. 0000001  
  8. 0000000 142 012  
  9. 0000002  
  10. 0000000 012  
  11. 0000001  
  12. 0000000 143 012  
  13. 0000002  
$ for x in "" " a" "b" "" "c" ;do echo $x |od -b ;done 0000000 012 0000001 0000000 040 141 012 0000003 0000000 012 0000001 0000000 142 012 0000002 0000000 012 0000001 0000000 143 012 0000002

三、IFS的其他实例

Example 1:

 

  1. $ IFS=:  
  2. $ var=ab::cd  
  3. $ echo $var  
  4. ab  cd  
  5. $ echo "$var"  
  6. ab::cd  
$ IFS=: $ var=ab::cd $ echo $var ab  cd $ echo "$var" ab::cd
解释下:x 的值是 "ab::cd",当进行到 echo $x 时,因为$符,所以会进行变量替换。Shell 根据 IFS 的值将 x 分解为 ab "" cd,然后echo,插入空隔,ab[space]""[space]cd,忽略"",输出  ab  cd 。

Example 2 :

  1. $ read a  
  2.        xy  z  
  3. $ echo $a  
  4. xy  z  
$ read a        xy  z $ echo $a xy  z

解释:这是 http://bbs.chinaunix.net/thread-207178-1-1.html 上的一个例子。此时IFS是默认值,本希望把所有的输入(包括空格)都放入变量a中,但是输出的a却把前面的空格给忽略了!!原因是:默认的 IFS 会按 space tab newline 来分割。这里需要注意的一点是,read 命令的实现过程,即在读入时已经替换了。解决办法是在开头加上一句 IFS=";" ,这里必须加上双引号,因为分号有特殊含义。

Example 3 :

  1. $ tmp="   xy z"  
  2. $ a=$tmp  
  3. $ echo $a  
  4. $ echo "$a"  
$ tmp="   xy z" $ a=$tmp $ echo $a $ echo "$a"

解释:什么时候会根据 IFS 来"处理"呢?我觉得是,对于不加引号的变量,使用时都会参考IFS,但是要注意其原始值!

Example 4 :

  1. #!/bin/bash  
  2. IFS_old=$IFS      #将原IFS值保存,以便用完后恢复  
  3. IFS=$’\n’        #更改IFS值为$’\n’ ,注意,以回车做为分隔符,IFS必须为:$’\n’  
  4. for i in $((cat pwd.txt)) #pwd.txt 来自这个命令:cat /etc/passwd >pwd.txt  
  5. do  
  6.     echo $i  
  7. done  
  8. IFS=$IFS_old      #恢复原IFS值  
#!/bin/bash IFS_old=$IFS      #将原IFS值保存,以便用完后恢复 IFS=$’\n’        #更改IFS值为$’\n’ ,注意,以回车做为分隔符,IFS必须为:$’\n’ for i in $((cat pwd.txt)) #pwd.txt 来自这个命令:cat /etc/passwd >pwd.txt do     echo $i done IFS=$IFS_old      #恢复原IFS值
另外一个例子,把IP地址逆转输出:

Example 5 :

  1. #!/bin/bash  
  2.   
  3. IP=220.112.253.111  
  4. IFS="."  
  5. TMPIP=$(echo $IP)  
  6. IFS=" " # space  
  7. echo $TMPIP  
  8. for x in $TMPIP ;do   
  9.     Xip="${x}.$Xip"  
  10. done  
  11. echo ${Xip%.}  
#!/bin/bash  IP=220.112.253.111 IFS="." TMPIP=$(echo $IP) IFS=" " # space echo $TMPIP for x in $TMPIP ;do      Xip="${x}.$Xip" done echo ${Xip%.}

Complex_Example 1:  http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=3660898&page=1#pid21798049

  1. function output_args_ifs(){  
  2.     echo "=$*"  
  3.     echo "="$*  
  4.     for m in $* ;do   
  5.         echo "[$m]"  
  6.     done  
  7. }  
  8.   
  9. IFS=':'  
  10. var='::a:b::c:::'  
  11. output_args_ifs $var  
function output_args_ifs(){     echo "=$*"     echo "="$*     for m in $* ;do          echo "[$m]"     done }  IFS=':' var='::a:b::c:::' output_args_ifs $var

 

输出为:

  1. =::a:b::c::  # 少了最后一个冒号!看前面就知道为什么了  
  2. =  a b  c   
  3. []  
  4. []  
  5. [a]  
  6. [b]  
  7. []  
  8. [c]  
  9. []  
=::a:b::c::  # 少了最后一个冒号!看前面就知道为什么了 =  a b  c  [] [] [a] [b] [] [c] []

由于 "output_args_ifs $var" 中 $var 没有加引号,所以根据IFS替换!根据IFS划分出变量: ""  ""  "a"  "b"  ""  "c" "" ""(可以通过输出 $# 来测试参数的个数!),重组的结果为

 "$@" 的值是  "" [space] "" [space]  "a" [space]  "b"  [space] "" [space]  "c" [space] "" [space] "",可以通过,echo==>"  a b  c   "
"$*" 的值是   "" [IFS] "" [IFS]  "a" [IFS]  "b"  [IFS] "" [IFS]  "c" [IFS] "" [IFS] "",忽略"",echo=>"::a:b::c::"

注意, $* 和 $@ 的值都是  ""   ""   "a"   "b"   ""   "c"  ""  "" 。可以说是一个列表……因为他们本来就是由 $1 $2 $3……组成的。

所以,《Linux程序设计》里推荐使用 $@,而不是$*

总结:IFS 其实还是很麻烦的,稍有不慎就会产生很奇怪的结果,因此使用的时候要注意!我也走了不少弯路,只希望能给后来者一些帮助。本文若有问题,欢迎指正!!谢谢!

如有转载,请注明blog.csdn.net/whuslei
参考:
http://blog.chinaunix.net/space.php?uid=20543672&do=blog&id=94358
http://smilejay.com/2011/12/bash_ifs/#comment-51

posted @ 2016-04-01 15:00 xzc 阅读(113) | 评论 (1)编辑 收藏
  2016年3月30日

MYSQL 获取当前日期及日期格式
获取系统日期: NOW()
格式化日期: DATE_FORMAT(date, format)
注: date:时间字段
format:日期格式

返回系统日期,输出 2009-12-25 14:38:59
select now();
输出 09-12-25
select date_format(now(),'%y-%m-%d');

根据format字符串格式化date值:

%S, %s 两位数字形式的秒( 00,01, ..., 59)
%I, %i 两位数字形式的分( 00,01, ..., 59)
%H 两位数字形式的小时,24 小时(00,01, ..., 23)
%h 两位数字形式的小时,12 小时(01,02, ..., 12)
%k 数字形式的小时,24 小时(0,1, ..., 23)
%l 数字形式的小时,12 小时(1, 2, ..., 12)
%T 24 小时的时间形式(hh:mm:ss)
%r 12 小时的时间形式(hh:mm:ss AM 或hh:mm:ss PM)
%p AM或PM
%W 一周中每一天的名称(Sunday, Monday, ..., Saturday)
%a 一周中每一天名称的缩写(Sun, Mon, ..., Sat)
%d 两位数字表示月中的天数(00, 01,..., 31)
%e 数字形式表示月中的天数(1, 2, ..., 31)
%D 英文后缀表示月中的天数(1st, 2nd, 3rd,...)
%w 以数字形式表示周中的天数( 0 = Sunday, 1=Monday, ..., 6=Saturday)
%j 以三位数字表示年中的天数( 001, 002, ..., 366)
%U 周(0, 1, 52),其中Sunday 为周中的第一天
%u 周(0, 1, 52),其中Monday 为周中的第一天
%M 月名(January, February, ..., December)
%b 缩写的月名( January, February,...., December)
%m 两位数字表示的月份(01, 02, ..., 12)
%c 数字表示的月份(1, 2, ...., 12)
%Y 四位数字表示的年份
%y 两位数字表示的年份
%% 直接值“%”

 

 

curdate()

 

MySQL 获得当前日期时间 函数
1.1 获得当前日期+时间(date + time)函数:now()

mysql> select now();

+---------------------+
| now() |
+---------------------+
| 2008-08-08 22:20:46 |
+---------------------+
除了 now() 函数能获得当前的日期时间外,MySQL 中还有下面的函数:

current_timestamp()
,current_timestamp
,localtime()
,localtime
,localtimestamp -- (v4.0.6)
,localtimestamp() -- (v4.0.6)
这些日期时间函数,都等同于 now()。鉴于 now() 函数简短易记,建议总是使用 now() 来替代上面列出的函数。

1.2 获得当前日期+时间(date + time)函数:sysdate()

sysdate() 日期时间函数跟 now() 类似,不同之处在于:now() 在执行开始时值就得到了, sysdate() 在函数执行时动态得到值。看下面的例子就明白了:

mysql> select now(), sleep(3), now();

+---------------------+----------+---------------------+
| now() | sleep(3) | now() |
+---------------------+----------+---------------------+
| 2008-08-08 22:28:21 | 0 | 2008-08-08 22:28:21 |
+---------------------+----------+---------------------+mysql> select sysdate(), sleep(3), sysdate();

+---------------------+----------+---------------------+
| sysdate() | sleep(3) | sysdate() |
+---------------------+----------+---------------------+
| 2008-08-08 22:28:41 | 0 | 2008-08-08 22:28:44 |
+---------------------+----------+---------------------+
可以看到,虽然中途 sleep 3 秒,但 now() 函数两次的时间值是相同的; sysdate() 函数两次得到的时间值相差 3秒。MySQL Manual 中是这样描述 sysdate() 的:Return the time at which the functionexecutes。

sysdate() 日期时间函数,一般情况下很少用到。

2. 获得当前日期(date)函数:curdate()

mysql> select curdate();

+------------+
| curdate() |
+------------+
| 2008-08-08 |
+------------+
其中,下面的两个日期函数等同于 curdate():

current_date()
,current_date
3. 获得当前时间(time)函数:curtime()

mysql> select curtime();

+-----------+
| curtime() |
+-----------+
| 22:41:30 |
+-----------+
其中,下面的两个时间函数等同于 curtime():

current_time()
,current_time
4. 获得当前 UTC 日期时间函数:utc_date(), utc_time(), utc_timestamp()

mysql> select utc_timestamp(), utc_date(), utc_time(), now()

+---------------------+------------+------------+---------------------+
| utc_timestamp() | utc_date() | utc_time() | now() |
+---------------------+------------+------------+---------------------+
| 2008-08-08 14:47:11 | 2008-08-08 | 14:47:11 | 2008-08-08 22:47:11 |
+---------------------+------------+------------+---------------------+
因为我国位于东八时区,所以本地时间 = UTC 时间 + 8 小时。UTC 时间在业务涉及多个国家和地区的时候,非常有用。

二、MySQL 日期时间 Extract(选取) 函数。
1. 选取日期时间的各个部分:日期、时间、年、季度、月、日、小时、分钟、秒、微秒

set @dt = '2008-09-10 07:15:30.123456';

select date(@dt); -- 2008-09-10
select time(@dt); -- 07:15:30.123456
select year(@dt); -- 2008
select quarter(@dt); -- 3
select month(@dt); -- 9
select week(@dt); -- 36
select day(@dt); -- 10
select hour(@dt); -- 7
select minute(@dt); -- 15
select second(@dt); -- 30
select microsecond(@dt); -- 123456
2. MySQL Extract() 函数,可以上面实现类似的功能:

set @dt = '2008-09-10 07:15:30.123456';

select extract(year from @dt); -- 2008
select extract(quarter from @dt); -- 3
select extract(month from @dt); -- 9
select extract(week from @dt); -- 36
select extract(day from @dt); -- 10
select extract(hour from @dt); -- 7
select extract(minute from @dt); -- 15
select extract(second from @dt); -- 30
select extract(microsecond from @dt); -- 123456select extract(year_month from @dt); -- 200809
select extract(day_hour from @dt); -- 1007
select extract(day_minute from @dt); -- 100715
select extract(day_second from @dt); -- 10071530
select extract(day_microsecond from @dt); -- 10071530123456
select extract(hour_minute from @dt); -- 715
select extract(hour_second from @dt); -- 71530
select extract(hour_microsecond from @dt); -- 71530123456
select extract(minute_second from @dt); -- 1530
select extract(minute_microsecond from @dt); -- 1530123456
select extract(second_microsecond from @dt); -- 30123456
MySQLExtract() 函数除了没有date(),time() 的功能外,其他功能一应具全。并且还具有选取‘day_microsecond’等功能。注意这里不是只选取 day 和 microsecond,而是从日期的 day 部分一直选取到 microsecond 部分。够强悍的吧!

MySQL Extract() 函数唯一不好的地方在于:你需要多敲几次键盘。

3. MySQL dayof… 函数:dayofweek(), dayofmonth(), dayofyear()

分别返回日期参数,在一周、一月、一年中的位置。

set @dt = '2008-08-08';

select dayofweek(@dt); -- 6
select dayofmonth(@dt); -- 8
select dayofyear(@dt); -- 221
日期 ‘2008-08-08′ 是一周中的第 6 天(1 = Sunday, 2 = Monday, …, 7 = Saturday);一月中的第 8 天;一年中的第 221 天。

4. MySQL week… 函数:week(), weekofyear(), dayofweek(), weekday(), yearweek()

set @dt = '2008-08-08';

select week(@dt); -- 31
select week(@dt,3); -- 32
select weekofyear(@dt); -- 32

select dayofweek(@dt); -- 6
select weekday(@dt); -- 4

select yearweek(@dt); -- 200831
MySQL week() 函数,可以有两个参数,具体可看手册。 weekofyear() 和 week() 一样,都是计算“某天”是位于一年中的第几周。 weekofyear(@dt) 等价于 week(@dt,3)。

MySQLweekday() 函数和 dayofweek() 类似,都是返回“某天”在一周中的位置。不同点在于参考的标准, weekday:(0 =Monday, 1 = Tuesday, …, 6 = Sunday); dayofweek:(1 = Sunday, 2 = Monday,…, 7 = Saturday)

MySQL yearweek() 函数,返回 year(2008) + week 位置(31)。

5. MySQL 返回星期和月份名称函数:dayname(), monthname()

set @dt = '2008-08-08';

select dayname(@dt); -- Friday
select monthname(@dt); -- August
思考,如何返回中文的名称呢?

6. MySQL last_day() 函数:返回月份中的最后一天。

select last_day('2008-02-01'); -- 2008-02-29
select last_day('2008-08-08'); -- 2008-08-31
MySQL last_day() 函数非常有用,比如我想得到当前月份中有多少天,可以这样来计算:

mysql> select now(), day(last_day(now())) as days;

+---------------------+------+
| now() | days |
+---------------------+------+
| 2008-08-09 11:45:45 | 31 |
+---------------------+------+ 三、MySQL 日期时间计算函数
1. MySQL 为日期增加一个时间间隔:date_add()

set @dt = now();

select date_add(@dt, interval 1 day); -- add 1 day
select date_add(@dt, interval 1 hour); -- add 1 hour
select date_add(@dt, interval 1 minute); -- ...
select date_add(@dt, interval 1 second);
select date_add(@dt, interval 1 microsecond);
select date_add(@dt, interval 1 week);
select date_add(@dt, interval 1 month);
select date_add(@dt, interval 1 quarter);
select date_add(@dt, interval 1 year);select date_add(@dt, interval -1 day); -- sub 1 day
MySQL adddate(), addtime()函数,可以用 date_add() 来替代。下面是 date_add() 实现 addtime() 功能示例:

mysql> set @dt = '2008-08-09 12:12:33';

mysql>
mysql> select date_add(@dt, interval '01:15:30' hour_second);

+------------------------------------------------+
| date_add(@dt, interval '01:15:30' hour_second) |
+------------------------------------------------+
| 2008-08-09 13:28:03 |
+------------------------------------------------+mysql> select date_add(@dt, interval '1 01:15:30' day_second);

+-------------------------------------------------+
| date_add(@dt, interval '1 01:15:30' day_second) |
+-------------------------------------------------+
| 2008-08-10 13:28:03 |
+-------------------------------------------------+
date_add() 函数,分别为 @dt 增加了“1小时 15分 30秒” 和 “1天 1小时 15分 30秒”。建议:总是使用 date_add() 日期时间函数来替代 adddate(), addtime()。

2. MySQL 为日期减去一个时间间隔:date_sub()

mysql> select date_sub('1998-01-01 00:00:00', interval '1 1:1:1' day_second);

+----------------------------------------------------------------+
| date_sub('1998-01-01 00:00:00', interval '1 1:1:1' day_second) |
+----------------------------------------------------------------+
| 1997-12-30 22:58:59 |
+----------------------------------------------------------------+
MySQL date_sub() 日期时间函数 和 date_add() 用法一致,不再赘述。另外,MySQL 中还有两个函数 subdate(), subtime(),建议,用 date_sub() 来替代。

3. MySQL 另类日期函数:period_add(P,N), period_diff(P1,P2)

函数参数“P” 的格式为“YYYYMM” 或者 “YYMM”,第二个参数“N” 表示增加或减去 N month(月)。

MySQL period_add(P,N):日期加/减去N月。

mysql> select period_add(200808,2), period_add(20080808,-2)

+----------------------+-------------------------+
| period_add(200808,2) | period_add(20080808,-2) |
+----------------------+-------------------------+
| 200810 | 20080806 |
+----------------------+-------------------------+
MySQL period_diff(P1,P2):日期 P1-P2,返回 N 个月。

mysql> select period_diff(200808, 200801);

+-----------------------------+
| period_diff(200808, 200801) |
+-----------------------------+
| 7 |
+-----------------------------+
在 MySQL 中,这两个日期函数,一般情况下很少用到。

4. MySQL 日期、时间相减函数:datediff(date1,date2), timediff(time1,time2)

MySQL datediff(date1,date2):两个日期相减 date1 - date2,返回天数。

select datediff('2008-08-08', '2008-08-01'); -- 7
select datediff('2008-08-01', '2008-08-08'); -- -7
MySQL timediff(time1,time2):两个日期相减 time1 - time2,返回 time 差值。

select timediff('2008-08-08 08:08:08', '2008-08-08 00:00:00'); -- 08:08:08
select timediff('08:08:08', '00:00:00'); -- 08:08:08
注意:timediff(time1,time2) 函数的两个参数类型必须相同。

四、MySQL 日期转换函数、时间转换函数
1. MySQL (时间、秒)转换函数:time_to_sec(time), sec_to_time(seconds)

select time_to_sec('01:00:05'); -- 3605
select sec_to_time(3605); -- '01:00:05'
2. MySQL (日期、天数)转换函数:to_days(date), from_days(days)

select to_days('0000-00-00'); -- 0
select to_days('2008-08-08'); -- 733627select from_days(0); -- '0000-00-00'
select from_days(733627); -- '2008-08-08'
3. MySQL Str to Date (字符串转换为日期)函数:str_to_date(str, format)

select str_to_date('08/09/2008', '%m/%d/%Y'); -- 2008-08-09
select str_to_date('08/09/08' , '%m/%d/%y'); -- 2008-08-09
select str_to_date('08.09.2008', '%m.%d.%Y'); -- 2008-08-09
select str_to_date('08:09:30', '%h:%i:%s'); -- 08:09:30
select str_to_date('08.09.2008 08:09:30', '%m.%d.%Y %h:%i:%s'); -- 2008-08-09 08:09:30
可以看到,str_to_date(str,format) 转换函数,可以把一些杂乱无章的字符串转换为日期格式。另外,它也可以转换为时间。“format” 可以参看 MySQL 手册。

4. MySQL Date/Time to Str(日期/时间转换为字符串)函数:date_format(date,format), time_format(time,format)

mysql> select date_format('2008-08-08 22:23:00', '%W %M %Y');

+------------------------------------------------+
| date_format('2008-08-08 22:23:00', '%W %M %Y') |
+------------------------------------------------+
| Friday August 2008 |
+------------------------------------------------+mysql> select date_format('2008-08-08 22:23:01', '%Y%m%d%H%i%s');

+----------------------------------------------------+
| date_format('2008-08-08 22:23:01', '%Y%m%d%H%i%s') |
+----------------------------------------------------+
| 20080808222301 |
+----------------------------------------------------+mysql> select time_format('22:23:01', '%H.%i.%s');

+-------------------------------------+
| time_format('22:23:01', '%H.%i.%s') |
+-------------------------------------+
| 22.23.01 |
+-------------------------------------+
MySQL 日期、时间转换函数:date_format(date,format), time_format(time,format) 能够把一个日期/时间转换成各种各样的字符串格式。它是 str_to_date(str,format) 函数的 一个逆转换。

5. MySQL 获得国家地区时间格式函数:get_format()

MySQL get_format() 语法:

get_format(date|time|datetime, 'eur'|'usa'|'jis'|'iso'|'internal'
MySQL get_format() 用法的全部示例:

select get_format(date,'usa') ; -- '%m.%d.%Y'
select get_format(date,'jis') ; -- '%Y-%m-%d'
select get_format(date,'iso') ; -- '%Y-%m-%d'
select get_format(date,'eur') ; -- '%d.%m.%Y'
select get_format(date,'internal') ; -- '%Y%m%d'
select get_format(datetime,'usa') ; -- '%Y-%m-%d %H.%i.%s'
select get_format(datetime,'jis') ; -- '%Y-%m-%d %H:%i:%s'
select get_format(datetime,'iso') ; -- '%Y-%m-%d %H:%i:%s'
select get_format(datetime,'eur') ; -- '%Y-%m-%d %H.%i.%s'
select get_format(datetime,'internal') ; -- '%Y%m%d%H%i%s'
select get_format(time,'usa') ; -- '%h:%i:%s %p'
select get_format(time,'jis') ; -- '%H:%i:%s'
select get_format(time,'iso') ; -- '%H:%i:%s'
select get_format(time,'eur') ; -- '%H.%i.%s'
select get_format(time,'internal') ; -- '%H%i%s'
MySQL get_format() 函数在实际中用到机会的比较少。

6. MySQL 拼凑日期、时间函数:makdedate(year,dayofyear), maketime(hour,minute,second)

select makedate(2001,31); -- '2001-01-31'
select makedate(2001,32); -- '2001-02-01'select maketime(12,15,30); -- '12:15:30' 五、MySQL 时间戳(Timestamp)函数
1. MySQL 获得当前时间戳函数:current_timestamp, current_timestamp()

mysql> select current_timestamp, current_timestamp();

+---------------------+---------------------+
| current_timestamp | current_timestamp() |
+---------------------+---------------------+
| 2008-08-09 23:22:24 | 2008-08-09 23:22:24 |
+---------------------+---------------------+
2. MySQL (Unix 时间戳、日期)转换函数:

unix_timestamp(),
unix_timestamp(date),
from_unixtime(unix_timestamp),
from_unixtime(unix_timestamp,format)
下面是示例:

select unix_timestamp(); -- 1218290027
select unix_timestamp('2008-08-08'); -- 1218124800
select unix_timestamp('2008-08-08 12:30:00'); -- 1218169800select from_unixtime(1218290027); -- '2008-08-09 21:53:47'
select from_unixtime(1218124800); -- '2008-08-08 00:00:00'
selectfrom_unixtime(1218169800); -- '2008-08-08 12:30:00'selectfrom_unixtime(1218169800, '%Y %D %M %h:%i:%s %x'); -- '2008 8th August12:30:00 2008'
3. MySQL 时间戳(timestamp)转换、增、减函数:

timestamp(date) -- date to timestamp
timestamp(dt,time) -- dt + time
timestampadd(unit,interval,datetime_expr) --
timestampdiff(unit,datetime_expr1,datetime_expr2) --
请看示例部分:

select timestamp('2008-08-08'); -- 2008-08-08 00:00:00
select timestamp('2008-08-08 08:00:00', '01:01:01'); -- 2008-08-08 09:01:01
selecttimestamp('2008-08-08 08:00:00', '10 01:01:01'); -- 2008-08-1809:01:01select timestampadd(day, 1, '2008-08-08 08:00:00'); --2008-08-09 08:00:00
select date_add('2008-08-08 08:00:00', interval 1 day); -- 2008-08-09 08:00:00
MySQL timestampadd() 函数类似于 date_add()。

select timestampdiff(year,'2002-05-01','2001-01-01'); -- -1
select timestampdiff(day ,'2002-05-01','2001-01-01'); -- -485
select timestampdiff(hour,'2008-08-08 12:00:00','2008-08-08 00:00:00'); -- -12

select datediff('2008-08-08 12:00:00', '2008-08-01 00:00:00'); -- 7
MySQL timestampdiff() 函数就比 datediff() 功能强多了,datediff() 只能计算两个日期(date)之间相差的天数。

六、MySQL 时区(timezone)转换函数convert_tz(dt,from_tz,to_tz)selectconvert_tz('2008-08-08 12:00:00', '+08:00', '+00:00'); -- 2008-08-0804:00:00
时区转换也可以通过 date_add, date_sub, timestampadd 来实现。

select date_add('2008-08-08 12:00:00', interval -8 hour); -- 2008-08-08 04:00:00
select date_sub('2008-08-08 12:00:00', interval 8 hour); -- 2008-08-08 04:00:00
select timestampadd(hour, -8, '2008-08-08 12:00:00'); -- 2008-08-08 04:00:00

posted @ 2016-03-30 10:33 xzc 阅读(112) | 评论 (2)编辑 收藏
  2016年3月24日

在项目中遇到一个奇怪的bug,是由一行简单代码引起的。
代码作用:比较两个UNIX文本文件,找出并打印文本2比文本1新增加的内容。
代码调用了diff命令,例如:
 
 

复制代码
代码如下:

# temp1.txt文件内容
$> cat temp1.txt
20110224
20110225
20110228
20110301
20110302
# temp2.txt文件内容
$> cat temp2.txt
20110228
20110301
20110302
20110303
20110304

 

# diff命令输出结果


复制代码
代码如下:

$> diff temp1.txt temp2.txt
1,2d0
< 20110224
< 20110225
5a4,5
> 20110303
> 20110304
# 只输出temp2.txt文件独有的内容
$> diff temp1.txt temp2.txt | grep "> " | sed 's/> //g'
20110303
20110304

 

说明:输出结果去掉了两个文件的共同内容,只输出了temp2.txt的新增部分,和预想的结果一样。
 
但是,随着temp1.txt文件内容的增加,diff命令出现了不同预期的结果:


复制代码
代码如下:

$> cat temp1.txt
20101216
20101217
20101220
20101221
20101223
20101224
20101227
20101228
20101229
20101230
20101231
20110103
20110104
20110105
20110106
20110107
20110110
20110111
20110112
20110113
20110114
20110117
20110118
20110119
20110120
20110121
20110124
20110125
20110126
20110127
20110128
20110131
20110201
20110202
20110203
20110204
20110207
20110208
20110209
20110210
20110211
20110214
20110215
20110216
20110217
20110218
20110221
20110222
20110223
20110224
20110225
20110228
20110301
20110302
20110303
$> cat temp2.txt
20110228
20110301
20110302
20110303
20110304
20110307
20110308
20110309
20110310
20110311
20110314
$> diff temp1.txt temp2.txt
1,55c1,11
< 20101216
< 20101217
< 20101220
< 20101221
< 20101223
< 20101224
< 20101227
< 20101228
< 20101229
< 20101230
< 20101231
< 20110103
< 20110104
< 20110105
< 20110106
< 20110107
< 20110110
< 20110111
< 20110112
< 20110113
< 20110114
< 20110117
< 20110118
< 20110119
< 20110120
< 20110121
< 20110124
< 20110125
< 20110126
< 20110127
< 20110128
< 20110131
< 20110201
< 20110202
< 20110203
< 20110204
< 20110207
< 20110208
< 20110209
< 20110210
< 20110211
< 20110214
< 20110215
< 20110216
< 20110217
< 20110218
< 20110221
< 20110222
< 20110223
< 20110224
< 20110225
< 20110228
< 20110301
< 20110302
< 20110303
---
> 20110228
> 20110301
> 20110302
> 20110303
> 20110304
> 20110307
> 20110308
> 20110309
> 20110310
> 20110311
> 20110314
$> diff temp1.txt temp2.txt | grep "> " | sed 's/> //g'
20110228
20110301
20110302
20110303
20110304
20110307
20110308
20110309
20110310
20110311
20110314

 

可以看到,diff命令不但输出了temp2.txt文件的新增部分(20110304-20110314),也同时输出了两个文件的共同内容(20110228-20110303),从而导致了与预期不一致的结果。
查看diff命令的man手册发现,diff的作用是比较两个文件的内容,并输出两个文件之间的差异,产生一个能够将两个文件互相转换的列表,但这个列表并不能100%保证是最小集。
于是,以上例子中,可以看到diff给出了temp1.txt和temp2.txt文件的比较差异结果,但其中包含了两个文件的共同部分,因此与预期不一样。
 
解决方法:
用comm命令代替diff,例如:


复制代码
代码如下:

$> comm -13 temp1.txt temp2.txt
20110304
20110307
20110308
20110309
20110310
20110311
20110314

 

comm命令用来比较两个文件,具体用法:
comm [-123] file1 file2
-1 过滤file1独有的内容
-2 过滤file2独有的内容
-3 过滤file1和file2重复的内容
 
备注:
diff的输出格式,主要有以下几种:
n1 a n3,n4
n1,n2 d n3
n1,n2 c n3,n4
例如"1,2d0" "5a4,5" "1,55c1,11"等。
其中n1和n2指第一个文件的行数,n3和n4指第二个文件的行数。"a"代表add增加,"d"代表delete删除,"c"代表change整块变动。
有了diff的输出结果,可以使用patch命令将一个文件恢复成另一个,例如:


复制代码
代码如下:

$> cat temp1.txt
20110224
20110225
20110228
20110301
20110302
$> cat temp2.txt
20110228
20110301
20110302
20110303
20110304
$> diff temp1.txt temp2.txt > temp.diff
$> cat temp.diff
1,2d0
< 20110224
< 20110225
5a4,5
> 20110303
> 20110304
# 使用temp.diff和temp1.txt恢复temp2文件
$> patch -i temp.diff -o temp2_restore.txt temp1.txt
Looks like a normal diff.
done
# 完成后temp2_restore和原temp2文件内容一致
$> cat temp2_restore.txt
20110228
20110301
20110302
20110303
20110304
posted @ 2016-03-24 12:09 xzc 阅读(97) | 评论 (1)编辑 收藏
status=`ftp -v -n $ip<<END_SCRIPT
user $name $code
binary
cd $remote_dir
lcd $local_dir
prompt
mget *.txt
#mdelete *.txt
close
bye
END_SCRIPT`

echo $status|grep "226 Transfer complete"
if [ $? -eq 0 ]
then
      echo "Connect Succeed!!!"
      exit 0
else
      echo $status|grep "530 Login incorrect"
      if [ $? -eq 0 ]
      then
            echo "FTP Connect Error!!!"
            exit 1
      else
            echo "No data transferred!!!"
            exit 0
      fi
fi
posted @ 2016-03-24 12:08 xzc 阅读(97) | 评论 (0)编辑 收藏
  2016年2月22日

获得当前日期+时间(date + time)函数:now()

复制代码
mysql> select now();  +---------------------+ | now() | +---------------------+ | 2008-08-08 22:20:46 | +---------------------+
复制代码

获得当前日期+时间(date + time)函数:sysdate()
sysdate() 日期时间函数跟 now() 类似,不同之处在于:now() 在执行开始时值就得到了, sysdate() 在函数执行时动态得到值。看下面的例子就明白了:

复制代码
mysql> select now(), sleep(3), now();  +---------------------+----------+---------------------+ | now() | sleep(3) | now() | +---------------------+----------+---------------------+ | 2008-08-08 22:28:21 | 0 | 2008-08-08 22:28:21 | +---------------------+----------+---------------------+
复制代码

sysdate() 日期时间函数,一般情况下很少用到。

 

MySQL 获得当前时间戳函数:current_timestamp, current_timestamp()

复制代码
mysql> select current_timestamp, current_timestamp();  +---------------------+---------------------+ | current_timestamp | current_timestamp() | +---------------------+---------------------+ | 2008-08-09 23:22:24 | 2008-08-09 23:22:24 | +---------------------+---------------------+
复制代码

 

MySQL 日期转换函数、时间转换函数

MySQL Date/Time to Str(日期/时间转换为字符串)函数:date_format(date,format), time_format(time,format)

复制代码
mysql> select date_format('2008-08-08 22:23:01', '%Y%m%d%H%i%s');  +----------------------------------------------------+ | date_format('2008-08-08 22:23:01', '%Y%m%d%H%i%s') | +----------------------------------------------------+ | 20080808222301 | +----------------------------------------------------+
复制代码

MySQL 日期、时间转换函数:date_format(date,format), time_format(time,format) 能够把一个日期/时间转换成各种各样的字符串格式。它是 str_to_date(str,format) 函数的 一个逆转换。

 

MySQL Str to Date (字符串转换为日期)函数:str_to_date(str, format)

select str_to_date('08/09/2008', '%m/%d/%Y'); -- 2008-08-09 select str_to_date('08/09/08' , '%m/%d/%y'); -- 2008-08-09 select str_to_date('08.09.2008', '%m.%d.%Y'); -- 2008-08-09 select str_to_date('08:09:30', '%h:%i:%s'); -- 08:09:30 select str_to_date('08.09.2008 08:09:30', '%m.%d.%Y %h:%i:%s'); -- 2008-08-09 08:09:30

可以看到,str_to_date(str,format) 转换函数,可以把一些杂乱无章的字符串转换为日期格式。另外,它也可以转换为时间。“format” 可以参看 MySQL 手册。

 

MySQL (日期、天数)转换函数:to_days(date), from_days(days)

select to_days('0000-00-00'); -- 0 select to_days('2008-08-08'); -- 733627

 

MySQL (时间、秒)转换函数:time_to_sec(time), sec_to_time(seconds)

select time_to_sec('01:00:05'); -- 3605 select sec_to_time(3605); -- '01:00:05'

 

MySQL 拼凑日期、时间函数:makdedate(year,dayofyear), maketime(hour,minute,second)

select makedate(2001,31); -- '2001-01-31' select makedate(2001,32); -- '2001-02-01' select maketime(12,15,30); -- '12:15:30'

 

MySQL (Unix 时间戳、日期)转换函数

unix_timestamp(), unix_timestamp(date), from_unixtime(unix_timestamp), from_unixtime(unix_timestamp,format)


下面是示例:

复制代码
select unix_timestamp(); -- 1218290027 select unix_timestamp('2008-08-08'); -- 1218124800 select unix_timestamp('2008-08-08 12:30:00'); -- 1218169800  select from_unixtime(1218290027); -- '2008-08-09 21:53:47' select from_unixtime(1218124800); -- '2008-08-08 00:00:00' select from_unixtime(1218169800); -- '2008-08-08 12:30:00'  select from_unixtime(1218169800, '%Y %D %M %h:%i:%s %x'); -- '2008 8th August 12:30:00 2008'
复制代码

 

 

MySQL 日期时间计算函数

 

MySQL 为日期增加一个时间间隔:date_add()

复制代码
set @dt = now();  select date_add(@dt, interval 1 day); -- add 1 day select date_add(@dt, interval 1 hour); -- add 1 hour select date_add(@dt, interval 1 minute); -- ... select date_add(@dt, interval 1 second); select date_add(@dt, interval 1 microsecond); select date_add(@dt, interval 1 week); select date_add(@dt, interval 1 month); select date_add(@dt, interval 1 quarter); select date_add(@dt, interval 1 year);  select date_add(@dt, interval -1 day); -- sub 1 day
复制代码

 

MySQL adddate(), addtime()函数,可以用 date_add() 来替代。下面是 date_add() 实现 addtime() 功能示例:

复制代码
mysql> set @dt = '2008-08-09 12:12:33';  mysql> mysql> select date_add(@dt, interval '01:15:30' hour_second);  +------------------------------------------------+ | date_add(@dt, interval '01:15:30' hour_second) | +------------------------------------------------+ | 2008-08-09 13:28:03 | +------------------------------------------------+  mysql> select date_add(@dt, interval '1 01:15:30' day_second);  +-------------------------------------------------+ | date_add(@dt, interval '1 01:15:30' day_second) | +-------------------------------------------------+ | 2008-08-10 13:28:03 | +-------------------------------------------------+
复制代码

 

MySQL 为日期减去一个时间间隔:date_sub()

复制代码
mysql> select date_sub('1998-01-01 00:00:00', interval '1 1:1:1' day_second);  +----------------------------------------------------------------+ | date_sub('1998-01-01 00:00:00', interval '1 1:1:1' day_second) | +----------------------------------------------------------------+ | 1997-12-30 22:58:59 | +----------------------------------------------------------------+
复制代码

MySQL date_sub() 日期时间函数 和 date_add() 用法一致,不再赘述。

 

MySQL 日期、时间相减函数:datediff(date1,date2), timediff(time1,time2)

MySQL datediff(date1,date2):两个日期相减 date1 - date2,返回天数。 select datediff('2008-08-08', '2008-08-01'); -- 7 select datediff('2008-08-01', '2008-08-08'); -- -7

MySQL timediff(time1,time2):两个日期相减 time1 - time2,返回 time 差值。

select timediff('2008-08-08 08:08:08', '2008-08-08 00:00:00'); -- 08:08:08 select timediff('08:08:08', '00:00:00'); -- 08:08:08

注意:timediff(time1,time2) 函数的两个参数类型必须相同。

 

MySQL 时间戳(timestamp)转换、增、减函数:

timestamp(date) -- date to timestamp timestamp(dt,time) -- dt + time timestampadd(unit,interval,datetime_expr) -- timestampdiff(unit,datetime_expr1,datetime_expr2) --

请看示例部分:

复制代码
select timestamp('2008-08-08'); -- 2008-08-08 00:00:00 select timestamp('2008-08-08 08:00:00', '01:01:01'); -- 2008-08-08 09:01:01 select timestamp('2008-08-08 08:00:00', '10 01:01:01'); -- 2008-08-18 09:01:01  select timestampadd(day, 1, '2008-08-08 08:00:00'); -- 2008-08-09 08:00:00 select date_add('2008-08-08 08:00:00', interval 1 day); -- 2008-08-09 08:00:00  MySQL timestampadd() 函数类似于 date_add()。 select timestampdiff(year,'2002-05-01','2001-01-01'); -- -1 select timestampdiff(day ,'2002-05-01','2001-01-01'); -- -485 select timestampdiff(hour,'2008-08-08 12:00:00','2008-08-08 00:00:00'); -- -12  select datediff('2008-08-08 12:00:00', '2008-08-01 00:00:00'); -- 7
复制代码

MySQL timestampdiff() 函数就比 datediff() 功能强多了,datediff() 只能计算两个日期(date)之间相差的天数。

 

MySQL 时区(timezone)转换函数

convert_tz(dt,from_tz,to_tz)  select convert_tz('2008-08-08 12:00:00', '+08:00', '+00:00'); -- 2008-08-08 04:00:00

时区转换也可以通过 date_add, date_sub, timestampadd 来实现。

select date_add('2008-08-08 12:00:00', interval -8 hour); -- 2008-08-08 04:00:00 select date_sub('2008-08-08 12:00:00', interval 8 hour); -- 2008-08-08 04:00:00 select timestampadd(hour, -8, '2008-08-08 12:00:00'); -- 2008-08-08 04:00:00

 

更多参考 http://www.cnblogs.com/she27/archive/2009/01/16/1377089.html

posted @ 2016-02-22 14:46 xzc 阅读(136) | 评论 (1)编辑 收藏
  2016年2月14日
[转载]http://www.blogjava.net/hongqiang/archive/2012/07/12/382939.html
假如你要在linux下删除大量文件,比如100万、1000万,像/var/spool/clientmqueue/的mail邮件, 
像/usr/local/nginx/proxy_temp的nginx缓存等,那么rm -rf *可能就不好使了。 
rsync提供了一些跟删除相关的参数 
rsync --help | grep delete 
     --del                   an alias for --delete-during 
     --delete                delete files that don't exist on the sending side 
     --delete-before         receiver deletes before transfer (default) 
     --delete-during         receiver deletes during transfer, not before 
     --delete-after          receiver deletes after transfer, not before 
     --delete-excluded       also delete excluded files on the receiving side 
     --ignore-errors         delete even if there are I/O errors 
     --max-delete=NUM        don't delete more than NUM files 
其中--delete-before    接收者在传输之前进行删除操作 
可以用来清空目录或文件,如下: 
1、先建立一个空目录 
mkdir /data/blank 
2、用rsync删除目标目录 
rsync --delete-before -d /data/blank/ /var/spool/clientmqueue/ 
这样目标目录很快就被清空了 
又假如你有一些特别大的文件要删除,比如nohup.out这样的实时更新的文件,动辄都是几十个G上百G的,也可 
以用rsync来清空大文件,而且效率比较高 
1、创建空文件 
touch /data/blank.txt 
2、用rsync清空文件 
rsync -a --delete-before --progress --stats /root/blank.txt /root/nohup.out 
building file list ... 
1 file to consider 
blank.txt 
           0 100%    0.00kB/s    0:00:00 (xfer#1, to-check=0/1) 
Number of files: 1 
Number of files transferred: 1 
Total file size: 0 bytes 
Total transferred file size: 0 bytes 
Literal data: 0 bytes 
Matched data: 0 bytes 
File list size: 27 
File list generation time: 0.006 seconds 
File list transfer time: 0.000 seconds 
Total bytes sent: 73 
Total bytes received: 31 
sent 73 bytes  received 31 bytes  208.00 bytes/sec 
total size is 0  speedup is 0.00 
tips: 
当SRC和DEST文件性质不一致时将会报错 
当SRC和DEST性质都为文件【f】时,意思是清空文件内容而不是删除文件 
当SRC和DEST性质都为目录【d】时,意思是删除该目录下的所有文件,使其变为空目录 
最重要的是,它的处理速度相当快,处理几个G的文件也就是秒级的事 
最核心的内容是:rsync实际上用的就是替换原理 
另外一种方式:利用xagr与ls结合
ls | xargs -n 20 rm -fr
ls当然是输出所有的文件名(用空格分割)
xargs就是将ls的输出,每20个为一组(以空格为分隔符),作为rm -rf的参数
也就是说将所有文件名20个为一组,由rm -rf删除,这样就不会超过命令行的长度了
posted @ 2016-02-14 11:05 xzc 阅读(121) | 评论 (1)编辑 收藏
  2015年12月25日

Cloudera Manager分析

目录

1. 相关目录

2. 配置

3. 数据库

4. CM结构

5. 升级

6. 卸载

7. 开启postgresql远程访问

1. 相关目录

  • /var/log/cloudera-scm-installer : 安装日志目录。
  • /var/log/* : 相关日志文件(相关服务的及CM的)。
  • /usr/share/cmf/ : 程序安装目录。
  • /usr/lib64/cmf/ : Agent程序代码。
  • /var/lib/cloudera-scm-server-db/data : 内嵌数据库目录。
  • /usr/bin/postgres : 内嵌数据库程序。
  • /etc/cloudera-scm-agent/ : agent的配置目录。
  • /etc/cloudera-scm-server/ : server的配置目录。
  • /opt/cloudera/parcels/ : Hadoop相关服务安装目录。
  • /opt/cloudera/parcel-repo/ : 下载的服务软件包数据,数据格式为parcels。
  • /opt/cloudera/parcel-cache/ : 下载的服务软件包缓存数据。
  • /etc/hadoop/* : 客户端配置文件目录。

2. 配置

  • Hadoop配置文件

    配置文件放置于/var/run/cloudera-scm-agent/process/目录下。如:/var/run/cloudera-scm-agent/process/193-hdfs-NAMENODE/core-site.xml。这些配置文件是通过Cloudera Manager启动相应服务(如HDFS)时生成的,内容从数据库中获得(即通过界面配置的参数)。

    在CM界面上更改配置是不会立即反映到配置文件中,这些信息会存储于数据库中,等下次重启服务时才会生成配置文件。且每次启动时都会产生新的配置文件。

    CM Server主要数据库为scm基中放置配置的数据表为configs。里面包含了服务的配置信息,每一次配置的更改会把当前页面的所有配置内容添加到数据库中,以此保存配置修改历史。

    scm数据库被配置成只能从localhost访问,如果需要从外部连接此数据库,修改vim /var/lib/cloudera-scm-server-db/data/pg_hba.conf文件,之后重启数据库。运行数据库的用户为cloudera-scm。

  • 查看配置内容

    1. 直接查询scm数据库的configs数据表的内容。
    2. 访问REST API: http://hostname:7180/api/v4/cm/deployment,返回JSON格式部署配置信息。
  • 配置生成方式

    CM为每个服务进程生成独立的配置目录(文件)。所有配置统一在服务端查询数据库生成(因为scm数据库只能在localhost下访问)生成配置文件,再由agent通过网络下载包含配置文件的zip包到本地解压到指定的目录。

  • 配置修改

    CM对于需要修改的配置预先定义,对于没有预先定义的配置,则通过在高级配置项中使用xml配置片段的方式进行配置。而对于/etc/hadoop/下的配置文件是客户端的配置,可以在CM通过部署客户端生成客户端配置。

3. 数据库

Cloudera manager主要的数据库为scm,存储Cloudera manager运行所需要的信息:配置,主机,用户等。

4. CM结构

CM分为Server与Agent两部分及数据库(自带更改过的嵌入Postgresql)。它主要做三件事件:

  1. 管理监控集群主机。
  2. 统一管理配置。
  3. 管理维护Hadoop平台系统。

实现采用C/S结构,Agent为客户端负责执行服务端发来的命令,执行方式一般为使用python调用相应的服务shell脚本。Server端为Java REST服务,提供REST API,Web管理端通过REST API调用Server端功能,Web界面使用富客户端技术(Knockout)。

  1. Server端主体使用Java实现。
  2. Agent端主体使用Python, 服务的启动通过调用相应的shell脚本进行启动,如果启动失败会重复4次调用启动脚本。
  3. Agent与Server保持心跳,使用Thrift RPC框架。

5. 升级

在CM中可以通过界面向导升级相关服务。升级过程为三步:

  1. 下载服务软件包。
  2. 把所下载的服务软件包分发到集群中受管的机器上。
  3. 安装服务软件包,使用软链接的方式把服务程序目录链接到新安装的软件包目录上。

6. 卸载

sudo /usr/share/cmf/uninstall-scm-express.sh, 然后删除/var/lib/cloudera-scm-server-db/目录,不然下次安装可能不成功。

7. 开启postgresql远程访问

CM内嵌数据库被配置成只能从localhost访问,如果需要从外部查看数据,数据修改vim /var/lib/cloudera-scm-server-db/data/pg_hba.conf文件,之后重启数据库。运行数据库的用户为cloudera-scm。

posted @ 2015-12-25 17:28 xzc 阅读(203) | 评论 (0)编辑 收藏
  2015年12月23日

除了在一个目录结构下查找文件这种基本的操作,你还可以用find命令实现一些实用的操作,使你的命令行之旅更加简易。

本文将介绍15种无论是于新手还是老鸟都非常有用的Linux find命令。

首先,在你的home目录下面创建下面的空文件,来测试下面的find命令示例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# vim create_sample_files.sh
touch MybashProgram.sh
touch mycprogram.c
touch MyCProgram.c
touch Program.c
mkdir backup
cd backup
touch MybashProgram.sh
touch mycprogram.c
touch MyCProgram.c
touch Program.c
# chmod +x create_sample_files.sh
# ./create_sample_files.sh
# ls -R
.:
backup                  MybashProgram.sh  MyCProgram.c
create_sample_files.sh  mycprogram.c      Program.c
./backup:
MybashProgram.sh  mycprogram.c  MyCProgram.c  Program.c

1. 用文件名查找文件

这是find命令的一个基本用法。下面的例子展示了用MyCProgram.c作为查找名在当前目录及其子目录中查找文件的方法。

1
2
3
# find -name "MyCProgram.c"
./backup/MyCProgram.c
./MyCProgram.c

2.用文件名查找文件,忽略大小写

这是find命令的一个基本用法。下面的例子展示了用MyCProgram.c作为查找名在当前目录及其子目录中查找文件的方法,忽略了大小写。

1
2
3
4
5
# find -iname "MyCProgram.c"
./mycprogram.c
./backup/mycprogram.c
./backup/MyCProgram.c
./MyCProgram.c

 

3. 使用mindepth和maxdepth限定搜索指定目录的深度

在root目录及其子目录下查找passwd文件。

1
2
3
4
5
# find / -name passwd
./usr/share/doc/nss_ldap-253/pam.d/passwd
./usr/bin/passwd
./etc/pam.d/passwd
./etc/passwd

在root目录及其1层深的子目录中查找passwd. (例如root — level 1, and one sub-directory — level 2)

1
2
# find -maxdepth 2 -name passwd
./etc/passwd

在root目录下及其最大两层深度的子目录中查找passwd文件. (例如 root — level 1, and two sub-directories — level 2 and 3 )

1
2
3
4
# find / -maxdepth 3 -name passwd
./usr/bin/passwd
./etc/pam.d/passwd
./etc/passwd

在第二层子目录和第四层子目录之间查找passwd文件。

1
2
3
# find -mindepth 3 -maxdepth 5 -name passwd
./usr/bin/passwd
./etc/pam.d/passwd

4. 在find命令查找到的文件上执行命令

下面的例子展示了find命令来计算所有不区分大小写的文件名为“MyCProgram.c”的文件的MD5验证和。{}将会被当前文件名取代。

1
2
3
4
5
find -iname "MyCProgram.c" -exec md5sum {} \;
d41d8cd98f00b204e9800998ecf8427e  ./mycprogram.c
d41d8cd98f00b204e9800998ecf8427e  ./backup/mycprogram.c
d41d8cd98f00b204e9800998ecf8427e  ./backup/MyCProgram.c
d41d8cd98f00b204e9800998ecf8427e  ./MyCProgram.c

5. 相反匹配

显示所有的名字不是MyCProgram.c的文件或者目录。由于maxdepth是1,所以只会显示当前目录下的文件和目录。

1
2
3
4
5
6
find -maxdepth 1 -not -iname "MyCProgram.c"
.
./MybashProgram.sh
./create_sample_files.sh
./backup
./Program.c

6. 使用inode编号查找文件

任何一个文件都有一个独一无二的inode编号,借此我们可以区分文件。创建两个名字相似的文件,例如一个有空格结尾,一个没有。

1
2
3
4
5
6
touch "test-file-name"
# touch "test-file-name "
[Note: There is a space at the end]
# ls -1 test*
test-file-name
test-file-name

从ls的输出不能区分哪个文件有空格结尾。使用选项-i,可以看到文件的inode编号,借此可以区分这两个文件。

1
2
3
ls -i1 test*
16187429 test-file-name
16187430 test-file-name

你可以如下面所示在find命令中指定inode编号。在此,find命令用inode编号重命名了一个文件。

1
2
3
4
5
find -inum 16187430 -exec mv {} new-test-file-name \;
 
 # ls -i1 *test*
16187430 new-test-file-name
16187429 test-file-name

你可以在你想对那些像上面一样的糟糕命名的文件做某些操作时使用这一技术。例如,名为file?.txt的文件名字中有一个特殊字符。若你想执行“rm file?.txt”,下面所示的所有三个文件都会被删除。所以,采用下面的步骤来删除”file?.txt”文件。

1
2
ls
file1.txt  file2.txt  file?.txt

找到每一个文件的inode编号。

1
2
3
4
ls -i1
804178 file1.txt
804179 file2.txt
804180 file?.txt

如下所示:?使用inode编号来删除那些具有特殊符号的文件名。

1
2
3
4
find -inum 804180 -exec rm {} \;
# ls
file1.txt  file2.txt
[Note: The file with name "file?.txt" is now removed]

7. 根据文件权限查找文件

下面的操作时合理的:

  • 找到具有指定权限的文件
  • 忽略其他权限位,检查是否和指定权限匹配
  • 根据给定的八进制/符号表达的权限搜索

此例中,假设目录包含以下文件。注意这些文件的权限不同。

1
2
3
4
5
6
7
8
ls -l
total 0
-rwxrwxrwx 1 root root 0 2009-02-19 20:31 all_for_all
-rw-r--r-- 1 root root 0 2009-02-19 20:30 everybody_read
---------- 1 root root 0 2009-02-19 20:31 no_for_all
-rw------- 1 root root 0 2009-02-19 20:29 ordinary_file
-rw-r----- 1 root root 0 2009-02-19 20:27 others_can_also_read
----r----- 1 root root 0 2009-02-19 20:27 others_can_only_read

找到具有组读权限的文件。使用下面的命令来找到当前目录下对同组用户具有读权限的文件,忽略该文件的其他权限。

1
2
3
4
5
find . -perm -g=r -type f -exec ls -l {} \;
-rw-r--r-- 1 root root 0 2009-02-19 20:30 ./everybody_read
-rwxrwxrwx 1 root root 0 2009-02-19 20:31 ./all_for_all
----r----- 1 root root 0 2009-02-19 20:27 ./others_can_only_read
-rw-r----- 1 root root 0 2009-02-19 20:27 ./others_can_also_read

找到对组用户具有只读权限的文件。

1
2
find . -perm g=r -type f -exec ls -l {} \;
----r----- 1 root root 0 2009-02-19 20:27 ./others_can_only_read

找到对组用户具有只读权限的文件(使用八进制权限形式)。

1
2
find . -perm 040 -type f -exec ls -l {} \;
----r----- 1 root root 0 2009-02-19 20:27 ./others_can_only_read

8. 找到home目录及子目录下所有的空文件(0字节文件)

下面命令的输出文件绝大多数都是锁定文件盒其他程序创建的place hoders

1
find ~ -empty

只列出你home目录里的空文件。

1
find . -maxdepth 1 -empty

只列出当年目录下的非隐藏空文件。

1
find . -maxdepth 1 -empty -not -name ".*"

9. 查找5个最大的文件

下面的命令列出当前目录及子目录下的5个最大的文件。这会需要一点时间,取决于命令需要处理的文件数量。

1
find . -type f -exec ls -s {} \; | sort -n -r | head -5

10. 查找5个最小的文件

方法同查找5个最大的文件类似,区别只是sort的顺序是降序。

1
find . -type f -exec ls -s {} \; | sort -n  | head -5

上面的命令中,很可能你看到的只是空文件(0字节文件)。如此,你可以使用下面的命令列出最小的文件,而不是0字节文件。

1
find . -not -empty -type f -exec ls -s {} \; | sort -n  | head -5

11. 使用-type查找指定文件类型的文件

只查找socket文件

1
find . -type s

查找所有的目录

1
find . -type d

查找所有的一般文件

1
find . -type f

查找所有的隐藏文件

1
find . -type f -name ".*"

查找所有的隐藏目录

1
find -type d -name ".*"

12. 通过和其他文件比较修改时间查找文件

显示在指定文件之后做出修改的文件。下面的find命令将显示所有的在ordinary_file之后创建修改的文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
ls -lrt
total 0
-rw-r----- 1 root root 0 2009-02-19 20:27 others_can_also_read
----r----- 1 root root 0 2009-02-19 20:27 others_can_only_read
-rw------- 1 root root 0 2009-02-19 20:29 ordinary_file
-rw-r--r-- 1 root root 0 2009-02-19 20:30 everybody_read
-rwxrwxrwx 1 root root 0 2009-02-19 20:31 all_for_all
---------- 1 root root 0 2009-02-19 20:31 no_for_all
 
# find -newer ordinary_file
.
./everybody_read
./all_for_all
./no_for_all

13. 通过文件大小查找文件

使用-size选项可以通过文件大小查找文件。

查找比指定文件大的文件

1
find ~ -size +100M

查找比指定文件小的文件

1
find ~ -size -100M

查找符合给定大小的文件

1
find ~ -size 100M

注意: – 指比给定尺寸小,+ 指比给定尺寸大。没有符号代表和给定尺寸完全一样大。

14. 给常用find操作取别名

若你发现有些东西很有用,你可以给他取别名。并且在任何你希望的地方执行。

常用的删除a.out文件。

1
2
alias rmao="find . -iname a.out -exec rm {} \;"
# rmao

删除c程序产生的core文件。

1
2
alias rmc="find . -iname core -exec rm {} \;"
# rmc

15. 用find命令删除大型打包文件

下面的命令删除大于100M的*.zip文件。

1
find / -type f -name *.zip -size +100M -exec rm -i {} \;"

用别名rm100m删除所有大雨100M的*.tar文件。使用同样的思想可以创建rm1g,rm2g,rm5g的一类别名来删除所有大于1G,2G,5G的文件。

1
2
3
4
5
6
7
8
9
alias rm100m="find / -type f -name *.tar -size +100M -exec rm -i {} \;"
# alias rm1g="find / -type f -name *.tar -size +1G -exec rm -i {} \;"
# alias rm2g="find / -type f -name *.tar -size +2G -exec rm -i {} \;"
# alias rm5g="find / -type f -name *.tar -size +5G -exec rm -i {} \;"
 
# rm100m
# rm1g
# rm2g
# rm5g

Find命令示例(第二部分)

若你喜欢这篇关于find命令的Mommy文章,别忘了看看第二部分的关于find命令的Daddy文章。《爹地,我找到了!15个极好的Linux find命令示例

posted @ 2015-12-23 10:34 xzc 阅读(167) | 评论 (3)编辑 收藏
仅列出标题  下一页