Windows 右键添加新建项

有时候写代码的时候,要新建一个文件,假如是.py。那么首先我们得新建一个文本文件(.txt),然后再重命名成xxx.py,因为改变文件扩展名的缘故,还会弹出一个确认的对话框。非常烦,那么有适合懒人的方法吗?答案是肯定的,只要你肯去找,网上的方法非常多。

Windows下一些定制或者或少要去修改注册表,说实话,对Windows的注册表真得不是非常感冒,但是Windows许多神秘的东西都隐藏在这里。

首先创建一个文本文件,改名为add_item_in_new_context.reg(注册表文件是以.reg为扩展名的)。然后将以下内容写到该文件中:

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\.py\ShellNew]
"FileName"="sample.py"
"NullFile"=""

该文件的目的是在HKEY_CLASSES_ROOT\.py路径下创建一个项ShellNew,并在该项下创建一些键值。ShellNew就是对应于右键新建菜单,换句话说,如果要删除不要的新建项目,也可以在注册表中删除对应的ShellNew项。而FileName这个键的目的是,在新建的时候使用一个模板文件来创建,有时候代码都是需要在文件开始处放一些注释和说明的,那么可以写一个sample.py:

#!/bin/env python
# coding=utf-8

'''A simple sentence to describe the function of this module.

Add detailed description here if need.

Eample:
    # python ./sample.py -t
    # ...
'''

# Can be 'Prototype', 'Development', 'Product'
__status__ = 'Development'
__author__ = 'yourname <yourname @example.com>'

# Add your code here
# Delete the description when you start coding.

def usage():
    '''Show script help information.'''
    pass

def main():
    '''The main entry.'''
    pass

if __name__ == '__main__':
    main()

# vim: set expandtab smarttab shiftwidth=4 tabstop=4:

然后把sample.py放到C:\Windows\ShellNew目录,现在再试试右键新建,会出现Python文件。

不过我并没有用这种方法,让.sh文件也成功,有空再研究下。

Grub 加载系统的三个阶段

一篇比较老的笔记,从老博客上搬运过来的。

手头刚买了一本书,书名为《Linux操作系统之奥秘》,作者是邱世华,是台湾的一个资深工程师。当时买这本书的原因是,网上评论这本书适合已经入门但是呢对Linux又是一知半解的人。买了之后,看了一点,发现真得非常适合我,现在只是看到第二章(GRUB),但是真得受益匪浅。

之前装Linux系统,因此对GRUB也不陌生,但是顶多是停留在一些开启启动配置,又或者修复MBR等等层面,对它的原理、细节就完全不清楚了。大家都知道,MBR其实只有512字节的大小,其中bootloader更是只占了这其中的446字节,另外的分别是64字节的分区表信息(一个分区需要16字节,这也是为什么只能分4个主分区的原因)以及2字节的magic number。而GRUB的大小必然不只512字节,那么它怎么放置多出来的东西呢? 没看书之前,我估计只知道,肯定是把启动必须的代码放到MBR的前446字节,而其它的放到硬盘的其它地方,至于具体的处理方式,就....)

事实上,GRUB管理开机启动的过程分成了三个阶段,分别是stage1/stage1.5/stage2。其中,stage1主要负责BIOS和GRUB之间的交接,载入存放于各个分区中的开机文件(我的理解是,例如Linux下/boot/grub/..下面的一些文件)。这部分才是真正放在MBR中的bootloader。而后stage1.5是连接stage1和stage2之间的通道,起着过渡的作用。最后才是GRUB中真正核心的部分stage2,它可以让用户以选项的方式将操作系统加载、修改选项以及新增参数。

查看全文

终端下肉眼看不见的东西

假设test目录下面有a.log、b.log和c.log三个文件:

# ls -1 *.log
a.log
b.log
c.log

现在,我们想要遍历这几个文件,找到关心的信息,例如log文件中是否存在error信息。那么,我们会考虑写一个for循环来处理这个问题:

# for i in `ls -1 *.log | sed '$d'`; do
> grep 'err' $i
> done

非常简单的一个循环,但是执行后会发现以下错误:

grep: a.log: No such file or directory
grep: b.log: No such file or directory
grep: c.log: No such file or directory

非常奇怪,不是*.log这几个文件都在当前目录存在着的吗?为什么这里又找不到呢?
查看全文

在 Linux 下管理 SSH 连接

工作过程中,往往需要连接到不同的服务器上,有些服务器因为处于特定的集群中,可以方便的通过跳板机跳转过去。而有一些开发机、测试机等零散的服务器就需要凭记忆来记住IP地址。肯定,这种方式非常麻烦,有些客户端可以用来管理 SSH 连接 ,例如Win下的xshell和putty等。

配置 SSH 连接

这里提供一种不需要安装客户端的简单方法,只利用SSH的配置文件(~/.ssh/config)来记录和管理多个 SSH 连接 。关于~/.ssh/config的配置很简单,随便找个手册了解一下就行。 例如,下面定义了连接到 test 这台机器所需的配置:

# Test host
Host test
    HostName 10.1.1.1
    User admin

一旦在配置文件中写好之后,可以简单地通过"ssh test"来连接到相应的服务器,非常简单。

参考Mac OS X 平台有哪些好用的 SSH 客户端? - 知乎,在上面的基础上再添加以下配置:

Host *
    ServerAliveInterval 60
    ControlMaster auto
    ControlPath ~/.ssh/%h-%p-%r
    ControlPersist yes

下面介绍两种方法来利用配置文件管理好 SSH 连接。

查看全文

Python 日志模块使用

Python内置了很多非常使用的模块,logging 模块是用于控制和输出日志的,它是一个非常强大的日志模块,可以按照不同的需求配置。它的官方文档地址是在这里

我自己也用过几次logging模块,但是前面用的时候都把它用得太复杂了,还自己封装了下。其实,有些代码越是简单越好,写得复杂得反而不容易扩展和使用。

以下是我在脚本中用到的一段代码:

def init_log(log_file):
    '''Initialize logging module.
    '''
    logger = logging.getLogger()
    logger.setLevel(logging.DEBUG)

    formatter = logging.Formatter('[%(levelname)s] %(message)s')

    # Create a file handler to store error messages
    fhdr = logging.FileHandler(log_file, mode = 'w')
    fhdr.setLevel(logging.ERROR)
    fhdr.setFormatter(formatter)

    # Create a stream handler to print all messages to console 
    chdr = logging.StreamHandler()
    chdr.setFormatter(formatter)

    logger.addHandler(fhdr)
    logger.addHandler(chdr)

    return logger

代码的意思很简单,这里就不多加解释了,需要注意的是第5行不能少,要不然会出现问题。因为当logging模块输出的日志分成多个级别,例如DEBUG、INFO、WARN、ERROR等。当没有通过setLevel方法设置日志级别的话,系统默认的日志级别是WARN,也就是说只胡日志级别大于等于WARN的日志才会输出可见,例如ERROR,而日志级别比它低的则被过滤掉了,例如DEBUG。

那为什么这一行不能少呢?因为当一条日志要打印输出时,首先会看这条日志的级别是否大于logging.setLevel设置的级别或者默认的WARN,如果不是则直接过滤掉;如果大于,则会发送给Logger对象绑定的各个handler对象,交由它们进一步处理日志,或者输出到屏幕,或者写入到文件中。而每个handler对象也会有它自己设置的日志级别,然后再进一步地过滤。所以如果不包含第5行,然后StreamHandler对象设置的日志级别是DEBUG的话,其实是没有意义的。

使用方法:

logger = init_logger('test.log')
logger.debug('%s, %s', 'hello', 'world');
logger.info(...)
logger.warn(...)
logger.error(...)

一个奇怪的 echo 结果

昨天经阮哥指点后,写一个检查redis-server的内存消耗的脚本。脚本本身不复杂,因为redis-cli已经提供了查询接口。

# redis-cli -p yourt_port info | grep 'used_memory'

# resuts:
# used_memory:122088016
# used_memory_human:116.43M
# used_memory_rss:128057344
# used_memory_peak:122079336
# used_memory_peak_human:116.42M

一般会选择提取出used_memory_human的结果,但是考虑到万一内存消耗上G了呢?那么这里也要进行一个单位转换,干脆就提取used_memory这个值,以字节为单位的,然后在这个值基础上除以1024*1024换算成MB。

查看全文

Sed 命令地址匹配问题总结

这个问题来源于ChinaUnix的一篇帖子“sed地址和模式匹配的问题”。

man sed手册说明

Sed默认的命令执行范围是全局的,如果想仅对其中部分行执行命令,可以使用地址限制。在Manual手册中有一节关于地址的描述,摘取部分如下:

Sed commands can be given with no addresses, in which case the command will be executed for all input lines;

Sed默认是全局编辑的,因此如果不明确指定行的话,命令会在所有输入行上执行。

with one address, in which case the command will only be executed for input lines which match that address;

如果指定一个行地址,那么sed命令就限制在那一行执行。

or with two addresses, in which case the command will be executed for all input lines which match the inclusive range of lines starting from the first address and continuing to the second address.

如果给了两个地址,即地址对(或者地址范围),则命令在匹配的这个地址范围内执行。但是需要注意的几点是:

The syntax is addr1,addr2 (i.e., the addresses are separated by a comma); the line which addr1 matched will always be accepted, even if addr2 selects an earlier line; If addr2 is a regexp, it will not be tested against the line that addr1 matched.

查看全文