linux 截取文件内容,shell脚本分析-截取文件的一部分

CODE:

#! /bin/bash

function check_pipe_status()

{

local status

for((i=1;i<=$#;i++)) {

eval status=\$$i

if [ $status -ne 0 ]; then

echo false;

fi

}

echo true

}

check_pipe_status中,eval status=\$$i语句经历了2次扩展,第一次扩展的结果是eval status=$n,其中n是该次循环的$i的值,第一个$被当作字符了,然后eval又使status=$n再次被当作shell指令执行一次,从而得到第n个寒暑参数的数值.

对于函数来说,调用者得到的结果就是函数echo的结果,而不是return出来的结果,return出来的结果放到了$?里面。

function get_file_size()

{

{ ls -l "$1" | gawk '{print $5}' ; } 2>/dev/null

if ! $(check_pipe_status "${PIPESTATUS[@]}"); then

return 1

fi

return 0

}

${PIPESTATUS[@]}代表了前面刚执行的语句的pipe两头的语句的结果,如正确的话全是0。而文件的结果被输出了。print $5就是输出的文件大小.

function check_number()

{

v=$(echo "$1" | grep '^\(+\?[0-9]\+\|0[xX][0-9a-fA-F]\+\)$' );

if [ -z "$v" ]; then

echo "Illeagal number $1" >&2;

exit 1;

fi

}

这里使用grep的时候,要注意一点,grep默认使用的是basic regular expression的表达方式,即: ? + | ( ) { }这几个字符在basic里面就是字面字符,没有特殊含义,如果想要有特殊含义,就得加上backslash符号,即\?就代表了前面的内容可有可无。或者还可以使用grep -E 那么,此时就默认使用extended regular expression了,这些字符就有了特殊含义了。或者使用egrep。

因此,'^\(+\?[0-9]\+\|0[xX][0-9a-fA-F]\+\)$'的含义就是:

起头的,前面'+'可有可无的,至少有1个0-9之间的字符的,或者是以0x起头的,16进制格式的数字串。然后结尾。

关于echo "Illeagal number $1" >&2 的作用,可以参看我的一个帖子,>&2的作用就是1>&2就是将fd2赋值给fd1,即echo所使用的fd1现在和fd2指向的目标一样。即单纯这条指令的数粗的fd1指向了和fd2一样的内容。我们自己做一个测试:

$cat test.sh

#!/bin/bash

echo "i am error output" >&2

echo "i am normal output"

$./test.sh

i am error outpur

i am normal output

$./test.sh >tmp

i am error output

$cat tmp

i am normal output

解释:注意虽然最后我们将整个脚本的标准输出定向到tmp,但是,这只是将整个脚本的执行进程的fd1重定向向到了tmp文件,而并不改变内部的echo "i am error output" >&2这个命令的fd1的指向,即该命令的fd1继续指向stderr,即fd2的指向,那么造成的结果是i am error output依然会输出到stderr即显示终端,而i am normal output就被重定向到文件了。这样看来,整个脚本的命令中,有向fd2的输出,也有向fd1的输出,而整个脚本的fd1的输出被重定向了,而fd2的没有,因此向fd2的输出就被显示出来了。这个可以作为我们在校本中向stderr输出的方法。我们不能这样想:这个echo命令的fd1指向fd2的内容了,而后来对整个脚本的重定向有将fd1改为指向文件了。所以这个命令的输出也指向文件。这是错误的。

实质是,在本脚本被执行前,其进程中的fd1就指向了文件tmp,fd2指向stderr,当执行到命令echo "i am error output" >&2时,其fd1开始也是指向tmp的,但是现在被更新为指向stderr,当此命令执行完后,别的命令的fd1还是指向文件。我们要说的是解释器先为真个进程设定好了fd的指向后采取执行各条命令,而不是执行完各条命令后再去看整个进程输出的指向。

下面继续看代码:

SCRIPT_NAME=$(basename $0)

PAGESIZE=4096

inf="$1"

outf="$2"

start="$3"

length="$4"

if [ $# -lt 2 ]; then

echo "Usage: $SCRIPT_NAME input-file output-file [start] [length]" >&2;

exit 1;

fi

file_sz=$(get_file_size "$inf");

if [ $? -ne 0 ]; then

echo "$inf is not present!" >&2;

exit 2;

fi

上面用$?来获取get_file_size函数return的数值,而该函数echo出来的内容就是filesize。看来shell中的函数结果和返回值是两码事。

if [ -z "$start" ]; then

start=0;

length=$file_sz;

elif [ -z "$length" ]; then

length=$((file_sz-start));

check_number "$start";

else

check_number "$start";

check_number "$length";

fi

上面((...))是进行数学运算的意思。

if [[ $((start+length)) -gt $file_sz ]]; then

printf "offset (%d,%d) beyond file length (%d)" $start $((start+length)) $file_sz >&2;

exit 1;

fi

if true; then

length1=$((length/PAGESIZE*PAGESIZE))

length2=$((length%PAGESIZE))

start1=$start

start2=$((start1+length1))

{

if [ $length1 -gt 0 ]; then

dd if="$inf" skip=$(printf "%d" $start1) ibs=$PAGESIZE count=$(($length1/PAGESIZE)) 2>/dev/null

fi

if [ $length2 -gt 0 ]; then

dd if="$inf" skip=$(printf "%d" $start2) ibs=1 count=$length2 2>/dev/null

fi

} >"$outf"

else

dd if="$inf" of="$outf" skip=$(printf "%d" $start) ibs=1 count=$(printf "%d" $length) 2>/dev/null

fi

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值