51Testing软件测试论坛

标题: shell脚本基本语法 [打印本页]

作者: 小小糖    时间: 2019-2-25 15:22
标题: shell脚本基本语法
本帖最后由 小小糖 于 2019-2-25 15:24 编辑

默认一行处理一条命令,但也可以用;分割多条命令,按顺序执行。
脚本文件中第一行必须用#! path-to-shell指定所用的shell。
除了第一行之外的#都是注释的开始标记,注释此行中#之后的内容
脚本最好要有执行权限,最好以sh作为后缀


1. 变量
变量的值都是字符串,一个变量可以处于已定义和未定义两种状态,已定义的变量可以有值也可以为空。
定义变量时不要有空格:variable=value
命令替换

可以从命令输出中提取信息,并赋值给变量。有两种形式:
variable=commands: commands用反引号字符扩起来。
variable=$(commands)

命令替换中的命令在subshell中执行,其中对变量的改变并不会反映到当前shell脚本中。

2. 重定向
重定向其实是文件描述符的复制,实现通过一个描述符访问另一个文件。
输出重定向

把某个输出流的内容通过另一个输出流输出。 比如:
echo "hello world" > tempfile,其实是以截断只写方式打开tempfile文件(文件描述符fd),然后把文件描述符1(标准输出)作为fd的复制,并关闭fd(如果明白linux内核中file和inode的关系会更好理解),这样程序中输出给文件描述符1的数据都重定向给了tempfile。
echo "hello world" >> tempfile,与上面的区别是以添加的方式打开tempfile。
cat /etc/shadow 2> error,错误信息会放到error文件中。

输入重定向
把某个文件当作标准输入,从中读取数据。 比如:
cat <error

这里cat本应该从标准输入0接收数据然后输出到标准输出,输入重定向相当于在文件描述符0上打开文件error
内联输入重定向无需使用文件进行重定向,只需要在命令行中指定用于输入重定向的数据。必须指定文本标记来划分数据的开始和结尾。
  1. $ wc << flag
  2. > data
  3. > haha
  4. > flag
  5. 2 2 8
  6. $
复制代码
其本质是把你临时输入的内容缓存下来作为命令的输入。
更复杂的重定向
a.out 3<>temp: 在文件描述符3上打开temp文件进行读写。 <>左边是文件描述符,而右边是文件名,如果想要重定向到另一个文件描述符,可用&n的形式。
a.out 1>&2表示把原本输出给标准输出的内容交给标准错误。

3. 管道
管道其实是一个环形缓冲区,左边的程序把数据放入缓冲区,右边的程序把数据读走。表现出来就是右边的程序把左边程序的输出作为输入。

4. 数值计算
shell不擅长数值计算,它的所有变量都是字符串类型的。
把一个表达式结果赋值给某个变量可以这样:
variable=$[ operation ]

但是operation只能是整数计算。
bc计算器(bash calculator): bc是一个交互式计算器。可以定义变量,使用注释,创建函数和编程语句等,功能丰富。
bc中的scale变量定义了小数的位数,默认时为0,使用小数的话记得先设置这个变量。

可以通过variable=$(echo "options; expression" | bc)的形式在shell脚本中使用bc。在options中可以定义变量,expression中定义了需要执行的数学计算,输出结果赋值给variable。比如:
  1. $ cat test.sh
  2. #! /bin/bash
  3. var1=100
  4. var2=40
  5. var3=$(echo "scale=4; $var1 / $var2" | bc)
  6. echo ans is $var3
  7. $
复制代码
如果需要大量的运算,难以在一行内列出多个表达式,可以使用内联重定向:
  1. ➜  shell_scripts git:(dev) ✗ cat bc1.sh
  2. #! /bin/bash

  3. var1=10.34
  4. var2=21.33
  5. var3=33.2
  6. var4=87

  7. var5=$(bc  EOF
  8. scale=4
  9. a1=($var1 * $var2)
  10. b1=($var3 + $var4)
  11. a1 + a2
  12. EOF
  13. )

  14. echo ans is $var5
  15. ➜  shell_scripts git:(dev) ✗ bash bc1.sh
  16. ans is 220.5522
  17. ➜  shell_scripts git:(dev) ✗
复制代码
5. 退出脚本shell中变量$?来保存上个已执行命令的退出状态码。

默认情况下,shell脚本会以脚本中最后一个命令的退出状态码退出。

脚本中可以使用exit <status>来指定脚本的退出状态码。

6. 流程控制if-then语句
  1. if  command1;then
  2.         commands
  3. elif comand2;then
  4.         commands
  5. else
  6.         commands
  7. fi
复制代码
if语句会运行if后面的命令,如果命令的退出状态码是0(正常退出),位于then部分的命令就会被执行;否则,else部分的命令会被执行。elif分支或者else分支可以省略。


test命令
用法:test [expression]
如果expression为true,test命令的返回状态为0,否则为1(包括无法识别的表达式)。

expression的形式多种多样:
(exp): 就是exp的值
!exp: exp取反
exp1 -a exp2: exp1和exp2相与的结果
exp1 -o exp2: exp1和exp2相或的结果


字符串比较
-n string: string的长度非0
string: 等价与-n string
-z string: string的长度为0
str1 = str2:这两个字符串是否相等
str1 != str2:
str1 < str2:
str1 > str2:

数值比较
int1 -eq int2:把两边当成整数,比较是否相同
int1 -ge int2: int1大于或等于 int2?
int1 -gt int2: int1 大于 int2 ?
int1 -le int2: 小于或等于
int1 -lt int2: 小于
int1 -ne int2: 不等于

文件比较
-d file: 文件是否存在且为目录
-e file: 是否存在
-f file: 是否存在且为文件
-r file: 是否存在且可读
-s file: 是否存在且非空
-w file: 是否存在且可写
-x file: 是否存在且可执行
-O file: 是否存在且属当前用户所有
-G file: 是否存在且默认组与当前用户相同
file1 -nt file2: 左边比右边新
file1 -ot file2: 左边比右边旧
test命令增强了if语句的判断能力,把逻辑表达式转换成命令执行状态。

bash shell提供了另一种条件测试方法,无需使用test指令。
  1. if [ condition ];then
  2.         commands
  3. fi
复制代码
这种形式也可以使用 [ conditions1 ] && [condition2 ]和 [ condition1 ] || [condition2]这样的复合逻辑式。

在字符串比较时,>要进行转义,否则认为是重定向。

高级特性
双括号命令
$((expression))形式:这种形式的expression可以是任意的数学赋值或者比较表达式,其中的变量不用$展开。支持自增自减、移位、位运算等运算符。
可以在if语句中使用双括号命令,也可以在脚本的普通命令里使用它来进行数学赋值。
不需要将双括号里的大于号转义

双方括号
[[expression]]双方括号提供了字符串比较的高级特性。它拥有test命令中的标准字符串比较,还提供了模式匹配功能。比如:
  1. ➜  cat test_double_square_brackets.sh
  2. #! /bin/bash
  3. # using pattern matching
  4. #
  5. if [[ $USER == i* ]] ; then
  6.         echo "Hello $USER"
  7. else
  8.         echo "Sorry, I don't know you"
  9. fi
  10. ➜  bash test_double_square_brackets.sh
  11. Hello invoker
复制代码

注意:普通的if语句使用一个等号判断是否想等,而双括号和双方括号都是采用两个等号。


case命令
  1. case variable in
  2.         pattern1 | pattern2)
  3.                 commands1;;
  4.         pattern3)
  5.                 commands2;;
  6.         *)
  7.                 default-commands;;
  8. esac
复制代码

case命令从上到下寻找,如果变量与某个分支的模式匹配,则执行此分支的命令,然后退出case。由于*匹配所有字符串,可作为最后的默认分支。分支的命令块结束时要用两个分号。


循环for命令

for命令允许你创建一个便利一系列值的循环。每次使用其中的一个值来执行定义好的一组命令。

  1. for var in list;do
  2.         commands
  3. done
复制代码

list是由IFS(internal field separator)分隔的字符串。默认是IFS是空格、制表符或者换行符。也可以改变IFS的值:IFS=' \n'表示换行和冒号都是字段分隔符。(换行和制表符用$'\n'和$'\t'表示)

bash对for命令的扩展

  1. for ((variable assignment; condition; iteration process));do
  2.         commands
  3. done
复制代码

这种类似c语言风格的for循环并没有遵循shell标准:变量赋值可以有空格;条件中的变量不用$展开;迭代过程的算术表达式不需要expr。


while命令
  1. while test-command;do
  2.         commands
  3. done
复制代码

test-command可以是命令本身(判断返回状态),也可以是用test或者方括号封装的逻辑表达式。测试命令可以指定多个,只有最后一个巨额定判断结果。


until命令
  1. until test-command;do
  2.         commands
  3. done
复制代码

until命令与while类似,只是当条件成立是退出循环。


break和continue

与C语言不同的是break n可以直接跳出n层循环。


处理循环的输出

如果想要对某个循环中的输出进行重定向或者管道可以在done命令之后添加相应的处理。





作者: qqq911    时间: 2019-4-16 11:04
感谢分享
作者: Miss_love    时间: 2020-12-25 16:11
感谢分享




欢迎光临 51Testing软件测试论坛 (http://bbs.51testing.com/) Powered by Discuz! X3.2