第一页 上页 1 2 3 4 5 6 7 8 9 10 下页 最后页 [ 显示模式: 摘要 | 列表 ]

Linux-以指定用户运行redis

[不指定 2017/05/11 10:25 | by 刘新修 ]

redis中无配置启动用户信息,需要添加redis用户,后以其启动(1):

useradd -s /bash/false -M redis  sudo -u redis /xxx/redis-server /xxx/etc/redis.conf >/dev/null 2>&1 &

linux指定某非root用户执行开机启动项的方法(2)

Linux下指定sun用户在linux开机时执行/home/sun/startrun.sh为例:

   以root登录linux

   执行vi /etc/rc.d/rc.local

   在文档末尾添加一行语句:su sun -c "/home/sun/startrun.sh"

   保存rc.local即可。

/bin/false和/sbin/nologin的区别
 
1 区别 
/bin/false是最严格的禁止login选项,一切服务都不能用。 
/sbin/nologin只是不允许login系统 
 
其中树莓派的/sbin/nologin文件在/usr/sbin/nologin 
小技巧: 
查看 /etc/passwd文件,能看到各用户使用的shell 
 
2.1 nologin 
当用户配置成/sbin/nologin时,如果再使用该用户ssh到linux操作系统,会提示 
This account is currently not available. 
 
如果在树莓派下,配置错误,误将/usr/sbin/nologin配置成/sbin/nologin,SSH时会提示 
root@raspberrypi:/home# useradd -s /sbin/nologin piaohailin 
root@raspberrypi:/home# su piaohailin 
Cannot execute /sbin/nologin: No such file or directory 
 
2.2 false 
当用户配置成/bin/false时,ssh之后显示如下 
root@raspberrypi:/home# useradd -s /bin/false piaohailin 
root@raspberrypi:/home# su piaohailin 
root@raspberrypi:/home# whoami 
root 

不会有任何提示,用户切换不过去 

 在Windows系统中,我们可以使用TreeSize工具查找一些大文件或文件夹,非常的方便高效,在Linux系统中,如何去搜索一些比较大的文件呢?下面我整理了一下在Linux系统中如何查找大文件或文件夹的方法。

1: 如何查找大文件?

 

其实很多时候,你需要了解当前系统下有哪些大文件,比如文件大小超过100M或1G(阀值视具体情况而定)。那么如何把这些大文件搜索出来呢?例如我要搜索当前目录下,超过800M大小的文件

C#代码
  1. [root@getlnx01 u03]# pwd  
  2. /u03  
  3. [root@getlnx01 u03]# find . -type f -size +800M  
  4. ./flash_recovery_area/backup/backupsets/ora_df873519197_s46815_s1  
  5. ./flash_recovery_area/backup/backupsets/ora_df873523646_s46822_s1  
  6. ./flash_recovery_area/backup/backupsets/ora_df873521714_s46818_s1  
  7. ./flash_recovery_area/backup/backupsets/ora_df873522876_s46820_s1  
  8. ./flash_recovery_area/backup/backupsets/ora_df873517396_s46813_s1  
  9. ./flash_recovery_area/backup/backupsets/ora_df873523321_s46821_s1  
  10. ./flash_recovery_area/backup/backupsets/ora_df873515765_s46811_s1  
  11. ./flash_recovery_area/backup/backupsets/ora_df873520789_s46817_s1  
  12. ./flash_recovery_area/backup/backupsets/ora_df873524162_s46823_s1  
  13. ./flash_recovery_area/backup/backupsets/ora_df873518302_s46814_s1  
  14. ./flash_recovery_area/backup/backupsets/ora_df873519953_s46816_s1  
  15. ./flash_recovery_area/backup/backupsets/ora_df873516500_s46812_s1  
  16. ./flash_recovery_area/backup/backupsets/ora_df873513413_s46809_s1  
  17. ./flash_recovery_area/backup/backupsets/ora_df873514789_s46810_s1  
  18. ./oradata/epps/invsubmat_d08.dbf  
  19. ./oradata/epps/gmtinv_d08.dbf  
  20. ./oradata/epps/gmtinv_x01.dbf  
  21. ./oradata/epps/undotbs02.dbf  
  22. ./oradata/epps/gmtinv_d07.dbf  
  23. ./oradata/epps/undotbs01.dbf  
  24. ./oradata/epps/gmtinv_x02.dbf  

如上命令所示,我们仅仅能看到超过800M大小的文件的文件名称,但是对文件的信息(例如,文件大小、文件属性)一无所知,那么能否更详细显示一些文件属性或信息呢,当然可以,如下所示

C#代码
  1. [root@getlnx01 u03]# find . -type f -size +800M  -print0 | xargs -0 ls -l  
  2. -rw-r----- 1 oracle oinstall 2782846976 Mar  6 11:51 ./flash_recovery_area/backup/backupsets/ora_df873513413_s46809_s1  
  3. -rw-r----- 1 oracle oinstall 1878433792 Mar  6 11:53 ./flash_recovery_area/backup/backupsets/ora_df873514789_s46810_s1  
  4. -rw-r----- 1 oracle oinstall 1378492416 Mar  6 11:54 ./flash_recovery_area/backup/backupsets/ora_df873515765_s46811_s1  
  5. -rw-r----- 1 oracle oinstall 1641381888 Mar  6 11:56 ./flash_recovery_area/backup/backupsets/ora_df873516500_s46812_s1  
  6. -rw-r----- 1 oracle oinstall 1564065792 Mar  6 11:58 ./flash_recovery_area/backup/backupsets/ora_df873517396_s46813_s1  
  7. -rw-r----- 1 oracle oinstall 1663492096 Mar  6 12:00 ./flash_recovery_area/backup/backupsets/ora_df873518302_s46814_s1  
  8. -rw-r----- 1 oracle oinstall 1368244224 Mar  6 12:02 ./flash_recovery_area/backup/backupsets/ora_df873519197_s46815_s1  
  9. -rw-r----- 1 oracle oinstall 1629069312 Mar  6 12:04 ./flash_recovery_area/backup/backupsets/ora_df873519953_s46816_s1  
  10. -rw-r----- 1 oracle oinstall 1629954048 Mar  6 12:06 ./flash_recovery_area/backup/backupsets/ora_df873520789_s46817_s1  
  11. -rw-r----- 1 oracle oinstall 1202192384 Mar  6 12:07 ./flash_recovery_area/backup/backupsets/ora_df873521714_s46818_s1  
  12. -rw-r----- 1 oracle oinstall 1189388288 Mar  6 12:10 ./flash_recovery_area/backup/backupsets/ora_df873522876_s46820_s1  
  13. -rw-r----- 1 oracle oinstall 1089257472 Mar  6 12:11 ./flash_recovery_area/backup/backupsets/ora_df873523321_s46821_s1  
  14. -rw-r----- 1 oracle oinstall 1097687040 Mar  6 12:12 ./flash_recovery_area/backup/backupsets/ora_df873523646_s46822_s1  
  15. -rw-r----- 1 oracle oinstall 1051009024 Mar  6 12:13 ./flash_recovery_area/backup/backupsets/ora_df873524162_s46823_s1  
  16. -rw-r----- 1 oracle oinstall 4294975488 Apr  3 15:07 ./oradata/epps/gmtinv_d07.dbf  
  17. -rw-r----- 1 oracle oinstall 4194312192 Apr  1 22:36 ./oradata/epps/gmtinv_d08.dbf  
  18. -rw-r----- 1 oracle oinstall 4294975488 Apr  3 15:54 ./oradata/epps/gmtinv_x01.dbf  
  19. -rw-r----- 1 oracle oinstall 4294975488 Apr  3 15:57 ./oradata/epps/gmtinv_x02.dbf  
  20. -rw-r----- 1 oracle oinstall 4294975488 Apr  1 22:35 ./oradata/epps/invsubmat_d08.dbf  
  21. -rw-r----- 1 oracle oinstall 8589942784 Apr  4 09:55 ./oradata/epps/undotbs01.dbf  
  22. -rw-r----- 1 oracle oinstall 8589942784 Apr  4 09:15 ./oradata/epps/undotbs02.dbf  

当我们只需要查找超过800M大小文件,并显示查找出来文件的具体大小,可以使用下面命令:

C#代码
  1. [root@getlnx01 u03]# find . -type f -size +800M  -print0 | xargs -0 du -h  
  2. 1.3G    ./flash_recovery_area/backup/backupsets/ora_df873519197_s46815_s1  
  3. 1.1G    ./flash_recovery_area/backup/backupsets/ora_df873523646_s46822_s1  
  4. 1.2G    ./flash_recovery_area/backup/backupsets/ora_df873521714_s46818_s1  
  5. 1.2G    ./flash_recovery_area/backup/backupsets/ora_df873522876_s46820_s1  
  6. 1.5G    ./flash_recovery_area/backup/backupsets/ora_df873517396_s46813_s1  
  7. 1.1G    ./flash_recovery_area/backup/backupsets/ora_df873523321_s46821_s1  
  8. 1.3G    ./flash_recovery_area/backup/backupsets/ora_df873515765_s46811_s1  
  9. 1.6G    ./flash_recovery_area/backup/backupsets/ora_df873520789_s46817_s1  
  10. 1004M   ./flash_recovery_area/backup/backupsets/ora_df873524162_s46823_s1  
  11. 1.6G    ./flash_recovery_area/backup/backupsets/ora_df873518302_s46814_s1  
  12. 1.6G    ./flash_recovery_area/backup/backupsets/ora_df873519953_s46816_s1  
  13. 1.6G    ./flash_recovery_area/backup/backupsets/ora_df873516500_s46812_s1  
  14. 2.6G    ./flash_recovery_area/backup/backupsets/ora_df873513413_s46809_s1  
  15. 1.8G    ./flash_recovery_area/backup/backupsets/ora_df873514789_s46810_s1  
  16. 4.1G    ./oradata/epps/invsubmat_d08.dbf  
  17. 4.0G    ./oradata/epps/gmtinv_d08.dbf  
  18. 4.1G    ./oradata/epps/gmtinv_x01.dbf  
  19. 8.1G    ./oradata/epps/undotbs02.dbf  
  20. 4.1G    ./oradata/epps/gmtinv_d07.dbf  
  21. 8.1G    ./oradata/epps/undotbs01.dbf  
  22. 4.1G    ./oradata/epps/gmtinv_x02.dbf  

如果你还需要对查找结果按照文件大小做一个排序,那么可以使用下面命令:

C#代码
  1. [root@getlnx01 u03]# find . -type f -size +800M  -print0 | xargs -0 du -h | sort -nr  
  2. 1004M   ./flash_recovery_area/backup/backupsets/ora_df873524162_s46823_s1  
  3. 8.1G    ./oradata/epps/undotbs02.dbf  
  4. 8.1G    ./oradata/epps/undotbs01.dbf  
  5. 4.1G    ./oradata/epps/invsubmat_d08.dbf  
  6. 4.1G    ./oradata/epps/gmtinv_x02.dbf  
  7. 4.1G    ./oradata/epps/gmtinv_x01.dbf  
  8. 4.1G    ./oradata/epps/gmtinv_d07.dbf  
  9. 4.0G    ./oradata/epps/gmtinv_d08.dbf  
  10. 2.6G    ./flash_recovery_area/backup/backupsets/ora_df873513413_s46809_s1  
  11. 1.8G    ./flash_recovery_area/backup/backupsets/ora_df873514789_s46810_s1  
  12. 1.6G    ./flash_recovery_area/backup/backupsets/ora_df873520789_s46817_s1  
  13. 1.6G    ./flash_recovery_area/backup/backupsets/ora_df873519953_s46816_s1  
  14. 1.6G    ./flash_recovery_area/backup/backupsets/ora_df873518302_s46814_s1  
  15. 1.6G    ./flash_recovery_area/backup/backupsets/ora_df873516500_s46812_s1  
  16. 1.5G    ./flash_recovery_area/backup/backupsets/ora_df873517396_s46813_s1  
  17. 1.3G    ./flash_recovery_area/backup/backupsets/ora_df873519197_s46815_s1  
  18. 1.3G    ./flash_recovery_area/backup/backupsets/ora_df873515765_s46811_s1  
  19. 1.2G    ./flash_recovery_area/backup/backupsets/ora_df873522876_s46820_s1  
  20. 1.2G    ./flash_recovery_area/backup/backupsets/ora_df873521714_s46818_s1  
  21. 1.1G    ./flash_recovery_area/backup/backupsets/ora_df873523646_s46822_s1  
  22. 1.1G    ./flash_recovery_area/backup/backupsets/ora_df873523321_s46821_s1  

不过如上截图所示,有时候排列的顺序并不完全是按大小一致,这个是因为du命令的参数h所致,你可以统一使用使用MB来显示,这样就能解决这个问题。到这里,这个在Linux系统查找大文件的命令已经非常完美了,当然如果你还有很多的需求,那么可以在这个命令上做修改、调整.

2: 如何查找Linux下的大目录

 

譬如有时候磁盘空间告警了,而你平时又疏于管理、监控文件的增长,那么我需要快速的了解哪些目录变得比较大,那么此时我们可以借助du命令来帮我们解决这个问题。

C#代码
  1. [root@getlnx01 u03]# du -h --max-depth=1  
  2. 16K     ./lost+found  
  3. 33G     ./flash_recovery_area  
  4. 37G     ./oradata  
  5. 70G     .  

如果你想知道flash_recovery_area目录下面有哪些大文件夹,那么可以将参数max-depth=2 ,如果你想对搜索出来的结果进行排序,那么可以借助于sort命令。如下所示

C#代码
  1. [root@getlnx01 u03]# du -h --max-depth=2 | sort -n  
  2. 3.5G    ./flash_recovery_area/EPPS  
  3. 16K     ./lost+found  
  4. 29G     ./flash_recovery_area/backup  
  5. 33G     ./flash_recovery_area  
  6. 37G     ./oradata  
  7. 37G     ./oradata/epps  
  8. 70G     .  
  9. [root@getlnx01 u03]# du -hm --max-depth=2 | sort -n  
  10. 1       ./lost+found  
  11. 3527    ./flash_recovery_area/EPPS  
  12. 29544   ./flash_recovery_area/backup  
  13. 33070   ./flash_recovery_area  
  14. 37705   ./oradata  
  15. 37705   ./oradata/epps  
  16. 70775   .  

[root@getlnx01 u03]# cd /

[root@getlnx01 /]# du -hm --max-depth=2 | sort -n

 

有时候搜索出来的结果太多了(譬如,我从根目录开始搜索),一直在刷屏,如果我只想查出最大的12个文件夹,怎么办呢?此时就要借助head命令来显示了

C#代码
  1. [root@getlnx01 /]# du -hm --max-depth=2 | sort -nr | head -12  
  2. 407480  .  
  3. 167880  ./u04  
  4. 158685  ./u02/oradata  
  5. 158685  ./u02  
  6. 152118  ./u04/oradata  
  7. 70775   ./u03  
  8. 37705   ./u03/oradata  
  9. 33070   ./u03/flash_recovery_area  
  10. 5995    ./u01/app  
  11. 5995    ./u01  
  12. 3551    ./usr  
  13. 1558    ./usr/share  
  14. [root@getlnx01 /]#   

查看具体目录:du -sh  /www/cnmo/

查看整体概况:df -h

Linux Shell 汇总

[不指定 2017/05/03 18:33 | by 刘新修 ]

 1、查看当前操作系统类型

C#代码
  1. #!/bin/sh  
  2. SYSTEM=`uname -s`  
  3. if [ $SYSTEM = "Linux" ] ; then  
  4. echo "Linux"  
  5. elif [ $SYSTEM = "FreeBSD" ] ; then  
  6. echo "FreeBSD"  
  7. elif [ $SYSTEM = "Solaris" ] ; then  
  8. echo "Solaris"  
  9. else  
  10. echo "What?"  
  11. fi  

 

C++代码
  1. hostname  
  2. ############### 最后一次修改的用户 ####################  
  3. cd /www/ftp/ysx/xfile/www  
  4. ls -lh  
  5. ############### 最后一次修改的用户 ####################  
  6. cat /etc/redhat-release  
  7. df -h  
  8. rsync -avzut --progress --delete /www/ftp/ycw/xfile/www/assets liuxinxiu@127.0.0.1::ysx_xfile_www --password-file=/pas/rsync.pas  
  9. rsync -avzut --progress /www/ftp/ycw/xfile/www/json/assets.json liuxinxiu@127.0.0.1::ysx_xfile_www --password-file=/pas/rsync.pas  
  10.   
  11. echo http://ysx.com/xfile/www/json/assets.json  
  12. UNAME=$(cat /www/ftp/ycw/xfile/www/json/assets.json | jq -c .name)  
  13. VERSION=$(cat /www/ftp/ycw/xfile/www/json/assets.json | jq -c .version)  
  14. VERSION=${VERSION//\"/}  
  15. UpdateTime=$(cat /www/ftp/ycw/xfile/www/json/assets.json | jq -c .UpdateTime)  
  16. UpdateTime=${UpdateTime//[[:space:]]/_}  
  17. echo $UNAME  
  18. echo $UpdateTime  
  19. cp /www/ftp/ycw/xfile/www/json/assets.json /www/ftp/back/xfile/www/json/assets-$VERSION-$BUILD_USER_ID-v$BUILD_NUMBER.json  
  20. cd /www/ftp/ycw/xfile/www/ && zip -r -q /www/ftp/back/xfile/www/assets-json-$VERSION-$BUILD_USER_ID-v$BUILD_NUMBER.zip assets json/assets.json  
  21. echo "" > /www/ftp/back/xfile/www/sh/sh-$VERSION.txt  
  22. echo cp /www/ftp/back/xfile/www/json/assets-$VERSION-$BUILD_USER_ID-v$BUILD_NUMBER.json /www/ftp/ysx/xfile/www/json/assets.json >> /www/ftp/back/xfile/www/sh/sh-$VERSION.txt  
  23. echo unzip /www/ftp/back/xfile/www/assets-json-$VERSION-$BUILD_USER_ID-v$BUILD_NUMBER.zip -d /www/ftp/ysx/xfile/www >> /www/ftp/back/xfile/www/sh/sh-$VERSION.txt  

其他版本,不增加平台版本号:

C#代码
  1. hostname  
  2. ############### 最后一次修改的用户 ####################  
  3. cd /www/ftp/ysx/xfile/www  
  4. ls -lh  
  5. ############### 最后一次修改的用户 ####################  
  6. cat /etc/redhat-release  
  7. df -h  
  8. rsync -avzut --progress --delete /www/ftp/ycw/xfile/www/assets liuxinxiu@127.0.0.1::ysx_xfile_www --password-file=/pas/rsync.pas  
  9. rsync -avzut --progress /www/ftp/ycw/xfile/www/json/assets.json liuxinxiu@127.0.0.1::ysx_xfile_www --password-file=/pas/rsync.pas  
  10.   
  11. echo http://ysx.cnmo.me/xfile/www/json/assets.json  
  12. UNAME=$(cat /www/ftp/ycw/xfile/www/json/assets.json | jq -c .name)  
  13. UNAME=${UNAME//\"/}  
  14. VERSION=$(cat /www/ftp/ycw/xfile/www/json/assets.json | jq -c .version)  
  15. VERSION=${VERSION//\"/}  
  16. UpdateTime=$(cat /www/ftp/ycw/xfile/www/json/assets.json | jq -c .UpdateTime)  
  17. UpdateTime=${UpdateTime//[[:space:]]/_}  
  18. UpdateTime=${UpdateTime//\"/}  
  19. cp /www/ftp/ycw/xfile/www/json/assets.json /www/ftp/back/xfile/www/json/assets-$VERSION-$UNAME-$UpdateTime.json  
  20. cd /www/ftp/ycw/xfile/www/ && zip -r -q /www/ftp/back/xfile/www/assets-json-$VERSION-$UNAME-$UpdateTime.zip assets json/assets.json  
  21. echo "" > /www/ftp/back/xfile/www/sh/sh-$VERSION-$UNAME-$UpdateTime.txt  
  22. echo cp /www/ftp/back/xfile/www/json/assets-$VERSION-$UNAME-$UpdateTime.json /www/ftp/ysx/xfile/www/json/assets.json >> /www/ftp/back/xfile/www/sh/sh-$VERSION-$UNAME-$UpdateTime.txt  
  23. echo unzip /www/ftp/back/xfile/www/assets-json-$VERSION-$UNAME-$UpdateTime.zip -d /www/ftp/ysx/xfile/www >> /www/ftp/back/xfile/www/sh/sh-$VERSION-$UNAME-$UpdateTime.txt  

 代码同步超级管理员

C#代码
  1. myPath="/www/ftp/${userName//\"/}"  
  2. ############### 这里的-d 参数判断$myPath是否存在 ###############  
  3. if [ ! -d "$myPath" ] ; then  
  4. echo "这个目录不存在呀!有问题请及时与管理员联系:liu.xinxiu@cnmo.com"  
  5. cat $myPath  
  6. exit  
  7. #else    
  8. #echo "目录存在!"  
  9. fi  
  10. ############### 这里的-d 参数判断$myPath是否存在 ###############  
  11. proName=${projectName//\"/}  
  12. proPath="$myPath/xfile/$proName" 
  13. ysxPath="/www/ftp/ysx/xfile/$proName" 
  14. backPath="/www/ftp/back/xfile/$proName" 
  15.  
  16. hostname 
  17. ############### 最后一次修改的用户 #################### 
  18. cd $proPath 
  19. ls -lh 
  20. ############### 最后一次修改的用户 #################### 
  21. cat /etc/redhat-release 
  22. df -h 
  23.  
  24. ############### 数据同步 #################### 
  25. rsync -avzut --progress --delete $proPath/assets liuxinxiu@127.0.0.1::ysx_xfile_$proName --password-file=/pas/rsync.pas 
  26. cp $proPath/json/assets.json $ysxPath/json/assets.json 
  27. ############### 数据同步 #################### 
  28.  
  29. echo http://ysx.cnmo.me/xfile/$proName/json/assets.json 
  30. UNAME=$(cat $proPath/json/assets.json | jq -c .name) 
  31. UNAME=${UNAME//\"/} 
  32. VERSION=$(cat $proPath/json/assets.json | jq -c .version) 
  33. VERSION=${VERSION//\"/} 
  34. UpdateTime=$(cat $proPath/json/assets.json | jq -c .UpdateTime) 
  35. UpdateTime=${UpdateTime//[[:space:]]/__} 
  36. UpdateTime=${UpdateTime//\:/_} 
  37. UpdateTime=${UpdateTime//\"/} 
  38.  
  39. ############### 数据备份操作 #################### 
  40. cp $proPath/json/assets.json $backPath/json/assets-${VERSION}__${UpdateTime}.json 
  41. cd $proPath/ && zip -r -q $backPath/assets-${VERSION}__${UpdateTime}.zip assets json/assets.json 
  42. echo "" > $backPath/sh/assets-${VERSION}__${UpdateTime}.txt 
  43. echo cp $backPath/json/assets-${VERSION}__${UpdateTime}.json $ysxPath/json/assets.json >> $backPath/sh/assets-${VERSION}__${UpdateTime}.txt 
  44. echo unzip -o $backPath/assets-${VERSION}__${UpdateTime}.zip -d $ysxPath >> $backPath/sh/assets-${VERSION}__${UpdateTime}.txt 
  45. echo sed -i "'"s/,'"addOth"':{/,'"Fallback"':'"'$BUILD_USER_ID-v${ENV, var="BUILD_ID"}'"','"addOth"':{/g"'" $ysxPath/json/assets.json >> $backPath/sh/assets-${VERSION}__${UpdateTime}.txt 
  46. ############### 数据备份操作 #################### 
  47.  
  48.  
  49. ############### 维护回退版本列表 #################### 
  50. versionList="$backPath/versionList.txt" 
  51. if [ ! -f "$versionList" ]; then 
  52.     #touch "$versionList" 
  53.     echo "vlist=assets-${VERSION}__${UpdateTime}" > $backPath/versionList.txt 
  54. else  
  55.     #grep -q "裸照" urfile  && echo "有的"  || echo "没的" 
  56.     grep -q "assets-${VERSION}__${UpdateTime}" $backPath/versionList.txt  && echo "相同代码在备份文件中已经存在,已再次执行了代码同步!您还可以选择代码回滚功能,一键回退指定版本~"  || sed -i "/^vlist.*$/s//& ,assets-${VERSION}__${UpdateTime}/g" $backPath/versionList.txt  
  57. fi  
  58. ############### 维护回退版本列表 ####################  

 

使用npm install -g 'xxx' 之后仍然报
Cannot find module 'xxx' 错误,可以通过设置环境变量来解决;

export NODE_PATH=/usr/local/lib/node_modules/  
echo $NODE_PATH  

Error: Cannot find module 'ftp'

#!/bin/sh  

myPath="/var/log/httpd/"  

myFile="/var /log/httpd/access.log"  

#这里的-x 参数判断$myPath是否存在并且是否具有可执行权限  

if [ ! -x "$myPath"]; then  

  mkdir "$myPath"  

fi  

#这里的-d 参数判断$myPath是否存在  

if [ ! -d "$myPath"]; then  

  mkdir "$myPath"  

fi  

#这里的-f参数判断$myFile是否存在  

if [ ! -f "$myFile" ]; then  

  touch "$myFile"  

fi  

#其他参数还有-n,-n是判断一个变量是否是否有值  

if [ ! -n "$myVar" ]; then  

  echo "$myVar is empty"  

  exit 0  

fi  

#两个变量判断是否相等  

if [ "$var1" = "$var2" ]; then  

  echo '$var1 eq $var2'  

else  

  echo '$var1 not eq $var2'  

fi

CSS HACK整理

[不指定 2017/03/09 10:16 | by 刘新修 ]
.test{
color:#000000; /* FF,OP支持 */
color:#0000FF\9; /* 所有IE浏览器(ie6+)支持 ;但是IE8不能识别“*”和“_”的css hack;所以我们可以这样写hack */
[color:#000000;color:#00FF00; /* SF,CH支持 */
*color:#FFFF00; /* IE7支持 */
_color:#FF0000; /* IE6支持 */
}

 

网上也流传着这样一种ie hack方法

.color1{ color:#F00; color/*\**/:#00F /*\**/}/*IE6,IE7,IE8,FF,OP,SA识别*/
.color2{ color:#F00; color /*\**/:#00F /*\9**/}/*IE7,IE8,FF,OP,SA识别*/
.color3{ color:#F00; color/*\**/:#00F \9}/*IE6,IE7,IE8识别*/
.color4{ color:#F00; color /*\**/:#00F\9}/*IE7,IE8识别*//*“color”和“/*\**/”之间有个空格*/

分析下:
background-color:blue; 各个浏览器都认识,这里给firefox用;
background-color:red\9;\9所有的ie浏览器可识别;
background-color:yellow\0; \0 是留给ie8的,但笔者测试,发现最新版opera也认识,汗。。。不过且慢,后面自有hack写了给opera认的,所以,\0我们就认为是给ie8留的;
+background-color:pink; + ie7定了;
_background-color:orange; _专门留给神奇的ie6;
:root #test { background-color:purple\9; } :root是给ie9的,网上流传了个版本是 :root #test { background-color:purple\0;},呃。。。这个。。。,新版opera也认识,所以经笔者反复验证最终ie9特有的为:root 选择符 {属性\9;}
@media all and (min-width:0px){ #test {background-color:black\0;} } 这个是老是跟ie抢着认\0的神奇的opera,必须加个\0,不然firefox,chrome,safari也都认识。。。
@media screen and (-webkit-min-device-pixel-ratio:0){ #test {background-color:gray;} }最后这个是浏览器新贵chrome和safari的。

好了就这么多了,特别注意以上顺序是不可以改变的。css hack虽然可以解决个浏览器之间css显示的差异问题,但是毕竟不符合W3C规范,我们平时写css最好是按照标准来,这样对我们以后维护也是大有好处的,实在不行再用。

区别不同浏览器的CSS hack写法: 

区别IE6与FF: 
background:orange;*background:blue; 

区别IE6与IE7: 
background:green !important;background:blue; 

区别IE7与FF: 
background:orange; *background:green; 

区别FF,IE7,IE6: 
background:orange;*background:green !important;*background:blue; 

注:IE都能识别*;标准浏览器(如FF)不能识别*;
IE6能识别*,但不能识别 !important, 
IE7能识别*,也能识别!important; 
FF不能识别*,但能识别!important;

 IE6IE7FF
*×
!important×



------------------------------------------------------ 
另外再补充一个,下划线"_", 
IE6支持下划线,IE7和firefox均不支持下划线。

 IE6IE7FF
*×
!important×
_××



于是大家还可以这样来区分IE6,IE7,firefox 
: background:orange;*background:green;_background:blue; 

注:不管是什么方法,书写的顺序都是firefox的写在前面,IE7的写在中间,IE6的写在最后面。

 mysql出现ERROR : (2006, 'MySQL server has gone away') 的问题意思就是指client和MySQL server之间的链接断开了。

造成这样的原因一般是sql操作的时间过长,或者是传送的数据太大(例如使用insert ... values的语句过长, 这种情况可以通过修改max_allowed_packed的配置参数来避免,也可以在程序中将数据分批插入)。

产生这个问题的原因有很多,总结下网上的分析:

原因一. MySQL 服务宕了

判断是否属于这个原因的方法很简单,进入mysql控制台,查看mysql的运行时长

mysql> show global status like 'uptime';
+---------------+---------+
| Variable_name | Value   |
+---------------+---------+
| Uptime        | 3414707 |
+---------------+---------+

1 row in set或者查看MySQL的报错日志,看看有没有重启的信息

如果uptime数值很大,表明mysql服务运行了很久了。说明最近服务没有重启过。
如果日志没有相关信息,也表名mysql服务最近没有重启过,可以继续检查下面几项内容。

原因二. mysql连接超时

即某个mysql长连接很久没有新的请求发起,达到了server端的timeout,被server强行关闭。
此后再通过这个connection发起查询的时候,就会报错server has gone away
(大部分PHP脚本就是属于此类)

mysql> show global variables like '%timeout';
+----------------------------+----------+
| Variable_name              | Value    |
+----------------------------+----------+
| connect_timeout            | 10       |
| delayed_insert_timeout     | 300      |
| innodb_lock_wait_timeout   | 50       |
| innodb_rollback_on_timeout | OFF      |
| interactive_timeout        | 28800    |
| lock_wait_timeout          | 31536000 |
| net_read_timeout           | 30       |
| net_write_timeout          | 60       |
| slave_net_timeout          | 3600     |
| wait_timeout               | 28800    |
+----------------------------+----------+
10 rows in set

wait_timeout 是28800秒,即mysql链接在无操作28800秒后被自动关闭

原因三. mysql请求链接进程被主动kill

这种情况和原因二相似,只是一个是人为一个是MYSQL自己的动作

mysql> show global status like 'com_kill';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Com_kill      | 21    |
+---------------+-------+
1 row in set原因四. Your SQL statement was too large.

当查询的结果集超过 max_allowed_packet 也会出现这样的报错。定位方法是打出相关报错的语句。

用select * into outfile 的方式导出到文件,查看文件大小是否超过 max_allowed_packet ,如果超过则需要调整参数,或者优化语句。

mysql> show global variables like 'max_allowed_packet';
+--------------------+---------+
| Variable_name      | Value   |
+--------------------+---------+
| max_allowed_packet | 1048576 |
+--------------------+---------+
1 row in set (0.00 sec)

修改参数:

mysql> set global max_allowed_packet=1024*1024*16;
mysql> show global variables like 'max_allowed_packet';
+--------------------+----------+
| Variable_name      | Value    |
+--------------------+----------+
| max_allowed_packet | 16777216 |
+--------------------+----------+
1 row in set (0.00 sec)

以下是补充:

应用程序(比如PHP)长时间的执行批量的MYSQL语句。执行一个SQL,但SQL语句过大或者语句中含有BLOB或者longblob字段。比如,图片数据的处理。都容易引起MySQL server has gone away。 

今天遇到类似的情景,MySQL只是冷冷的说:MySQL server has gone away。 

大概浏览了一下,主要可能是因为以下几种原因: 
一种可能是发送的SQL语句太长,以致超过了max_allowed_packet的大小,如果是这种原因,你只要修改my.cnf,加大max_allowed_packet的值即可。 



还有一种可能是因为某些原因导致超时,比如说程序中获取数据库连接时采用了Singleton的做法,虽然多次连接数据库,但其实使用的都是同一个连接,而且程序中某两次操作数据库的间隔时间超过了wait_timeout(SHOW STATUS能看到此设置),那么就可能出现问题。最简单的处理方式就是把wait_timeout改大,当然你也可以在程序里时不时顺手mysql_ping()一下,这样MySQL就知道它不是一个人在战斗。 

解决MySQL server has gone away 

1、应用程序(比如PHP)长时间的执行批量的MYSQL语句。最常见的就是采集或者新旧数据转化。 
解决方案: 
在my.cnf文件中添加或者修改以下两个变量: 
wait_timeout=2880000 
interactive_timeout = 2880000 
关于两个变量的具体说明可以google或者看官方手册。如果不能修改my.cnf,则可以在连接数据库的时候设置CLIENT_INTERACTIVE,比如: 
sql = "set interactive_timeout=24*3600"; 
mysql_real_query(...) 


2、执行一个SQL,但SQL语句过大或者语句中含有BLOB或者longblob字段。比如,图片数据的处理 
解决方案: 
在my.cnf文件中添加或者修改以下变量: 
max_allowed_packet = 10M(也可以设置自己需要的大小) 
max_allowed_packet 参数的作用是,用来控制其通信缓冲区的最大长度。 


最近做网站有一个站要用到WEB网页采集器功能,当一个PHP脚本在请求URL的时候,可能这个被请求的网页非常慢慢,超过了mysql的 wait-timeout时间,然后当网页内容被抓回来后,准备插入到MySQL的时候,发现MySQL的连接超时关闭了,于是就出现了“MySQL server has gone away”这样的错误提示,解决这个问题,我的经验有以下两点,或许对大家有用处: 
第 一种方法: 
当然是增加你的 wait-timeout值,这个参数是在my.cnf(在Windows下台下面是my.ini)中设置,我的数据库负荷稍微大一点,所以,我设置的值 为10,(这个值的单位是秒,意思是当一个数据库连接在10秒钟内没有任何操作的话,就会强行关闭,我使用的不是永久链接 (mysql_pconnect),用的是mysql_connect,关于这个wait-timeout的效果你可以在MySQL的进程列表中看到 (show processlist) ),你可以把这个wait-timeout设置成更大,比如300秒,呵呵,一般来讲300秒足够用了,其实你也可以不用设置,MySQL默认是8个小 时。情况由你的服务器和站点来定。 
第二种方法: 
这也是我个人认为最好的方法,即检查 MySQL的链接状态,使其重新链接。 
可能大家都知道有mysql_ping这么一个函数,在很多资料中都说这个mysql_ping的 API会检查数据库是否链接,如果是断开的话会尝试重新连接,但在我的测试过程中发现事实并不是这样子的,是有条件的,必须要通过 mysql_options这个C API传递相关参数,让MYSQL有断开自动链接的选项(MySQL默认为不自动连接),但我测试中发现PHP的MySQL的API中并不带这个函数,你重新编辑MySQL吧,呵呵。但mysql_ping这个函数还是终于能用得上的,只是要在其中有一个小小的操作技巧: 
这是我的的数据库操 作类中间的一个函数 

 V8 引擎概览

 
Google V8 引擎使用 C++ 代码编写,实现了 ECMAScript 规范的第五版,可以运行在所有的主流
 
操作系统中,甚至可以运行在移动终端 ( 基于 ARM 的处理器,如 HTC G7 等 )。V8 最早被开发用以嵌入到 Google 的开源浏览器 Chrome 中,但是 V8 是一个可以独立的模块,完全可以嵌入您自己的应用,著名的 Node.js( 一个异步的服务器框架,可以在服务端使用 JavaScript 写出搞笑的网络服务器 ) 就是基于 V8 引擎的。
 
和其他 JavaScript 引擎一样,V8 会编译 / 执行 JavaScript 代码,管理内存,负责垃圾回收,与宿主语言的交互等。V8 的垃圾回收器采用了众多技术,使得其运行效率大大提高。通过暴露宿主对象 ( 变量,函数等 ) 到 JavaScript,JavaScript 可以访问宿主环境中的对象,并在脚本中完成对宿主对象的操作。
 
V8 引擎基本概念
 
图 1. V8 引擎基本概念关系图 ( 根据 Google V8 官方文档 ) 
handle
 
handle 是指向对象的指针,在 V8 中,所有的对象都通过 handle 来引用,handle 主要用于 V8 的垃圾回收机制。
 
在 V8 中,handle 分为两种:持久化 (Persistent)handle 和本地 (Local)handle,持久化 handle 存放在堆上,而本地 handle 存放在栈上。这个与 C/C++ 中的堆和栈的意义相同 ( 简而言之,堆上的空间需要开发人员自己申请,使用完成之后显式的释放;而栈上的为自动变量,在退出函数 / 方法之后自动被释放 )。持久化 handle 与本地 handle 都是 Handle 的子类。在 V8 中,所有数据访问均需要通过 handle。需要注意的是,使用持久化 handle 之后,需要显式的调用 Dispose() 来通知垃圾回收机制。
 
作用域 (scope)
 
scope 是 handle 的集合,可以包含若干个 handle,这样就无需将每个 handle 逐次释放,而是直接释放整个 scope。
 
在使用本地 handle 时,需要声明一个 HandleScope 的实例,scope 是 handle 的容器,使用 scope,则无需依次释放 handle。
 
 HandleScope handle_scope; 
 Local<ObjectTemplate> temp; 
 
上下文 (context)
 
context 是一个执行器环境,使用 context 可以将相互分离的 JavaScript 脚本在同一个 V8 实例中运行,而互不干涉。在运行 JavaScript 脚本是,需要显式的指定 context 对象。
 
数据及模板
 
由于 C++ 原生数据类型与 JavaScript 中数据类型有很大差异,因此 V8 提供了 Data 类,从 JavaScript 到 C++,从 C++ 到 JavaScrpt 都会用到这个类及其子类,比如:
 
 Handle<Value> Add(const Arguments& args){ 
   int a = args[0]->Uint32Value(); 
   int b = args[1]->Uint32Value(); 
 
   return Integer::New(a+b); 
 } 
 
Integer 即为 Data 的一个子类。
 
V8 中,有两个模板 (Template) 类 ( 并非 C++ 中的模板类 ):对象模板 (ObjectTempalte) 和函数模板 (FunctionTemplate),这两个模板类用以定义 JavaScript 对象和 JavaScript 函数。我们在后续的小节部分将会接触到模板类的实例。通过使用 ObjectTemplate,可以将 C++ 中的对象暴露给脚本环境,类似的,FunctionTemplate 用以将 C++ 函数暴露给脚本环境,以供脚本使用。
 
初始化 context 是使用 V8 引擎所必需的过程,代码非常简单:
 
 Persistent<Context> context = Context::New(); 
V8 引擎使用示例
 
有了上面所述的基本概念之后,我们来看一下一个使用 V8 引擎的应用程序的基本流程:
 
创建 HandleScope 实例
创建一个持久化的 Context
进入 Context
创建脚本字符串
创建 Script 对象,通过 Script::Compile()
执行脚本对象的 Run 方法
获取 / 处理结果
显式的调用 Context 的 Dispose 方法
基本代码模板
 
 
清单 1. 代码模块 
        
 #include <v8.h> 
 
 using namespace v8; 
 
 int main(int argc, char *argv[]) { 
   // 创建一个句柄作用域 ( 在栈上 ) 
   HandleScope handle_scope; 
 
   // 创建一个新的上下文对象
   Persistent<Context> context = Context::New(); 
 
   // 进入上一步创建的上下文,用于编译执行 helloworld 
   Context::Scope context_scope(context); 
 
   // 创建一个字符串对象,值为'Hello, Wrold!', 字符串对象被 JS 引擎
   // 求值后,结果为'Hello, World!'
   Handle<String> source = String::New("'Hello' + ', World!'"); 
 
   // 编译字符串对象为脚本对象
   Handle<Script> script = Script::Compile(source); 
 
   // 执行脚本,获取结果
   Handle <Value> result = script->Run(); 
 
   // 释放上下文资源
   context.Dispose(); 
 
   // 转换结果为字符串
   String::AsciiValue ascii(result); 
 
   printf("%s\n", *ascii); 
 
   return 0; 
 } 
 
以上代码为一个使用 V8 引擎来运行脚本的基本模板,可以看到,开发人员可以很容易的在自己的代码中嵌入 V8 来处理 JavaScript 脚本。我们在下面小节中详细讨论如何在脚本中访问 C++ 资源。
 
使用 C++ 变量
 
在 JavaScript 与 V8 间共享变量事实上是非常容易的,基本模板如下:
 
 
清单 2. 共享变量 
        
 static type xxx; 
 
 static Handle<Value> xxxGetter( 
   Local<String> name, 
   const AccessorInfo& info){ 
 
   //code about get xxx 
 } 
 
 static void xxxSetter( 
   Local<String> name, 
   Local<Value> value, 
   const AccessorInfo& info){ 
 
   //code about set xxx 
 } 
 
首先在 C++ 中定义数据,并以约定的方式定义 getter/setter 函数,然后需要将 getter/setter 通过下列机制公开给脚本:
 
 global->SetAccessor(String::New("xxx"), xxxGetter, xxxSetter); 
 
其中,global 对象为一个全局对象的模板:
 
 Handle<ObjectTemplate> global = ObjectTemplate::New(); 
 
下面我们来看一个实例:
 
 
清单 3. 实例 1 
        
 static char sname[512] = {0}; 
 
 static Handle<Value> NameGetter(Local<String> name, 
     const AccessorInfo& info) { 
   return String::New((char*)&sname,strlen((char*)&sname)); 
 } 
 
 static void NameSetter(Local<String> name, 
     Local<Value> value, 
     const AccessorInfo& info) { 
   Local<String> str = value->ToString(); 
   str->WriteAscii((char*)&sname); 
 } 
 
定义了 NameGetter, NameSetter 之后,在 main 函数中,将其注册在 global 上:
 
 // Create a template for the global object. 
 Handle<ObjectTemplate> global = ObjectTemplate::New(); 
 
 //public the name variable to script 
 global->SetAccessor(String::New("name"), NameGetter, NameSetter); 
 
在 C++ 中,将 sname 的值设置为”cpp”:
 
 //set sname to "cpp" in cpp program 
 strncpy(sname, "cpp", sizeof(sname)); 
 
然后在 JavaScript 中访问该变量,并修改:
 
 print(name); 
 
 //set the variable `name` to "js"
 name='js'; 
 print(name); 
 
运行结果如下:
 
 cpp 
 js 
 
运行脚本,第一个 print 调用会打印在 C++ 代码中设置的 name 变量的值:cpp,然后我们在脚本中修改 name 值为:js,再次调用 print 函数则打印出设置后的值:js。
 
调用 C++ 函数
 
在 JavaScript 中调用 C++ 函数是脚本化最常见的方式,通过使用 C++ 函数,可以极大程度的增强 JavaScript 脚本的能力,如文件读写,网络 / 数据库访问,图形 / 图像处理等等,而在 V8 中,调用 C++ 函数也非常的方便。
 
在 C++ 代码中,定义以下原型的函数:
 
 Handle<Value> function(constArguments& args){ 
   //return something 
 } 
 
然后,再将其公开给脚本:
 
 global->Set(String::New("function"),FunctionTemplate::New(function)); 
 
同样,我们来看两个示例:
 
 
清单 4. 实例 2 
        
 Handle<Value> Add(const Arguments& args){ 
   int a = args[0]->Uint32Value(); 
   int b = args[1]->Uint32Value(); 
 
   return Integer::New(a+b); 
 } 
 
 Handle<Value> Print(const Arguments& args) { 
   bool first = true; 
   for (int i = 0; i < args.Length(); i++) { 
     HandleScope handle_scope; 
     if (first) { 
       first = false; 
     } else { 
       printf(" "); 
    
     String::Utf8Value str(args[i]); 
     const char* cstr = ToCString(str); 
     printf("%s", cstr); 
  
   printf("\n"); 
   fflush(stdout); 
   return Undefined(); 
 } 
 
函数 Add 将两个参数相加,并返回和。函数 Print 接受任意多个参数,然后将参数转换为字符串输出,最后输出换行。
 
 global->Set(String::New("print"), FunctionTemplate::New(Print)); 
 global->Set(String::New("add"), FunctionTemplate::New(Add)); 
 
我们定义以下脚本:
 
 var x = (function(a, b){ 
   return a + b;   
 })(12, 7); 
 
 print(x); 
 
 //invoke function add defined in cpp 
 var y = add(43, 9); 
 print(y); 
 
运行结果如下:
 
 19 
 52 
 
使用 C++ 类
 
如果从面向对象的视角来分析,最合理的方式是将 C++ 类公开给 JavaScript,这样可以将 JavaScript 内置的对象数量大大增加,从而尽可能少的使用宿主语言,而更大的利用动态语言的灵活性和扩展性。事实上,C++ 语言概念众多,内容繁复,学习曲线较 JavaScript 远为陡峭。最好的应用场景是:既有脚本语言的灵活性,又有 C/C++ 等系统语言的效率。使用 V8 引擎,可以很方便的将 C++ 类”包装”成可供 JavaScript 使用的资源。
 
我们这里举一个较为简单的例子,定义一个 Person 类,然后将这个类包装并暴露给 JavaScript 脚本,在脚本中新建 Person 类的对象,使用 Person 对象的方法。
 
首先,我们在 C++ 中定义好类 Person:
 
 
清单 5. 定义类 
        
 class Person { 
 private: 
   unsigned int age; 
   char name[512]; 
 
 public: 
   Person(unsigned int age, char *name) { 
     this->age = age; 
     strncpy(this->name, name, sizeof(this->name)); 
  
 
   unsigned int getAge() { 
     return this->age; 
  
 
   void setAge(unsigned int nage) { 
     this->age = nage; 
  
 
   char *getName() { 
     return this->name; 
  
 
   void setName(char *nname) { 
     strncpy(this->name, nname, sizeof(this->name)); 
  
 }; 
 
Person 类的结构很简单,只包含两个字段 age 和 name,并定义了各自的 getter/setter. 然后我们来定义构造器的包装:
 
 Handle<Value> PersonConstructor(const Arguments& args){ 
   Handle<Object> object = args.This(); 
   HandleScope handle_scope; 
   int age = args[0]->Uint32Value(); 
 
   String::Utf8Value str(args[1]); 
   char* name = ToCString(str); 
 
   Person *person = new Person(age, name); 
   object->SetInternalField(0, External::New(person)); 
   return object; 
 } 
 
从函数原型上可以看出,构造器的包装与上一小节中,函数的包装是一致的,因为构造函数在 V8 看来,也是一个函数。需要注意的是,从 args 中获取参数并转换为合适的类型之后,我们根据此参数来调用 Person 类实际的构造函数,并将其设置在 object 的内部字段中。紧接着,我们需要包装 Person 类的 getter/setter:
 
 Handle<Value> PersonGetAge(const Arguments& args){ 
   Local<Object> self = args.Holder(); 
   Local<External> wrap = Local<External>::Cast(self->GetInternalField(0)); 
 
   void *ptr = wrap->Value(); 
 
   return Integer::New(static_cast<Person*>(ptr)->getAge()); 
 } 
 
 Handle<Value> PersonSetAge(const Arguments& args) 
 { 
   Local<Object> self = args.Holder(); 
   Local<External> wrap = Local<External>::Cast(self->GetInternalField(0)); 
 
   void* ptr = wrap->Value(); 
 
   static_cast<Person*>(ptr)->setAge(args[0]->Uint32Value()); 
   return Undefined(); 
 } 
 
而 getName 和 setName 的与上例类似。在对函数包装完成之后,需要将 Person 类暴露给脚本环境:
 
首先,创建一个新的函数模板,将其与字符串”Person”绑定,并放入 global:
 
 Handle<FunctionTemplate> person_template = FunctionTemplate::New(PersonConstructor); 
 person_template->SetClassName(String::New("Person")); 
 global->Set(String::New("Person"), person_template); 
 
然后定义原型模板:
 
 Handle<ObjectTemplate> person_proto = person_template->PrototypeTemplate(); 
 
 person_proto->Set("getAge", FunctionTemplate::New(PersonGetAge)); 
 person_proto->Set("setAge", FunctionTemplate::New(PersonSetAge)); 
 
 person_proto->Set("getName", FunctionTemplate::New(PersonGetName)); 
 person_proto->Set("setName", FunctionTemplate::New(PersonSetName)); 
 
最后设置实例模板:
 
 Handle<ObjectTemplate> person_inst = person_template->InstanceTemplate(); 
 person_inst->SetInternalFieldCount(1); 
 
随后,创建一个用以测试的脚本:
 
 //global function to print out detail info of person 
 function printPerson(person){ 
    print(person.getAge()+":"+person.getName()); 
 } 
 
 //new a person object 
 var person = new Person(26, "juntao"); 
 
 //print it out 
 printPerson(person); 
 
 //set new value 
 person.setAge(28); 
 person.setName("juntao.qiu"); 
 
 //print it out 
 printPerson(person); 
 
运行得到以下结果:
 
 26:juntao 
 28:juntao.qiu 
简单示例
 
在这一小节中,我们将编写一个简单的桌面计算器:表达式求值部分通过 V8 引擎来进行,而流程控制部分则放在 C++ 代码中,这样可以将表达式解析等复杂细节绕开。同时,我们还得到了一个额外的好处,用户在脚本中可以自定义函数,从而可以在计算器中定义自己的运算规则。
 
桌上计算器
 
计算器程序首先进入一个 MainLoop,从标准输入读取一行命令,然后调用 V8 引擎去求值,然后将结果打印到控制台,然后再进入循环:
 
 
清单 6. 桌面计算器示例 
        
 void MainLoop(Handle<Context> context) { 
   while(true) { 
     char buffer[1024] = {0}; 
     printf("$ "); 
     char *str = fgets(buffer, sizeof(buffer), stdin); 
     if(str == NULL) { 
       break; 
    
     HandleScope handle_scope; 
     ExecuteString(String::New(str), String::New("calc"), true); 
  
 } 
 
在 main 函数中设置全局对象,创建上下文对象,并进入 MainLoop:
 
 int main(int argc, char *argv[]){ 
   HandleScope handle_scope; 
 
   // Create a template for the global object. 
   Handle<ObjectTemplate> global = ObjectTemplate::New(); 
 
   // Expose the local functions to script 
   global->Set(String::New("load"), FunctionTemplate::New(Load)); 
   global->Set(String::New("print"), FunctionTemplate::New(Print)); 
   global->Set(String::New("quit"), FunctionTemplate::New(Quit)); 
 
   // Create a new execution environment containing the built-in 
   // functions 
   Handle<Context> context = Context::New(NULL, global); 
 
   // Enter the newly created execution environment. 
   Context::Scope context_scope(context); 
 
   // Enter main loop 
   MainLoop(context); 
 
   V8::Dispose(); 
 
 
   return 0; 
 } 
 
在 main 函数中,为脚本提供了三个函数,load 函数用以将用户指定的脚本加载进来,并放入全局的上下文中一边引用,print 函数用以打印结果,而 quit 提供用户退出计算器的功能。
 
测试一下:
 
 $ 1+2 
 3 
 
 $ (10+3)/(9.0-5) 
 3.25 
 
 $ typeof print 
 function 
 
 $ typeof non 
 undefined 
 
 // 自定义函数
 $ function add(a, b){return a+b;} 
 $ add(999, 2323) 
 3322 
 
 // 查看 print 标识符的内容
 $ print 
 function print() { [native code] } 
 
load 函数提供了用户自定义函数的功能,将脚本文件作为一个字符串加载到内存,然后对该字符串编译,求值,并将处理过的脚本对象放入当前 context 中,以便用户使用。
 
 Handle<Value> Load(const Arguments& args){ 
   if(args.Length() != 1){ 
     return Undefined(); 
  
 
   HandleScope handle_scope; 
   String::Utf8Value file(args[0]); 
 
   Handle<String> source = ReadFile(*file); 
   ExecuteString(source, String::New(*file), false); 
 
   return Undefined(); 
 } 
 
而 ExecuteString 函数,负责将字符串编译运行:
 
 bool ExecuteString(Handle<String> source, 
           Handle<Value> name, 
           bool print_result) 
 { 
   HandleScope handle_scope; 
   TryCatch try_catch; 
   Handle<Script> script = Script::Compile(source, name); 
   if (script.IsEmpty()) { 
     return false; 
   } else { 
     Handle<Value> result = script->Run(); 
     if (result.IsEmpty()) { 
       return false; 
     } else { 
       if (print_result && !result->IsUndefined()) { 
         String::Utf8Value str(result); 
         const char* cstr = ToCString(str); 
         printf("%s\n", cstr); 
      
       return true; 
    
  
 } 
 
将下列内容存入一个文本文件,并命令为 calc.js:
 
 function sum(){ 
   var s = 0; 
   for(var i = 0; i < arguments.length; i++){ 
     s += arguments[i]; 
  
   return s; 
 } 
 
 function avg(){ 
   var args = arguments; 
   var count = args.length; 
   var sum = 0; 
   for(var i = 0; i < count; i++){ 
     sum += args[i]; 
  
   return sum/count; 
 } 
 
然后在计算器中测试:
 
 // 此时 sum 符号位定义
 $ typeof sum 
 undefined 
 
 // 加载文件,并求值
 $ load("calc.js") 
 
 // 可以看到,sum 的类型为函数
 $ typeof sum 
 function 
 
 $ sum(1,2,3,4,5,6,7,8,9) 
 45 
结束语
 
使用 V8 引擎,可以轻松的将脚本的好处带进 C++ 应用,使得 C++ 应用更具灵活性,扩展性。我们在文中讨论了基本的模板,如何使用 C++ 变量,函数,以及类。最后的实例中给出了一个计算器的原型。由于 V8 的设计原则,开发人员可以快速的将其嵌入到自己的应用中,并且无需太过担心脚本语言的执行效率。
第一页 上页 1 2 3 4 5 6 7 8 9 10 下页 最后页 [ 显示模式: 摘要 | 列表 ]