python和shell脚本实现查看大文件指定区域范围内的文件内容

1. 功能

   实践中经常有需要查看某个文件(特别是超过1G的大文件)指定区域范围内的文本内容的需求,为此,笔者使用python的原生open、read和write函数实现对指定文件指定范围内的内容重定向到另一文件的功能,需要时结合shell脚本以16进制显示出筛选出来的文件内容。

2. 原理解析

   sub_file:主要使用python原生的open打开指定文件,seek到指定范围的起始位置之后,read出指定范围的文件内容,write到另一文件。由于read函数实现时已对大文件进行缓冲区处理故打开大文件读取时速度适中不会有太多的等待时间。
   show: 主要使用shell脚本来调用sub_file,对sub_file的输出文件读取,使用xxd命令来实现对读取内容的处理以16进制的形式显示。

3. 实现脚本

3.1 sub_file

#!/usr/bin/env python
# author: caft
# email: caft0505@gmail.com
# Filename: sub_file
# Function: get a sub_file from the specified file

import os
import sys
import getopt
import stat

def usage():
    print 'Usage: get a sub_file from the specified file'
    print 'sub_file <-f file_from> <-t file_to> <-o offset> <-l length> [-h help]'

def sub_file(file_from, file_to, offset, length):
    base = [10, 16]
    try:
        if isinstance(offset, str):
            offset = long(offset, base['0x' in offset])
        if isinstance(length, str):
            length = long(length, base['0x' in length])
    except Exception, err:
        print 'error: %s' % str(err)
        return -1

    rfd = 0
    wfd = 1
    try:
        rfd = os.open(file_from, os.O_RDONLY)
        wfd = os.open(file_to, os.O_WRONLY | os.O_CREAT, 0644)

        f_stat = os.stat(file_from)

        # st_size will be 0 if file_from is a device.
        if stat.S_ISREG(f_stat.st_mode):
            if f_stat.st_size > 0:
                if offset > f_stat.st_size:
                    offset = 0
                elif offset < 0: # means to get file content from tail.
                    offset = f_stat.st_size + offset

            length = min(f_stat.st_size - offset, length)
        else:
            offset = 0
            length = 0

        os.lseek(rfd, max(offset, 0), 0)

        while length > 0:
            rlen = min(4096, length)
            buf = os.read(rfd, rlen)
            assert rlen == os.write(wfd, buf)
            length -= rlen

    except Exception, err:
        print 'error: %s' % str(err)
        return -1
    finally:
        os.close(rfd)
        os.close(wfd)

    return 0

def parse_args(args):
    if len(args) == 0:
        usage()
        sys.exit(0)

    opts = ()
    file_from = ''
    file_to = ''
    offset = 0
    length = 0

    try:
        opts, args = getopt.getopt(args, 'f:t:o:l:h')
    except getopt.GetoptError, err:
        print 'error:', str(err)
        sys.exit(-1)

    if len(args) > 0 or len(opts) != 4:
        usage()
        sys.exit(-1)

    for option, value in opts:
        if option == '-f':
            file_from = value
        elif option == '-t':
            file_to = value
        elif option == '-o':
            offset = value
        elif option == '-l':
            length = value
        '''elif option == '-h': #unused
            usage()
            sys.exit(0)'''

    return (file_from, file_to, offset, length)

if __name__ == '__main__':
    ret = sub_file(*parse_args(sys.argv[1:]))
    sys.exit(ret)

3.2 show

#!/usr/bin/env sh
# author: caft
# email: caft0505@gmail.com
# Filename: show
# Function: show the text in hex from the specified file

function usage()
{
    echo 'Usage: show the text in hex from the specified file'
    echo 'show <-n file> <-o offset> <-l length> [-h help]'
}

if [ $# -ne 6 ]
then
    usage;
    exit 0
fi

file_from=''
offset=0
length=0
while getopts n:o:l:h OPTION
do
    case $OPTION
    in
        n) file_from=$OPTARG;;
        o)  let "offset = $OPTARG" 2>/dev/null
            if [ $? -ne 0 ]
            then
                if [[ "$OPTARG" != "0" && "$OPTARG" != "0x0"
                   && "$OPTARG" != "-0" && "$OPTARG" != "-0x0" ]]
                then
                    echo 'error input:' $OPTARG
                    exit -1
                fi
            fi;;
        l)  let "length = $OPTARG" 2>/dev/null
            if [ $? -ne 0 ]
            then
                if [[ "$OPTARG" != "0" && "$OPTARG" != "0x0" ]]
                then
                    echo 'error input:' $OPTARG
                    exit -1
                fi
            fi;;
        h) usage; # unused
            exit 0;;
        ?) exit -1;;
    esac
done

argc=$[ $# + 1 ]

if [ $OPTIND != $argc ]
then
    usage;
    exit -1
fi

if [ $length -eq 0 ]
then
    exit 0
elif [ $length -lt 0 ]
then
    echo 'error length is negative!'
    exit -1
fi

file_to=".~tmp_for_${file_from_}" # replace '/' with '_'
if [ ! -f $file_to ]
then
    touch $file_to
else
    echo 'error:' \'$file_to\' 'is existed.'
    exit -1
fi

sub_file "-f" "$file_from" "-t" "$file_to" "-o" $offset "-l" $length

if [ $? -eq 0 ]
then
    xxd $file_to
fi

rm -f $file_to

4. 使用方法

4.1 sub_file的使用


4.2 show的使用

   另外,对于show而言,-o 和 -l 参数均可为一个简单的不含括号计算表达式,但当计算结果为0时,可能会报错,因为计算过程是使用shell中的 let 工具来完成的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值