Shell-编程基础(一)

Shell-编程基础(一)

By timebusker on May 29, 2018

IFS的默认值为:空白(包括:空格,制表符,换行符).

Linux脚本开头

#!/bin/sh是指此脚本使用/bin/sh来解释执行,#!是特殊的表示符,其后面根的是此解释此脚本的shell的路径。 其实第一句的#!是对脚本的解释器程序路径,脚本的内容是由解释器解释的,我们可以用各种各样的解释器来写对应的脚本。 比如/bin/csh脚本,/bin/perl脚本,/bin/awk脚本,/bin/sed脚本,甚至/bin/echo等等。

Shell脚本执行权限

给shell脚本添加执行权限,可以简单的通过./mine_shell.sh来执行脚本,否则只能通过sh mine_shell.sh执行脚本。

# 修改脚本执行权限
chmod +x mine_shell.sh  

变量

shell编程中分为两种变量,第一种是我们自己定义的变量(自定义变量), 第二种是Linux已定义的环境变量(环境变量, 例如:$PATH, $HOME 等…, 这类变量我们可以直接使用)。

自定义变量和系统环境变量的用法,使用很简单,就是使用$符号加上变量名就行了。记住:定义变量不用$符号,使用变量要加$就行了。

我们在自定义变量时,使用了双引号,在shell编程中, 如果变量出现空格或者引号,那么也必须加引号, 否则就可以省略。还有一点需要注意,定义变量的时候,“=”左右千万不要有空格啊。

定义变量时使用单引号:赋值中不能出现空格,赋值中可以通过  $  引用其他变量,此时单引号可以省略。
定义变量时使用双引号:赋值中可以包含转义字符类内容而不被识别,不能正常引用其他变量。

image

数据运算

整数运算

在shell中,有两种方式能实现整数运算,一种是使用expr命令, 另外一种是通过方括号($[])来实现。

#!/bin/bash
#输出13
expr 10 + 3
#输出10+3
expr 10+3
#输出7
expr 10 - 3
#输出30
expr 10 \* 3
#输出3
expr 10 / 3
#输出1
expr 10 % 3
#将计算结果赋值给变量
num1=$(expr 10 % 3)
#将计算结果赋值给变量
num2=`expr 10 % 3`
  • 注意:
    • 在以上的乘法(*)中,我们用了反斜线()来转义,不然会报错。
    • 运算符前后必须还有空格,否则会被直接当作字符串返回。
    • 如果要将计算结果保存到变量,就需要用到我们上篇文章讲到的那两种方式($() 或者 ``)来替换命令了。

整数运算推荐使用

方括号($[]):讲运算表达式包含在括号内,简单明了,避免歧义,推荐使用。

#!/bin/bash
num1=10
num2=3
#输出num1 + num2=13
echo "num1 + num2=$[$num1 + $num2]"
#输出num1+num2=13
echo "num1+num2=$[$num1+$num2]"
#输出num1 - num2=7
echo "num1 - num2=$[$num1 - $num2]"
#输出num1 * num2=30
echo "num1 * num2=$[$num1 * $num2]"
#输出num1 > num2=1
echo "num1 > num2=$[$num1 > $num2]"
#输出num1 < num2=0
echo "num1 < num2=$[$num1 < $num2]"
#将运算结果赋值给变量,输出num3=3
num3=$[$num1 / $num2]
echo "num3=$num3"

浮点运算

在shell中,做浮点运算一般是用bash的计算器(bc)。在shell脚本中,一般我们的使用方法是:
variable=$(echo "options; expression" | bc)

#!/bin/bash
#表示 10/3, 保留2位小数,将结果赋值给了num, 输出3.33
num=$(echo "scale=2; 10 / 3" | bc)
echo $num

条件选择

if-then语句

if command
then
    commands
fi
----------------------------------------
if command; then
    commands
fi

在shell脚本的if其实是根据紧跟后面的那个命令的退出状态码来判断是否执行then后面的语句的。
关于退出状态码,你只需要记住:正常退出(命令执行正常)的状态码是0, 非正常退出的状态码不是0(有不少)。 以上语句的语义为: 如果if后面的命令执行正常(状态码0),那么就执行then后面的语句。否则不执行。 fi代表if语句的结束。

if-then-else语句

if command; then
    doSomeThing
else
    doSomeThing
fi
----------------------------------------
if command1;then
    doSomeThing 
elif command2; then
    doSomeThing
fi

test命令

test命令用于if-then或者if-then-else语句中,主要用于判断列出的条件是否成立,如果成立,就会退出并返回退出状态码0,否则返回非0。 这意味着我们可以通过test命令来写表达式命令了。

test命令只能判断一下三类条件:

  • 数值比较
  • 字符串比较
  • 文件比较
数值比较

image

使用双括号

数值比较除了使用以上文本形式的比较符运算,还可以使用常规数学比较符,双括号命令(( expression ))允许你在比较过程中使用高级数学表达式。

#!/bin/bash
num1=100
num2=200
if (( num1 > num2 )) ;then
    echo "num1 > num2"
else 
    echo "num2 <= num2"  

注意:括号里面两边都需要有空格

字符串比较

image

使用双方括号

双方括号命令提供了针对字符串比较的高级特性。它不仅解决了使用test所带来的一系列毛病,还提供了一些test命令所没有的高级用法。 双方括号命令的格式如:[[ expression ]]

case语句

语法:
case var in     var变量
    patten 1)   匹配模式1 a|b|c  |和or类似
    command...  需要执行的命令
    ;;      命令执行完毕
    patten 2)
    command...
    ;;
    *)      默认值,没有匹配的模式
    command...  
    ;;
esac            代表case语句的结束

使用示例:

#!/bin/bash
case $num in
1)
    echo "num=1";;
2)
    echo "num=2";;
3)
    echo "num=3";;
4)
    echo "num=4";;
*)
    echo "defaul";;
esac 

for

for-in语句

list代表要循环的值,在每次循环的时候,会把当前的值赋值给var(变量名而已,随意定), 这样在循环体中就可以直接通过$var获取当前值了。

for var in list 
do
    commands
done

程序示例:

#!/bin/bash
# 根据空格将abcde分割,然后依次输出出来
for str in a b c d e
do
    echo $str
done    

造成这个结果的原因是:for…in循环默认是循环一组通过空格或制表符(tab键)或换行符(Enter键)分割的值。 这个其实是由内部字段分隔符配置的,它是由系统环境变量IFS定义的。当然,既然是由环境变量定义的,那当然也就能修改啊。

修改IFS值

#!/bin/bash
#定义一个变量oldIFS保存未修改前的IFS的值
oldIFS=$IFS
#修改IFS值,以逗号为分隔符
IFS=$','
list=a,b,c,d,e
list2="a b c d e"
for var in $list
do
    echo $var
done
for var2 in $list2
do
    echo $var2
done
#还原IFS的值
IFS=$oldIFS

C语言风格的for循环

bash中c语言风格的for循环遵循如下格式:

#!/bin/bash
for (( i = 0; i <= 10; i++ ))
do
    echo $i
done  

while循环

如果你习惯了其它语言的while循环,那么到这儿你又会发现这个while循环有点变态了。 与其它编程语言while的不同在于:在bash中的while语句,看起来似乎是结合了if-then语句(参考上一篇)和for循环语句。其基本格式如下:

while test command 
do
    other commands
done

until循环语句

在掌握while循环语句之后, until语句就很简单了。until语句就是与while语句恰好相反, while语句是在test命令退出状态码为0的时候执行循环, 而until语句是在test命令退出状态码不为0的时候执行。

#!/bin/bash
flag=0
until (( $flag > 10 ))
do
    echo $flag
    flag=$[ $flag + 1 ]
done

控制循环

  • break用于跳出当前循环。

命令行参数处理

根据参数位置获取参数

bash shell可根据参数位置获取参数。通过 $1 到 $9 获取第1到第9个的命令行参数。$0为shell名。 如果参数超过9个,那么就只能通过${}来获取了, 例如获取第10个参数,那么可以写为${10}。
$0默认会获取到当前shell文件的名称,但是,它也包含(./),如果你以完整路径运行,那么这还会包含目录名。因此,上面通过basename命令来获取单纯的文件名$(basename $0)。

读取所有参数

在bash shell中通过 $# 可获取参数总数。

#!/bin/bash
# 获取参数总数,并依次读取   
for (( index=0; index <= $#; index++ ))
do
    echo ${!index}
done

我们通过 $# 获取总参数个数。然后通过循环获取每个位置的参数。注意: 按照正常的理解,上面的 ${!index} 应该是 ${$index}才对, 对吧? 但是,由于${}内不能再写$符号,bash shell在这个地方是用了!符号,所以以上才写为了${!index}。

在bash shell中还可以通过 $* 和 $@ 来获取所有参数。但是这两者之间有着很大的区别:

  • $* 会将命令行上提供的所有参数当作一个单词保存, 我们得到的值也就相当于是个字符串整体.
  • $@ 会将命令行上提供的所有参数当作同一字符串中的多个独立的单词。

获取屏幕输入

我们在shell执行过程中获取用户的输入,以此与用户进行交互。这是通过read命令来实现的。下面就来看看其用法:

  • 单个输入
    #!/bin/bash
    # -n参数表示不换行   
    echo -n "yes or no(y/n)?"
    read choice
    echo "your choice: $choice"
    

    事实上,我们可以不指定read后面的变量名,如果我们不指定, read命令会将它收到的任何数据都放进特殊环境变量REPLY中.

    #!/bin/bash
    echo -n "yes or no(y/n)?"
    read
    echo "your choice: $REPLY"   
    
  • 多个输入
    #!/bin/bash
    read -p "what's your name?" first last
    echo first: $first
    echo last: $last