2013年十二月

使用Bash中Complete自动补全命令

大家在Linux下都用shell的TAB自动补全功能,非常方便,但是有时自己开发程序,可能需要自定义实现TAB自动补全功能,这时可能就会用到complete命令来实现对命令的自定义补全,本文主要介绍complete的用法,下一篇会着重介绍对ssh的自动补全的实现。

入门

首先先看一个非常简单的例子:

$ # Create a dummy command:
$ touch ~/bin/myfoo
$ chmod +x ~/bin/myfoo

$ # Create some files:
$ touch a.bar a.foo b.bar b.foo

$ # Use the command and try auto-completion.
$ # Note that all files are displayed:
$ myfoo <TAB><TAB>
a.bar a.foo b.bar b.foo

$ # Now tell bash that we only want foo files.
$ # This command tells bash args to myfoo are completed
$ # by generating a list of files and then excluding
$ # everything # that doesn't match *.foo:
$ complete -f -X '!*.foo' myfoo

$ # Tray again:
$ myfoo <TAB><TAB>
a.foo b.foo
  • 首先自定义了command: myfoo,  然后测试对myfoo的自动补全功能,默认情况下,myfoo会自动列出当前目录的文件作为自动补全
    内容
  • complete -f -X ‘!*.foo’ myfoo : 使用complete命令对myfoo自定义补全功能,参数含义:-f 是列出当前的文件 -X pattern 将符合pattern条件的文件exclude,这里主要是显示*.foo的文件,将*.bar文件排除在外

complete参数详解

complete [-abcdefgjksuv] [-o comp-option] [-A action] [-G globpat] [-W wordlist] [-P prefix] [-S suffix] [-X filterpat] [-F function] [-C command] name [name ...]
  • -W wordlist: 自动补全使用的wordlist, 使用IFS分割,会和当前用户输入的Word做前缀比较,提示那些匹配的word list.
  • -S suffix: 向每个自动补全word后添加suffix 后缀.
  • -P prefix: 向每个自动补全word后添加prefix 前缀.
  • -X filterpat: 对于文件名,将匹配pattern的文件名从completion list中移除(exclude), pattern中使用!表示否定
  • -G globpat: 对于文件名,将匹配pattern的文件名作为可能的completion. 与-X刚好相反,-X “!*.foo” 与 -G “*.foo”作用相同
  • -C command: 将command命令的执行结果作为可能的completion.
  • -F function: 执行shell function,在function中对COMPREPLY这个数组复制,作为可能的completion
  • -p [name]: 打印当前自定义的complete
  • -r [name]: 删除当前自定的complete
  • -A action : 表示生成可能的completion的方式,包括alias, file, directory等,具体请参看文后的参看资料

使用样例

  • 使用-C -G -X参数
    complete -C "pwd" ls  # ls的自动补全为当前目录
    complete -G "*.py" ls # ls的自动补全为.py文件
    complete -X "*.py" ls # ls的自动补全为非.py文件
    
  • 使用-F 参数自定义补全函数

    function _mycomplete_()
    {
        local cmd="${1##*/}"  # 当前命令
        local word=${COMP_WORDS[COMP_CWORD]}  #当前输入的字符串
        local line=${COMP_LINE}  #整行字符串
        local xpat='*.py'  # pattern
        # 根据word的值来补全当前非.py的文件file.
        COMPREPLY=($(compgen -f -X "$xpat" -- "${word}"))
    }
    # _mycomplete_函数可定义在.bash_profile中,然后执行
    source ~/.bash_profile
    # 当然也可多个命令共用一个function, 只要_myfunction_作区分即可,比如对cmd执行case语句
    # 生成不同的xpat
    
    complete -F _mycomplete_ myfoo  #使用_mycomplete 作为myfoo的自动补全
    

参考资料



Hadoop MapReduce学习笔记1

Hadoop MapReduce是比较经典的Master/Slave架构设计,系统主要包括两大模块:

  • JobTracker : 也就是我们所说的Master, 包括资源管理功能和作业调用功能;
  • TaskTracker : Slave模块,或者称为Worker,任务执行的节点;

JobTracker中资源管理

  1. Hadoop以slot(槽位)代表计算资源,包括一定的内存和cpu核,具体细分为Map Slot和Reduce Slot,一个Task可占用多个slots;一个TaskTracker可划分多个slots(可配置), slots间的资源隔离目前hadoop做的不是太好;
  2. TaskTracker作为具体的执行单元,采用pull的的方式拉取任务,TaskTracker会定期的向JobTracker发送心跳,心跳的信息包括:我还活着,TaskTracker中运行的task的状态,如果有空闲的slots的话,向JobTracker表明我有空闲资源,JobTracker以心跳应答的方式向TaskTracker分配新的Task;
  3. JobTracker不会主动的和TaskTracker联系,只会接收心跳,然后再应答中向TaskTracker发送指令,如启动Task, 杀死Task;如果长时间未收到TaskTracker的心跳,表明TaskTracker可能已宕机,则会重启TaskTracker上已经分配的任务到其他的TaskTracker中;
  4. 任务的调度策略:默认简单任务调度策略FIFO,可用户自定义任务的调度策略;

JobTracker中的作业控制

  1. Hadoop将作业分为三个层次:
    • 作业: 用户提交的作业,使用JobInProgress控制作业的运行状态,包含多个Tasks
    • Tasks: 包括Map Task 和 Reduce Task: 使用TaskInProgress控制任务的运行状态,可能包含多个Task Attempt.
    • Task Attempt : 某个Task的运行一次尝试,这里采用的类似two-phase commit的协议,因为jobtracker可能会针对同一Task启动两个Attempt(谁先执行完,使用谁的计算结果,并把另外一个杀掉),然后才会提交task attempt的结作为Task的计算结果,在TaskTracker中执行.
  2. JobTracker会从TaskTracker的心跳汇聚TaskAttempt的运行状态,然后调度未完成的task,分配给TaskTracker.


clipboard

c++中const变量问题的简单分析

今天同事问了关于const 值被更改的问题,这个问题在面试中也会经常被问到,所以专门写篇博客总结下。

代码如下

输出结果:a:10 p:20

简单分析:

其实针对该问题,原因比较简单,在printf调用中,由于a是常量,编译器做了优化,将a的值直接替换为10,所以在后续对a的内存位置进行更改为20时,并未对printf的a参数影响。当然,同事并未相信我的分析,我只能调用汇编后的代码进行分析。

深度分析:

1. 生成汇编代码:

g++ -S test.cpp   # 输出的汇编代码位于test.s中

2. 汇编代码如下:


根据第26行,验证了我上述的分析,此时同事想让我讲下整个汇编代码的逻辑(我心里暗喜,刚好最近在上@林士鼎 的课程,顺便复习下)
3. 函数调用的知识
理解函数调用栈,有几个概念需要事先明确:
a. 栈的增长方式由高到低(大学课本里早就会背了,但是要真正理解)
b. 参数传递方式:寄存器 + 栈
c. %rsp : 栈头指针 , push pop会更改对应的指针值
d. %rbp : 帧指针, 这个概念非常重要,当前函数的栈的起始位置,
使用%rbp + offset访问局部变量及传递的参数,下面这张图是@林士鼎 老师的课件中某个图

4. 汇编分析:

main:
.LFB2:
pushq %rbp    # 将原来的帧指针保存
.LCFI0:
movq %rsp, %rbp   # 将当前%rsp 保存至%rbp, 当前帧
.LCFI1:
subq $32, %rsp   # 将栈下移32Bytes, 这32字节保存了main的参数和main中局部变量
.LCFI2:
movl %edi, -4(%rbp)   # 取 argc的值
movq %rsi, -16(%rbp)    # 取argv的值, 为何会占12Bytes呢? 后续分析
movl $10, -20(%rbp)    # 将10赋值给a
leaq -20(%rbp), %rax   #取a的地址到%rax
movq %rax, -32(%rbp)     #将a的地址赋值给p(int *), 32的偏移有待分析
movq -32(%rbp), %rax    # 去p的值到%rax
movl $20, (%rax)     # 对*p赋值
movq -32(%rbp), %rax
movl (%rax), %edx   #这两步相当于*p,同时将其赋值到寄存器作为printf的参数
movl $10, %esi     #传递10参数(其实是a)
movl $.LC0, %edi    # "a:%d p:%d\n"
movl $0, %eax   #这个作用稍后分析
call printf
movl $0, %eax  #main函数的返回值
leave
ret

变量在栈的位置分布情况:


5. 其他问题分析:

a. 为何argv 和 p在栈的位置偏移异常,这里主要是因为argc 和a 的大小为4Bytes,  而系统是64Bits, 所以存在8Bytes对齐,
这里可以验证,在a后面单独声明一个b变量,发现其在栈的空间刚好为间隙的位置

b.  movl $0, %eax   这句话的作用:当对于变参的参数传递时,%eax标示的使用vector register的数目(可以向printf传递float类型参数进行验证)

参考资料:

1. http://stackoverflow.com/questions/6212665/why-is-eax-zeroed-before-a-call-to-printf

2. http://yaronspace.cn/blog/archives/1347



This is from android

没想起wordpress还有app版本,多谢小芳邓的推荐。

最近一年blog都快荒废了,我的勤奋点了。