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)