shell编程 - 字符串和算数计算

        计算机程序其实就是处理数据。很多编程问题需要使用到更小的数据单元,例如字符串和数字。shell提供了多种字符串操作的参数扩展。除了算术扩展,还有一个常见的叫做bc的命令行程序,它能执行更高层次的数学运算。

参数扩展(Parameter Expansion)

基本参数

        参数扩展的最简单形式体现在平常对变量的使用中。

$a扩展后成为变量a所包含的内容,无论a包含什么。简单参数也可以被花括号包围,例如${a},这对扩展本身毫无影响。

但是,当变量相邻与其他文本时,则必须使用花括号,否则shell可能混淆。

a="foo"

echo $a_file

输出的结果是:空,

因为shell会试图扩展名为a_file的变量而不是a变量。可以通过加上花括号解决

a="foo"

echo ${a}_file 

输出结果是:foo_file

综上,变量的使用,建议一直添加花括号来进行扩展,避免扩展不存在的变量。 

大于9的位置参数也是需要给相应数字加上花括号来使用。例如,访问第11个位置变量,${11}。

空变量扩展的管理

        有的参数扩展用于处理不存在的变量或者空变量。这些参数扩展在处理缺失的位置参数和给参数赋默认值时很有用处。

常见的空变量扩展包括:

${var:-word}:如果变量 var 未定义或为空字符串,则返回 word,否则返回 var 的值。
${var:=word}:如果变量 var 未定义或为空字符串,则将 var 的值设置为 word,并返回 word,否则返回 var 的值。(位置参数不能以这种方式赋值,会报错
${var:+word}:如果变量 var 定义且非空,则返回 word,否则返回空字符串。
${var:?message}:如果变量 var 未定义或为空字符串,则输出错误信息 message,并退出脚本,否则返回 var 的值。
${var:offset:length}:如果变量 var 定义且非空,则返回从位置 offset 开始、长度为 length 的子字符串,否则返回空字符串。

以上是一些常见的空字符串扩展,还有更多的用法可以参考 bash 的文档。

需要注意的是,在进行空字符串扩展时,需要将变量名或表达式用大括号括起来。

返回变量名的扩展

bash 获取变量名扩展

在 bash 中,具有返回变量名的功能。这种功能在相当特殊的情况下才会被用到。
${!prefix*}:该扩展返回所有以 prefix 开头的变量名。
${!prefix@}:该扩展返回所有以 prefix 开头的变量名,以数组的形式返回。

注意不要缺失* 或者 @

echo ${!BASH*}

 输出结果,返回所有的以BASH开头的变量名。   

BASH BASHOPTS BASHPID BASH_ALIASES BASH_ARGC BASH_ARGV BASH_CMDS BASH_COMMAND BASH_LINENO BASH_SOURCE BASH_SUBSHELL BASH_VERSINFO BASH_VERSION

字符串操作

        bash 字符串变量大写小写转换扩展

        在bash中,可以使用${变量名^^}将字符串变量中所有字符转换为大写,${变量名,,}将字符串变量中所有字符转换为小写。
        例如,假设有一个变量str,其值为Hello World,那么${str^^}将返回HELLO WORLD,${str,,}将返回hello world。

        在 bash 中,可以使用字符串扩展来操作字符串。常见的字符串扩展包括:

        ${#parameter}:获取字符串的长度。一般来说,参数parameter是个字符串。如果参数parameter是“@”或“*”,即${#@}或者${#*},那么扩展结果就是位置参数的个数。

        ${parameter:offset:length}:获取从位置 offset 开始、长度为 length 的子字符串,如果设置有length,length不能小于0;length如果不指定,直到字符串末尾,即 ${parameter:offset};如果offset的值为负,默认表示它从字符串末尾开始,而不是字符串开头。注意!负值前必须有一个空格,以防和${parameter:-word}扩展混淆

        如果参数parameter是"@",扩展的结果是位置参数的从offset开始,length为需要获取的位置参数个数,${@:1:2}表示扩展为从$1到$2的位置参数值。

        ${parameter#pattern}:从字符串开头删除最短匹配的子字符串。

        ${parameter##pattern}:从字符串开头删除最长匹配的子字符串。

        ${parameter%pattern}:从字符串结尾删除最短匹配的子字符串。

        ${parameter%%pattern}:从字符串结尾删除最长匹配的子字符串。

        ${parameter/old/new}:用 new 替换字符串中第一个匹配的 old。

        ${parameter//old/new}:用 new 替换字符串中所有匹配的 old。

        ${parameter/#substring/new}:如果字符串以 substring 开头,则用 new 替换 substring。

        ${parameter/%substring/new}:如果字符串以 substring 结尾,则用 new 替换 substring。

以上是一些常见的字符串扩展,还有更多的用法可以参考 bash 的文档。

        参数扩展是一个比较重要的功能,进行字符串操作的扩展可以替代其他常用的命令。扩展通过取代外部程序,改善了脚本的执行效率。比如 通过参数扩展 ${#j}来取代$(echo $j | wc -c)。

算术计算和扩展

        用来对整数进行算术运算,基本形式如下所示:

$((expression)),其中expression是一个有效的算术表达式。

数字进制

        在算术表达式中,shell支持任何进制表示的整数。

不同的数字进制
符号描述
Number默认情况下,number没有任何符号,将作为十进制数字
0Number在数字表达式中,以0开始的数字被认为是八进制数字
0xnumber在数字表达式中,以0x开始的数字被认为是十六进制数字
base#numberbase进制的number

echo $((0xff)) 表示十进制整数255;

echo $((2#11111111))表示十进制整数255。

一元运算符

有两种一元运算符:+和-。它们分别用于指示一个数字是正或是负。

简单算术

算术操作符
操作符描述
+加法
-减法
*乘法
/整除
**求幂
%取模(余数)

计算余数(取模)在循环中很有用。

考虑一个场景,显示了一行数字,其中5的倍数突出展示 

#!/bin/bash

# modulo: demonstrate the modulo operator

for ((i=1;i<=20;i++));do
        # todo
        if ((i % 5 == 0));then
                # todo
                printf "<%d> " $i
        else
                printf "%d " $i
        fi
done

赋值

赋值操作符
运算符描述
parameter=value简单赋值运算。赋予parameter值为value
parameter+=value加法运算。等价于parameter=parameter+value
parameter-=value减法运算。等价于parameter=parameter-value
parameter*=value乘法运算。等价于parameter=parameter*value
parameter/=value整除运算。等价于parameter=parameter÷value
parameter%=value取模运算。等价于parameter=parameter%value
parameter++变量后增量运算。等价于parameter=parameter+1
parameter--变量后减量运算。等价于parameter=parameter-1
++parameter变量前增量运算。等价于parameter=parameter+1
--parameter变量前减量运算。等价于parameter=parameter-1

        以上,增量(++)和减量(--)运算特别有意义,它们以1为间隔 增加或减少参数的值。这种风格的表示法是从C语言衍生而来的,并且已经被其他几种编程语言采用,其中包括bash。

        ++ -- 既可能在参数前部也可能在参数尾部出现。虽然它们都以1为间隔增加或减少参数的值,两者的位置安排有一个微妙的区别。

        如果在参数前部,参数在返回前增加(或减少)。如果在参数尾部,该操作在参数返回后执行。对于大部分shell应用,前置运算操作比较常用。

位操作

有一种操作符以一种非同寻常的方式巧妙的进行数字运算,这些操作符在位层面进行执行运算。

逻辑操作

逻辑操作,比较运算 复合命令(( ))支持多种比较操作。

comparison operators
操作符描述
<=小于或等于
>=大于或等于
<小于
>大于
==等于
!=不等于
&&且 逻辑与
||或 逻辑或
expression1?expression2:expression3三元操作符。如果表达式expression1成立(非零,为true),那么执行expression2,否则执行expression3

三元操作expression1?expression2:expression3(该操作模仿C语言中的相应操作)执行一个独立的逻辑测试。它可以被用作某种意义上的if/then/else语句。它作用于三个算术表达式上(不可以是字符串),并且如果第一个表达式为真,就执行第二个表达式,否则执行第三个表达式。

#!/bin/bash

a=0
((a<1?++a:--a))
echo $a
((a<1?++a:--a))
echo $a

这是一个三元操作,本例实现了一个来回切换,每次操作被执行,变量a的值从0变为1,或从1变为0。

请注意!!在表达式内赋值操作并不能简单使用。当试图这样做时,bash将输出一个错误。

a=0
((a<1?a+=1:a-=1))

输出报错信息:

bash: ((: a<1?a+=1:a-=1: attempted assignment to non-variable (error token is "-=1")

这个问题可以通过使用括号包围赋值表达式来解决。报错原因是bash没有把a-=1当做一个整体处理。

((a<1?(a+=1):(a-=1)))

一个综合的例子,该例用到上述的知识点,输出一个简单的数字表

#!/bin/bash

# arith-loop: script to demonstrate arithmetic operators

finished=0
a=0
printf "a\ta**2\ta**3\n"
printf "=\t====\t====\n"

until ((finished));do
        b=$((a**2))
        c=$((a**3))
        printf "%d\t%d\t%d\n" $a $b $c
        ((a<10?++a:(finished=1)))
done

输出结果

a       a**2    a**3
=       ====    ====
0       0       0
1       1       1
2       4       8
3       9       27
4       16      64
5       25      125
6       36      216
7       49      343
8       64      512
9       81      729
10      100     1000

bc:一种任意精度计算语言

        shell可以处理所有的整数运算。但是如果需要执行更高级的数学运算,或者用浮点数怎么办呢?答案是无法实现。至少无法用shell直接实现。

        想要达到上述目的,需要使用外部程序。比如Perl或AWK是一个可能的解决方案或者使用专门的计算器程序bc,大多数linux系统都支持程序bc。

随着脚本编程经验的增长,有效而巧妙地操纵字符串和数字将会是非常重要的!


可以关注作者微信公众号,追踪更多有价值的内容!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值