Linux Bash Shell学习(十五:变量类型和整型运算

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow

也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!

               

  本文也即《Learning the bash Shell》3rd Edition的第六章Command-Line Options and Typed varilables之读书笔记之二,但我们将不限于此。

  在之前,我们涉及的变量基本上是字符串,也有整数,例如便是参数个数的$#。我们可以使用declare来制定变量的属性。

变量类型定义

declare –a name:表示数组array。

declare –f name:表示是function的名字。

declare –F name:同上,但只显示function的名字。这个和上面的具体差异不太明白,但是这两者都很少使用,先不理会它们。

扫描二维码关注公众号,回复: 3921681 查看本文章

declare –i name:表示整数

declare –r name:表示只读。不能使用unset。对于只读变量,也可以使用readonly name的方式,相当于declare –r name。readonly可以带三个选项:-f表示这是个function的名字,-p表示打印所有的readonly的名字,-a表示这是个只读的数组。

declare –x name:同export,即不仅在当前的环境中起作用,也在外部的shell环境中起作用。

整型运算

  我们可以通过declare -i来定义整型变量。在上一次的学习中,使用了$(($OPTIND - 1))来进行计算$((…))是用于进行整型运算的。在$((…))中,我们并不需要对变量加上$来表示它的值,也不需要预先声明这个变量是个整型。在双引号下也能进行有效运算。下面是个例子:

#declare -i aa=13        
aa=13        
echo '$((aa-3))'=$((aa-3))        
echo '$(($aa-3))'=$(($aa-3))        
#date显示日期,date +%j表示今天是年度的第几天,$(command)表示其显示结果        
echo "Only $(( (365-$(date +%j)) / 7 )) weeks until the New Year"

  前面两个echo得到的值都是10,我们也不需要预先声明aa是个整数,因为$((…))已经表明是整型的运算,会自动将字符变为整数。

运算类型和C语言一样。也支持$((x += 2))的格式,包括下面几种操作。在下面的例子中我们引用了上面aa=13。

++ :$((aa++))为13,并将aa赋值为14,注意使用$(($aa++))会报错,无法解析13++的含义,所以为了简洁并且不产生错误,不在运算式中加入$,如果是$((++aa))为14,并将aa赋值为14,这与C语言是一样的。 -- :$((aa--))为13,并将aa赋值为12,如果是$((--aa))为12,并将aa赋值为12。 + - * / %:求余:$((aa%5))=3 **:这个在C语言中是没有的,表示Exponentiation,即取幂。例如上面例子中$(($aa**3))相当于13*13*13=2197 << >> & | ~ ! ^

  还支持逻辑运算,包括<, >, <=, >=,==,!=,&&,||,这些也与C语言一样。例如$((3>1))为1。这和命令运行return 0表示真是不一样的。一个是逻辑运算的结果,一个是exit status。例如上面$((3>1))为1,逻辑计算结果为1,而执行结果的 exit status为0。这两个概念需要区分。

  我们在http://blog.csdn.net/flowingflying/archive/2009/12/22/5069646.aspx中给出同[ … ]进行条件判断的方式,这里>,<,=等符号是用于判断字符串的,表示用于比较数字的,在[ … ]中,如果对数字进行比较,需要使用-lt, –gt, –le, –ge, –eq, –ne。使用[ … ],例如if [ 3 –gt 20 ]; then,条件不成立,但是[ 3 > 20 ],则成立,因为此刻比较的是字符串。所以这是很容易引起混淆的。如果需要表达比较复杂,例如[ /( 3 -gt 2 /) || /( 4 -le 1 /) ]是不太好阅读的。我们需要强调一点:在if [ condition ]; then中,shell对于function或者command是已0来表示成功,因此if也是判断是否为0,这和$(())的数学逻辑运算是不一样的。对于上面的例子,可以使用if [ $(((3 > 2) && (4 <= 1))) = 1 ],前面(((3 > 2) && (4 <= 1))) 运算结构为1,然后进行[ str1 = str2 ]的比较,判断是否成立。这样写仍然很麻烦,以及使用if  (((3 > 2) && (4 <= 1))) ,即((…))的方式表示。

对于数学运算的赋值,使用$((...))有时显的比较繁复,可以使用let,格式如下:

let intvar=expression

  let表示expression是个数学运算,无须使用$(())来作进一步表明,这样的赋值方式简洁很多。 等号前后是没有空格的,在expression的表达式中也是没有空格的,如果有空格必须用引号引起来,可以是单引号,也可以是双引号,let x=1+4;let x='1 + 4';let x="1 + 4",这三个同样都是给x赋值为5。下面是一个例子,获取指定目录的所占大小空间:

function test1        
{        
    echo "test1 ${*}"        
    for dir in ${*:-.}; do        
        if [ -e $dir ]; then        
            # du - estimate file space usage,返回block数目          
            result=$(du -s $dir | cut -f 1)        
            let total=$result*1024          
            echo -n "Total for $dir = $total bytes"        
            if [ $total -ge 1048576 ]; then        
                echo " ($((total/1048576)) Mb)"        
            elif [ $total -ge 1024 ]; then        
                echo " ($((total/1024)) Kb)"        
            fi        
        fi        
    done        
}

  下面是一个较大的例子,使用这本书一直在用的pushd和popd的例子。进行了一些功能加强。当pushnd +n时,将第N个元素移到最上面,并进入该目录,如果没有参数,将最上的两个元素交换,并进入交换后最top的目录,否则安原pushd的处理方式进行处理。如果popnd +n,则将第N个元素从stack中删除,其他的同popd的处理。

#获取在stack中第N的参数,从0开始计算,并将前N的存放stackfront,后N的存放在stack中        
function getNdirs        
{        
    echo getNdirs $@        
    stackfront=''        
    let count=0        
    #通过数学计算和数字判度,可以向C那样进行次数的控制,由于for是用于列表元素,所以使用while,循环之后,stackfront存储前N个entry,含N,stack则存贮后面的元素。而target存贮第N个元素          
    while [ $count -le $1 ] && [ -n "$stack" ]; do        
        # target为stack中最top level的entry,含后面的空格        
        target=${stack%${stack#* }}        
        # 将最top的entry存放在stackfront的后面   
        stackfront="$stackfront$target"        
        # stack为取出最top entry后的值        
        stack=${stack#$target}        
        let count=count+1        
    done        
    # 将第N个元素重复从stackfont中移出,则stackfont存贮N之前的元素        
    stackfront=${stackfront%$target}        
}



# 当pushnd +n时,将第N个元素移到最上面,并进入该目录,如果没有参数,将最上的两个元素交换,并进入交换后最top的目录,否则安pushd的处理方式进行处理。        
function pushnd        
{        
     echo        
    echo pushnd $@        

    #检查如果是pushnd +n的情况,需要将地N个元素移到最上方   
     if [ $(echo $1 | grep '^+[0-9][0-9]*$') ]; then        
        # 将参数1,去除+,获取n        
        let num=${1#+}        
        getNdirs $num        
        stack="$target$stackfront$stack"        
        cd $target        
    elif [ -z "$1" ]; then        
    # case of pushnd without args; swap top two directories        
        firstdir=${stack%% *}        
        stack=${stack#* }        
        seconddir=${stack%% *}        
        stack=${stack#* }        
        stack="$seconddir $firstdir $stack"        
        cd $seconddir        
     else        
    # normal case of pushd dirname        
        dirname=$1        
         # -a等同于 &&        
        if [ /( -d $dirname /) -a /( -x $dirname /) ]; then        
            stack="$dirname ${stack:-$PWD" "}"        
            cd $dirname        
        fi        
     fi
    echo "stack=$stack"        
    echo "directory=$PWD"        

}

# 如果popnd +n,则将第N个元素从stack中删除,其他的同popd的处理        
function popnd        
{        
    echo        
    echo popnd $@


    if [ $(echo $1 | grep '^+[0-9][0-9]*$') ]; then        
    # case of popd +n: delete n-th directory from stack        
        let num=${1#+}        
        getNdirs $num        
        stack="$stackfront$stack"        
#      cd ${stack%% *}        
     else        
        if [ -n "$stack" ]; then        
            stack=${stack#* }        
            if [ -n "$stack" ]; then        
                cd ${stack%% *}        
            else        
                echo "stack becomes empty."        
            fi        
        else        
            echo "stack already empty."        
        fi        
    fi        
     echo "stack=$stack"        
    echo "directory=$PWD"        

}

pushnd /home        
pushnd /etc        
pushnd /home/wei/mywork        
pushnd +3        
pushnd        
pushnd +1
popnd +3        
popnd        
popnd        
popnd

for的应用

  我们希望for和C或者JAVA那样使用,这样在数组的情况下非常方便,格式为:

for (( initialisation ; ending condition ; update ))        
do        
        statements...        
done

  如果使用for((;;))泽则表示一个无限循环,在statements中可以用break来退出循环。下面是一个九九乘法表的例子:

for (( i=1; i <= 9 ; i++ ))        
do        
        for (( j=1 ; j <= 9 ; j++ ))        
        do        
                echo -ne "$(( j * i ))/t"        
        done        
        echo        
done

相关链接: 我的Linux操作相关文章

           

给我老师的人工智能教程打call!http://blog.csdn.net/jiangjunshow

这里写图片描述

猜你喜欢

转载自blog.csdn.net/skdhfdfc/article/details/83689551