bash中的递归

这是learning the bash shell, 3rd ed中的一个练习的改良版本。搁这儿不是显摆我做出来了,就是记录一下bash里递归怎么用。

Positional parameters就是没有named好。curdir那个变量我就懒得传了,还得处理参数,于是用了个全局的。

recls ()
{
    # TODO check: only accepts 1 argument, must be a directory
    # global var singletab
    singletab='\t'
    # global var curdir, reset
    unset curdir
    # start recursion
    recdir 0 $@
    unset singletab curdir
}

recdir ()
{
    local level=$1 file
    shift 1
    for file in $@; do
        rptprt $singletab $level
        echo -e $file
        if [ -d "$curdir$file" ]; then
            curdir=$curdir$file/
            recdir $((level+1)) $(ls $curdir)
            curdir=${curdir%$file/}
        fi
    done
}

rptprt ()
{
    # usage: prt STRING_TO_PRINT TIMES
    # well, you may think we could use brace expansion to do it:
    # printf "$1%.0s" {1..$2}
    # but brace expansion is performed before parameter expansion, e.g.
    # {1..$2} where the second parameter is 5
    # will be evaluated to {1..5} insteand of 1 2 3 4 5
    # because {1..$2} is an illegal brace expansion so bash just keep it as is
    # then parameter expansion will make it {1..5}
    # However, we can always use eval:
    # printf "$1%.0s" $(eval echo {1..$myvar})
    if [ $2 -gt 0 ]; then
        printf "$1%.0s" $(seq $2)
    fi
}

我还特意写了一个rptprt (repeat print)来重复打印。注意它极为tricky...我写了好多注释。简单来说就是和bash分析输入时,做各种工作的顺序有关。

这破程序把我折腾死了。书里有好多又臭又长的例子,我发誓再也不用Bash写超过5行的脚本了。。。Bash根本就不适合做很多事情,所以深学的价值不是很高,但又不能不懂。

Gears of War


Gears of war这个游戏是n个月以前爱辉推荐给我的。当时我看总共7个多G吓了一跳,不过还是拖进了电驴。经历了几个月的下载,就在我快把这回事儿忘了的时候,下载完成了。。。

玩起来竟是欲罢不能。游戏可操作性极好,画面也非常有真实感。配乐更是地道,打起来非常紧张刺激。主角是个老兵而且无疑是个战斗英雄,但这个游戏不像英雄萨姆那样,可以让你一人单挑一万个怪物。主角的身体和敌人士兵一样脆弱,在高难度下,甚至比对方脆弱很多。所以如果不加思考的一味猛冲,你一定会死的很惨。身处硝烟弥漫的战场上,稍不留神就会失去性命。必须时刻观察敌我位置和距离,计算地形和各种障碍带来的影响,还要把敌我的武器装备考虑进去,才能选择合适的战术,一路杀敌前进。

老潘不敢自称高手,但已经打穿hardcore难度,并且在此难度中一次轻易击败总boss,颇有些心得。

find与grep连用

find与grep连用实在是使用频度太高了,我写了个bash函数抽象一下,置于.bashrc中。

从最后一句你可以看出bash的command line processing有多复杂。其原因正是它做了太多的{}, *, ~, $(())这种工作,用到的特殊字符太多,而且还是分步做的,以至于escape起来巨繁复。此命令的原型是

find [LOCATION] [-iname GLOBPATTERN] -exec grep -l[i] REGEXPATTERN '{}' \;

由于token splitting是在parameter expansion之前进行的,我不得不用动用eval,否则keyword会被认为是一个token。但是用了eval就导致命令中原有的好几个特殊字符必须escape,所以写出来才会这么恶心。。。

findgrep () {
    local usage="
Search for content in files in a directory.\n
Usage: findgrep [-i] [-n keyword] [-l location] pattern\n
            Options:\n
            -i              ignoring case when grepping\n
            -n keyword      only check files with names\n
                            containing this keyword (ignoring case)\n
            -l location     the location to start the search.\n
                            Must be a directory\n
            Arguments:\n
            pattern     the grep pattern used"

    # vital for repeatly using getopts
    unset OPTIND

    # check options
    local opt location i pattern keyword
    while getopts "in:l:" opt; do
        case $opt in
            i  ) i=i;;
            n  ) keyword="-iname '*'$OPTARG'*'";;
            l  ) location=$OPTARG
                 if [ ! -d $location ]; then
                     echo -e $usage
                     return 1
                 fi;;
            \? ) echo -e $usage
                 return 1;;
        esac
    done

    shift $(($OPTIND - 1))

    # check arguments
    if [ $# = 1 ]; then
        pattern=$1
    else
        echo -e $usage
        return 1
    fi

#    debug
#    echo keyword="$keyword"
#    echo location=$location
#    echo pattern=$pattern
#    echo i=$i

    # I hate bash cmd line processing!!!
    eval find $location $keyword -exec grep -l$i $pattern "'"{}"'" \\\;
}

我还是用Python吧。。。

分页共1页 1