我的U盘是跟钥匙系一起的,最近两次因为U盘插在公司机器上下班后忘了拿,结果回家后在门口游荡,郁闷的等室友回来才有家门进,于是要做这么个东西,关机前检测到没拔U盘,要猛叫猛叫。 原理倒是不复杂,研究了下,检测U盘可以读取/proc/bus/usb/devices,如果主机上插有U盘,会出现Driver=usb-storage这一行的。 *Update: * /proc/bus/usb/devices只有在挂载了usbfs才有; usbutils工具里面除了lsusb,还提供了usb-devices工具,列出内容跟/proc/bus/usb/devices是一样的, 更适合。 然后是关机脚本的运行。Linux关机时候会执行level 0的init脚本,比如对于Debian/Ubuntu,就是/etc/rc0.d下的文件,我工作机跑的是Archlinux,专门为用户自定命令提供了/etc/rc.local.shutdown文件,作为/etc/rc.shutdown的hook,前者不会因为initscripts包的升级安装被覆盖。 至于让主机会叫,当然是主机喇叭了,这里可没有外放音箱。查了下发现beep这个程序,安装后发现功能还不少,可以定制beep的音调,时长等,可玩性很高。于是先找了音谱频率对照表,按把美剧《24小时》里面CTU内常用的电话铃声谱了出来,大概是EEGC 或者 EEC^C的样子,不过因为主板蜂鸣器的结构区别,通常不同频率的音量有些不同。 另外当然也应该有点视觉提示啦,在init script里面,终端支持的东西多着呢,按终端颜色代码,让终端打印红色加粗闪烁体,足够显眼了。 最终效果是这样的: 1 2 3 4 5 6 7 8 9 10 #!/bin/bash # # /etc/rc.local.shutdown: Local shutdown script. # while [[ `usb-devices | grep usb-storage` ]]; do echo -e "\033[31;1;5m!!!!!! Unplug Your USB Driver or I'll Keep SCREAMING !!!!!!! \033[0m" [...]
ssh连接远程主机时候询问密码,跟su、sudo命令的默认行为一样,是不从stdin读入数据的,据称是为安全考虑,但是有时候在脚本当中确实需要无人守值的登陆。 搜索一下不难找到类似的例子,使用expect来完成密码应答: 1 2 3 4 5 6 7 8 9 10 #!/bin/bash auto_login_ssh () { expect -c "set timeout -1; spawn -noecho ssh -o StrictHostKeyChecking=no $2 ${@:3}; expect *assword:*; send -- $1\r; interact;"; } auto_login_ssh passwd user@host StrictHostKeyChecking=no参数让ssh默认添加新主机的公钥指纹,也就不会出现出现是否继续yes/no的提示了。 expect很不错,上述代码基本可以达到要求了,能够当翻墙用的ssh -D自动登陆,执行远程命令等等,但是如果作为一个完全非交互的远程工具,应该说还一差,不能返回整个连接执行过程是否成功。 使用expect后,程序的exit status是expect的,而不是ssh的,所以如果遇上连接不到的主机、密码错误等情况,expect也一样是正常退出,$?为0,所以需要对expect的代码稍加修改; 1 2 3 4 5 6 7 8 9 10 11 [...]
整系统的备份,应该很多人会想起Ghost,其实开源界有其相应的实现,比如CloneZilla、Partimage,或者原始点的dd,对备份Linux来说,这些Linux原生的工具显然要比需要DOS/WinPE环境的Ghost要更加“原汁原味”,而且开源版的工具功能一点也不少,一样可以网络传输等,而且支持多种格式(或者说格式无关,dd),不过本文关注的,是一个更加原始的方法,tar。 tar的历史都好几十年了,它的用法没有改变,而且相信未来很几十年内都不会变,而且作为一个日常常用的压缩解压工具,很多人都可以对它自如控制。其实,tar是很好的系统备份/迁移工具,它抽象于文件系统,不管是从ext迁移到reiserfs,从普通文件系统到LVM,还是到RAID,比起上述的那些影像工具,tar可以说是最胜任的迁移工具。 其实Ubuntu的社区文档BackupYourSystem/TAR有详细的解析和介绍,我在这里抄录一些重点,不做过多解释,看命令: 创建备份: cd / tar -cvpzf backup.tar.gz --exclude=/backup.tar.gz --exclude=/lost+found --exclude=/proc/* --exclude=/sys/* --exclude=/mnt/* --exclude=/media/* --exclude=/dev/* / 恢复备份: tar -xvpzf /home/test/backup.tar.gz -C / 通过网络接收备份并恢复: nc -l -p 1024 | tar -xvpjf - -C /mnt/disk 或者:(这个就不用nc了,也就不需要下面那行,但是要开sshd) ssh user@host cat backfile.tar.gz |tar -xvpzf - -C /mnt/disk 通过网络发送备份: cat backup.tar.gz | nc -q 0 192.168.1.x 1024 通过网络发送备份成文件等,按需自由配置。 【这里用的nc是netcat工具,提供稳定的后台网络连接;另外archlinux下默认安装的gnu-netcat不支持-q参数,意为管道传输完后退出,一般在发送方配置,如果省了,可以人工Ctrl+C结束之】 [...]
快捷键打开关闭:Project (P):给.vimrc添加 nmap <silent> <Leader>P <Plug>ToggleProject 项目信息记录在~/.vimprojects Project窗口可直接编辑,添加删除完全跟vim编辑文件一致: 删除项目:zm折叠全部,光标移动到项目行,dd。 在Project窗口,对光标文件名按Return(Enter),即在右窗口打开该文件; 水平分割右窗口,增加打开该文件; 在右边窗口打开文件,同时水平打开一新窗口(跟help描述不符!!) 如果安装有miniBufExplorer插件,当打开超过一个文件,顶部出现一个MiniBufExplorer,相当于tab,在相应位置按即可在右窗口打开该文件;至于关闭,按d就是。按在该窗口内按<Tab>、<S-Tab>可以前后选中各个文件。可用tabbar插件替代,增加了Alt+1,2,3 或者ctrl+tab这样切换各个标签。 以下命令,大写为递归作用。 \r \R 更新项目 \c \C 创建项目 \w \W 删除文件 \g \G 搜索文件 vim-project的Help,中文版翻译:http://www.cppblog.com/DrMagic/archive/2007/11/19/36964.html (发现部分特性跟Help描述不符,可能vim版本问题) 另外一篇实用手记:http://lebenbeck.blogspot.com/2009/01/vim-project-plugin.html PS: g G搜索功能是按quickfix list返回的,quickfix用法速记(quicklist本来作用是记录编译器出错的信息,以下的“错误”指找到的文本): :cc 显示当前错误 :cl[ist] 显示列表 :cN[ext] next :cp[revious] previous :cr[ewind] 【num】 调到某错误 :cope[n] 打开错误窗口 :ccl[ose] 关闭错误窗口 另有Location List,作用跟用法完全一样,只是命令的开头字母c换成l。
此前文章《最简单方法远程调试Python多进程子程序》利用了Unix管道文件以及简单的bash来配合调试多进程子程序,但也因此没法跨平台支持windows下的子进程调试,这次简单使用socket接口写了个模块,利用类文件对象传给Pdb的构造,因此不仅可以跨平台,甚至跨机器,跨网络调试都没问题(通常不会这么BT的)。 使用方法,用回之前的例子: 先在终端运行调试服务端: python -c "import rm_pdb; rm_pdb.server()" 在另外的终端运行这个文件: multiproces_debug.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #!/usr/bin/python import multiprocessing import pdb import rm_pdb def child_process(): print "Child-Process" rm_pdb.pdb().set_trace() var = "debug me!" def main_process(): print "Parent-Process" p [...]
Python 2.6新增的multiprocessing,即多进程,给子进程代码调试有点困难,比如python自带的pdb如果直接在子进程代码里面启动会抛出一堆异常,原因是子进程的stdin/out/err等文件都已关闭,pdb无法调用。据闻winpdb、Wing IDE的调试器能够支持这样的远程调试,但似乎过于重量级(好吧前者比后者要轻多了,但一样要wxPython的环境,再说pdb的灵活可靠它们难以比拟)。 其实只需稍作改动即可用pdb继续调试子进程的代码,思路来自这个博客:子进程的stdin/out/err关闭了,那可以自己重新按/dev/stdout的名称打开来用。当然这指*nix下,win下要麻烦一些,后面再说。 pdb支持自定义输出输入的文件,我再稍作改动,使用fifo管道(Named Pipe)来完成pdb的输出输入的重定向,这样的好处是,可以同时对父子进程调试! multiproces_debug.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #!/usr/bin/python import multiprocessing import pdb def child_process(): print "Child-Process" pdb.Pdb(stdin=open('p_in', 'r+'), stdout=open('p_out', 'w+')).set_trace() var = "debug me!" def main_process(): print "Parent-Process" p = multiprocessing.Process(target = [...]
这篇笔记相对Python来说,有点底层,先来解释几个名词: C-Python: 或者CPython,指C实现的Python虚拟机的基础API。最通用的Python就是是基于C实现的,它的底层API称为C-Python API,所有Python代码的最终变成这些API以及数据结构的调用,才有了Python世界的精彩; Cython:准确说Cython是单独的一门语言,专门用来写在Python里面import用的扩展库。实际上Cython的语法基本上跟Python一致,而Cython有专门的“编译器”先将Cython代码转变成C(自动加入了一大堆的C-Python API),然后使用C编译器编译出最终的Python可调用的模块。 GIL:Global Interpreter Lock,是Python虚拟机的多线程机制的核心机制,翻译为:全局解释器锁。其实Python线程是操作系统级别的线程,在不同平台有不同的底层实现(如win下就用win32_thread, posix下就用pthread等),Python解释器为了使所有对象的操作是线程安全的,使用了一个全局锁(GIL)来同步所有的线程,所以造成“一个时刻只有一个Python线程运行”的伪线程假象。GIL是个颗粒度很大的锁,它的实现跟性能问题多年来也引起过争议,但到今天它还是经受起了考验,即使它让Python在多核平台下CPU得不到最大发挥。 GIL的作用很简单,任何一个线程除非获得锁,否则都在睡眠,而如果获得锁的线程一刻不释放锁,别的线程就永远睡眠下去。对于纯Python线程,这个问题不大,Python代码会通过解释器实时转换成微指令,而解释器给他们算着,每个线程执行了一定的指令数后就要把机会让给别的线程。这个过程中操作系统的调度作用比较微妙,不管操作系统怎么调度,即使把有锁线程挂起到后台,尝试唤醒没锁的,解释器也不给他任何执行机会,所以Python对象很安全。 所以一般来说,做纯Python的编程不需要考虑到GIL,它们是不同层面的东西,但是模块级别的C-Python、Cython等C层面的代码,跟Python虚拟机是平起平坐的,所以GIL很可能需要考虑,特别那些代码涉及IO阻塞、长时间运算、休眠等情况的时候(否则整个Python都在等这个耗时操作的返回,因为他们没获得锁,急也没办法)。 想体现这个过程,很简单,考虑下面的代码,一段纯Python和一段纯C的循环,每次print一段文字就睡眠一秒。 1 2 3 4 5 6 7 void _c_loop ( void ) { while(1) { printf("Print from C loop\n"); sleep(1); } } 1 2 3 4 def _py_loop(): while True: print "Print from Python loop" time.sleep(1) 先不管他们是如何揉合到同一Python进程里面,两个进程分别执行了这两个函数后,他们应该以大概相互间隔着输出文字;但实际情况是,Print from Python loop这句出现了一次之后(先启动了纯Python线程,否则它连启动的机会都没),剩下的输出全都是Print from C [...]
Update 2010.1.5: 其实研究ffmpeg不用找什么教程,第一步应该是下载ffmpeg的源码包。下面提到的An FFmpeg and SDL Tutorial确实有讲解,但是教程总是跟不上代码的变化的,所以直接看可工作代码最好;ffmpeg的结构很分明,后台是几个库:libxxx,前台是三个程序ffmpeg, ffplay, ffserver,那篇教程说的就是ffplay的实现。一个播放器,其实重点不是解码,解码的东西是lib去做的,主要是做声音视频的时钟同步。ffplay的代码可以说是一个可用播放器最简单的实现了,源码里面有个output_example.c,可以说是最基本的api示范吧。ffmpeg是转换编码解码转换程序,因为涉及重新采样等等,所以代码量也不少的。 这两天"调研"了下ffmpeg的API,不得不承认被雷倒:ffmpeg又是一个很geek的项目,纯社区开发,基于逆向,功能强大,但是文档极度有限,想了解API?看源码去…… 网上关于ffmpeg API的资料,无非是ffmpeg文档里面的两个链接,Using libavformat and libavcodec byMartin Böhme(以及其Update,介绍了新引入的API)跟An FFmpeg and SDL Tutorialby Stephen Dranger;两个tutorial基于ffmpeg 0.4.8,现在ffmpeg发布的版本是0.5.0,好像数值相差不大,不过0.4.8是5年前的了(相比之下wine用了15年版本号才到达1.0,有过之余无不及),两个教程里面的代码在0.5.0下一编译,哇,一堆错误,可不仅有些api函数变了,有些结构成员压根就没了,头文件的位置更是不一样(各个库分家了)……所以我调试了好几个小时,终于把例子的代码弄好(其实Martin Böhme那篇有一段09年加入的更新说明,链接了有相关的解决办法,我一开始没注意,几个小时自己解决,不过也有收获)。 最后我调试好的代码流程:打开一个视频文件,抓取前5帧保存为文件;【基于Stephen Dranger的Tutorial1】源码在此:GoogleCode av_register_all();//初始化ffmpeg库,如果系统里面的ffmpeg没配置好这里会出错 av_open_input_file(); av_find_stream_info();//查找文件的流信息 dump_format();//dump只是个调试函数,输出文件的音、视频流的基本信息了,帧率、分辨率、音频采样等等 for(...);//遍历文件的各个流,找到第一个视频流,并记录该流的编码信息 sws_getContext();//根据编码信息设置渲染格式 avcodec_find_decoder();//在库里面查找支持该格式的解码器 avcodec_open();//打开解码器 pFrame=avcodec_alloc_frame();//分配一个帧指针,指向解码后的原始帧 pFrameRGB=avcodec_alloc_frame();//分配一个帧指针,指向存放转换成RGB后的帧 avpicture_fill(pFrameRGB);//给pFrameRGB帧加上分配的内存; while true{ av_read_frame();//读取一个帧(到最后帧则break) avcodec_decode_video();//解码该帧 sws_scale();//把该帧转换(渲染)成RGB SaveFrame();//对前5帧保存成ppm图形文件(这个是自定义函数,非API) av_free_packet();//释放本次读取的帧内存 } avcodec_close(); av_close_input_file(); 用到的API就这么多,当然实际代码稍复杂一点;ppm图像是类似BMP的非压缩格式,SaveFrame就是相当于把pFrameRGB的内存拷贝进文件,写文件并不复杂; 调试过程的问题,首先是头文件,ffmpeg 0.5.0的API已经拆分成好几个独立的库,用pacman -Ql ffmpeg看了下文件分布,在include下好几个目录都是它的,看名字可以大概猜出他们的功能: libavcodec:CODEC其实是Coder/Decoder的缩写,也就是编码解码器;libavdevice:对输出输入设备的支持;libavformat:对音频视频格式的解析libavutil:集项工具;libpostproc:后期效果处理;libswscale:视频场景比例缩放、色彩映射转换; 修改好头文件包含,终于少了些not [...]
Page optimized by WP Minify WordPress Plugin