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根本就不适合做很多事情,所以深学的价值不是很高,但又不能不懂。

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吧。。。

ssh传送数据

ssh这玩意儿深究起来也是没完没了的。SSH the Secure Shell The Definitive Guide第二版应该不错,但是在这上投资时间似乎有点不值。关键是我对那些加密原理本来就一知半解的,要想彻底明白还得先看那个。。。

总之今天是悟了一个ssh的牛逼用法。牛逼仅限于老潘我自己的判断。。。 

cat file1 | ssh user@host 'cat - > file2'

就是这样了,管道将流引入ssh,ssh连接远程主机,执行命令,此命令的stdin即是ssh的stdin。由此实现远程传输数据的效果。其实这是我一直想用ssh做的 - 总不能老拿ssh当增强版telnet使吧 - 但一直都不会。 今天算开眼了,嘿。

bash相关文件与变量

bash也有点儿太那啥了。。。很多东西不太直觉。

/etc下那些全局文件我就不说了,一般不需要碰。只说用户目录下的。

注意.bash_profile和.bashrc的区别: 

.bash_profile/.bash_login/.profile(按顺序,只执行找到的第一个)仅在login或者指定--login参数时被执行。

.bashrc则仅在invoking subshell时执行。比如直接敲bash时就会执行这个。

但其实很多人不需要根据这两种情况执行不同的命令,所以.profile里经常看到执行.bashrc。

我们平时老说环境变量环境变量的,其实在bash中,环境变量是变量的一种而已。普通的变量用简单的varname=value即可设置(不要加空格!)。export的变量,就是环境变量了,说到底,其与普通变量的不同只是subprocess可以得到环境变量罢了。

unset可以用来清除变量(包括环境变量)。其中还有一些细节就不说了。但是有个东西很邪恶,就是unset名字相对的set,并不是用来设置变量的!!!

set是用来设置options的,就和shopt类似。老潘最最最最爱用的,当然是set -o vi啦。这里还有个陷阱,就是设置option时,减号是“设置”,加号是“取消”。比如set +o vi就是取消vi editing mode进入默认的emacs editing mode。这种弱智设计,是因为-是通用的前缀,当初设计的时候没考虑“取消”这个操作,直接把“设置”用了-,后来想换已经来不及了。。。真弱啊 

 

vi mode in bash

I love vi mode so much that I have to enter vi mode immediately once bash is started.

Add .inputrc to ~ with this line:

set editing-mode vi

(Need support from Readline lib.)

...or

set -o vi

(Utilize the ability of Bash itself.) 

open Cygwin shell from here...

http://sylefeb.blogspot.com/2006/10/tools-adding-cygwin-to-explorer-context.html

http://sources.redhat.com/ml/cygwin/2002-05/msg01645.html

Very helpful time saver!

I used the method in the the latter post and choose "C:\\WINDOWS\\System32\\cmd.exe /c C:\\cygwin\\cygwin.bat %1" as the registry value. Plus, the addictional code in .bash_profile should be:

if [ "$BASHHERE" != "" ]; then
    cd $( echo "$BASHHERE" | tr "\134" /)
fi

在binary文件中查找字符串

#!/usr/bin/python
import os, sys

def searchIn(filename):
  command = ''.join(('strings ', filename, ' | grep "', sys.argv[1], '" > /dev/null'))
  result = os.system(command)
  if result == 0:
    print ''.join((sys.argv[1], ' found in ', filename))

searchIn('Desktop/CM0652_Messages_Nico_2.xls')
searchIn('Desktop/BMD_SELFCARE_PRODUCTION-Copy-bcl-v1.xls')
searchIn('Desktop/CM652_AdditionalTranslations.xls'

仅限装有strings和grep命令的平台。

Linux命令行quirks

从当前目录下递归的找到所有后缀为.ext (ignoring case)的文件,列出内容中含有sth-to-be-found (ignoring case)的文件。
find . -iname '*.ext' -exec grep -il 'sth-to-be-found' '{}' \;
在标准输出上打印日志文件,并随文件增长append输出。
tail -f filename
tail -nN filename 

"*" 在bash和regular expression中的意义虽然有些接近,还是不一样的。re中的"*"是指zero or more preceding,千万注意。

^u delete to the start of the line

^k delete to the end of the line

^a move the cursor to the start of the line 

^e move the cursor to the end of the line

bash中用set -o vi来切换到vi模式,爽!注意切换以后是insert mode,按esc可进入normal mode。

类Unix系统中的I/O buffer,贰

今天讨论standard I/O,即由ISO C标准规范的一组函数。与上一篇提到的file I/O不同,由于它们是标准C的一部分,它们在许多平台(不止是类Unix平台)上被实现。

类Unix系统中的I/O buffer,壹

Unix家族系统中的各种I/O API是非常常用的,不幸的是,它们也是令人迷惑的。

CDT with Cygwin搞定debug环境

总感觉Eclipse CDT不是那么好用,尤其是Windows下。其实咱要求不高,不是非要达到Visual Studio的水平,毕竟这不是Eclipse的拳头产品。但是总不能太难使吧。。。

分页共1页 1