Bash比较版本号

Linux下bash直接用sort -V实现,Mac下的bash没有-V选项,研究之后有两种方式可以实现,第一种纯sort命令方式,第二种自行写逻辑。

第一种:

sort -n -t . -k 1,3 version.txt

结果:

1.01.2
1.1.0
1.12.3
1.2.5
2.4

第二种,来自(stackoverflow)

#!/bin/bash
vercomp () {
    if [[ $1 == $2 ]]
    then
        return 0
    fi
    local IFS=.
    local i ver1=($1) ver2=($2)
    # fill empty fields in ver1 with zeros
    for ((i=${#ver1[@]}; i<${#ver2[@]}; i++))
    do
        ver1[i]=0
    done
    for ((i=0; i<${#ver1[@]}; i++))
    do
        if [[ -z ${ver2[i]} ]]
        then
            # fill empty fields in ver2 with zeros
            ver2[i]=0
        fi
        if ((10#${ver1[i]} > 10#${ver2[i]}))
        then
            return 1
        fi
        if ((10#${ver1[i]} < 10#${ver2[i]}))
        then
            return 2
        fi
    done
    return 0
}

testvercomp () {
    vercomp $1 $2
    case $? in
        0) op='=';;
        1) op='>';;
        2) op='<';;
    esac
    if [[ $op != $3 ]]
    then
        echo "FAIL: Expected '$3', Actual '$op', Arg1 '$1', Arg2 '$2'"
    else
        echo "Pass: '$1 $op $2'"
    fi
}

# Run tests
# argument table format:
# testarg1   testarg2     expected_relationship
echo "The following tests should pass"
while read -r test
do
    testvercomp $test
done << EOF
1            1            =
2.1          2.2          <
3.0.4.10     3.0.4.2      >
4.08         4.08.01      <
3.2.1.9.8144 3.2          >
3.2          3.2.1.9.8144 <
1.2          2.1          <
2.1          1.2          >
5.6.7        5.6.7        =
1.01.1       1.1.1        =
1.1.1        1.01.1       =
1            1.0          =
1.0          1            =
1.0.2.0      1.0.2        =
1..0         1.0          =
1.0          1..0         =
EOF

echo "The following test should fail (test the tester)"
testvercomp 1 1 '>'
$ . ./vercomp
The following tests should pass
Pass: '1 = 1'
Pass: '2.1 < 2.2'
Pass: '3.0.4.10 > 3.0.4.2'
Pass: '4.08 < 4.08.01'
Pass: '3.2.1.9.8144 > 3.2'
Pass: '3.2 < 3.2.1.9.8144'
Pass: '1.2 < 2.1'
Pass: '2.1 > 1.2'
Pass: '5.6.7 = 5.6.7'
Pass: '1.01.1 = 1.1.1'
Pass: '1.1.1 = 1.01.1'
Pass: '1 = 1.0'
Pass: '1.0 = 1'
Pass: '1.0.2.0 = 1.0.2'
Pass: '1..0 = 1.0'
Pass: '1.0 = 1..0'
The following test should fail (test the tester)
FAIL: Expected '>', Actual '=', Arg1 '1', Arg2 '1'

参考:

http://stackoverflow.com/questions/4023830/how-compare-two-strings-in-dot-separated-version-format-in-bash

Mac rsync+fswatch(inotify) 全自动同步

原创脚本,在bash下通用,mac下是fswatch(从brew安装),linux换成inotifywait即可,脚本写到这水平真不是一般的NB。
用法:

  1. 脚本参数和fswatch参数一致。
  2. fswatch默认忽略了.git .svn和IDE的meta文件,需要忽略其他自行添加即可(可写死可传递命令行参数)。
  3. 在脚本内部也可以设置全局忽略,见$excludeCommon变量,针对单个项目设置忽略见exclude[0]变量。
  4. $projectArr是根叔组,其他数组全部是关联叔组,$rsyncArr设置rsync服务端参数,这个必须和$projectArr一一对应。
  5. 要做到同样的功能,这个脚本的NB程度已经是极限。
#!/usr/bin/env bash
dirPrefixPhp='/Users/Ares/Documents/Work/php'
excludeCommon="app/cache/* app/logs/*"
projectArr[0]=$dirPrefixPhp'/project1'
projectArr[1]=$dirPrefixPhp'/project2'
rsyncArr[0]='-e "ssh -p222" root@xxx.xxx.xxx.xxx:/srv/www/project1'
rsyncArr[1]='root@xxx.xxx.xxx.xxx:/srv/www/project2'
#wild card,seperated by space
exclude[0]=""
watchArgs=$*
if [ -z "$watchArgs" ];then
	watchArgs='.'
fi
fswatch --exclude=.git --exclude=.svn --exclude=.settings --exclude=.project --exclude=.buildpath $watchArgs|while read v;do
	if [ ! -e $v ];then
		continue
	fi
	for k1 in ${!projectArr[*]};do
		dirPrefix=${projectArr[$k1]}
		if [ "${v:0:${#dirPrefix}}" = "$dirPrefix" ];then
			path=${v#$dirPrefix}
			excludeK1=($excludeCommon' '${exclude[$k1]})
			if [ -n "$excludeK1" ];then
				for v2 in ${excludeK1[*]};do
					if [[ "${path:1}" == $v2 ]];then
						break 2
					fi
				done
			fi
			rsync='rsync -avz -R --chown apache:apache'
			rsync="cd ${projectArr[$k1]} && "$rsync' .'$path' '${rsyncArr[$k1]}' --no-p --no-t'
			dst=${rsyncArr[$k1]#*@}
			#dst=${dst%:*}
			echo -n '['`date +%H:%M:%S`'] '{projectArr[$k1]##*/}$path' => '$dst
			#echo -n '['`date +%H:%M:%S`']' $dst$path
			time=$( (time eval $rsync > /dev/null) 2>&1|head -n2|tail -n1|cut -f2)
			if [ 0 -eq $? ];then
				echo -ne " 33[32mok33[0m"
			else
				echo -ne " 33[31mfailed33[0m"
			fi
			echo '('${time:2}')'
		fi
	done
done

运行结果展示

project1/app/conf/app.ini => xxx.xxx.xxx.xxx:/srv/www/project1 ok(0.001s)
project2/app/conf/app.ini => xxx.xxx.xxx.xxx:/srv/www/project2 ok(0.003s)
project3/doc/sms.png => xxx.xxx.xxx.xxx failed(0.002s)

 

shell(bash) “time”输出

bashtime是一个很有用的命令,它可以为一段脚本或一个程序的执行计时,这通常在粗略比较程序执行效率的时候很方便。但是你会发现,time命令输出的时间文字不能被简单地重定向,例如重定向至一个文本文件,只能显示在屏幕上,这对于非交互计时很不方便。例如: 继续阅读

Shell中输出颜色和控制

       我们知道,使用ls命令列出文件列表时,不同的文件类型会用不同的颜色显示。那么如何实现这样带颜色的文本输出呢?答案并不复杂,不管是用shell还是C语言

一、shell下的实现方法

       先来讲在shell下,如何实现。用echo命令就可以实现,参看以下例子:

       echo  -e  "33[32mHello, world!"

       当你在终端里敲下这条命令后,是不是发现系统用绿色输出了"Hello,world!",不止如此,连之后的命令提示符都变成了绿色?不要着急,听我继续说。echo命令-e选项的作用是激活终端对反斜线转义符(即)的解释。引号内33用于引导非常规字符序列,在这里的作用就是引导设置输出属性,后边的[32m就是将前景色设置为绿色,字母m表示设置的属性类别,数字代表属性值。设置可以单独使用,例如:

       echo -e  "33[0m"

       这行命令的作用是恢复属性为默认值,也就是说0m设置项用于恢复默认值。现在你的终端是不是又一切正常了?

       理解了这些,剩下的就简单了。用这种命令,除了设置文本前景色,还可以设置很多属性。下边列出其他的设置项:

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

      33[0m 关闭所有属性
     33[1m 设置高亮度
     33[4m 下划线
     33[5m 闪烁
     33[7m 反显
     33[8m 消隐
     33[30m 至 33[37m 设置前景色
     33[40m 至 33[47m 设置背景色
     33[nA 光标上移n行 
     33[nB 光标下移n行
     33[nC 光标右移n行
     33[nD 光标左移n行
     33[y;xH设置光标位置
     33[2J 清屏
     33[K 清除从光标到行尾的内容
     33[s 保存光标位置 
     33[u 恢复光标位置
     33[?25l 隐藏光标
     33[?25h 显示光标

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

      各数字所代表的颜色如下:

      字背景颜色范围:40----49
     40:黑
     41:深红
     42:绿
     43:黄色
     44:蓝色
     45:紫色
     46:深绿
     47:白色

     字颜色:30-----------39
     30:黑
     31:红
     32:绿
     33:黄
     34:蓝色
     35:紫色
     36:深绿 
     37:白色

      另外,同类的多种设置项可以组合在一起,中间用分号(;)隔开。如下:

      echo -e "33[20;1H33[1;4;32mHello,world33[0m"

      这行命令首先33[20;1H将光标移动到终端第20行第1列,之后的33[1;4;32m将文本属性设置为高亮、带下划线且颜色为绿色,然后输出Hello,world;最后33[0m将终端属性恢复为默认值,这样就不会看到连命令完成后的命令提示符也变了样儿了。

      通过以上各种命令的组合就可以实现对终端输出地复杂控制。

二、如何在C编程中实现?

      理解了以上在Shell中的实现方法,关于在C中如何实现就很简单了。可以说只需要用printf函数代替上边的echo -e就OK了。参见下例:

      int color = 32;

      printf("33[20;1H33[1;4;%dmHello, world.33[0m", color);

      这个例子类似上边shell中最后那个例子,只是这里颜色值通过变量color来指定(当然,也可以直接指定)。

三、联想

      看到这里你可能会想,是不是在其他编程语言里也可以用类似的方法实现对终端输出的控制呢?答案是肯定的!比如在python中,可以如下输出:

      color=32

      print “33[20;1H33[1;4;%dHello, world.33[0m"%color

      这个例子的效果跟上边C的例子是相同的。