Shell

北战南征 提交于 2019-12-04 18:20:39

一、  Shell

 

1.  Shell 简介

1. Shell 是一个用 C 语言编写的程序,它既是一种命令语言,又是一种程序设计语言,它是用户使用 Linux 的桥梁2. Shell 脚本(Shell Script),是一种为 Shell 编写的脚本程序3. 用户开发的 Shell 脚本可以驻留在命令搜索路径的目录之下(通常是 /bin、/usr/bin 等),像普通命令一样使用。如果打算反复使用编好的 Shell 脚本,可以开发出自己的新命令4. Linux 的 Shell 种类众多,常见的有:   1)Bourne Shell(/usr/bin/sh 或 /bin/sh)   2)Bourne Again Shell(/bin/bash)   3)Shell for Root(/sbin/sh)   ....5. 本文关注的是 Bash,也就是 Bourne Again Shell   1)由于易用和免费,Bash 在日常工作中被广泛使用   2)Bash 也是大多数 Linux 系统默认的 Shell   3)一般情况下,人们并不区分 Bourne Shell 和 Bourne Again Shell,所以 #!/bin/sh 也可以写为 #!/bin/bash,#! 是一个约定的标记,其路径告诉系统这个脚本需要什么解释器来执行,即使用哪一种 Shell6. Shell 脚本的编写   1)使用 vi/vim 命令来创建文件,新建一个文件 test.sh,扩展名为 sh( sh 代表 Shell,扩展名并不影响脚本执行,见名知意就好 )   2)第一行一般为:#!/bin/bash   3)如:      #!/bin/bash      echo "Hello World !"7. Shell 脚本有两种执行方法:   1)作为可执行程序,如:      # chmod a+x ./test.sh      # ./test.sh      注意:这个要求在 Shell 脚本的开头必须指明执行该脚本的具体 Shell,即 #!/bin/bash   2)作为解释器参数,这种运行方式是直接运行解释器,其参数就是 Shell 脚本的文件名,如:      # /bin/bash test.sh       # /bin/php test.php      注意:这种方式运行的脚本,不需要在第一行指定解释器信息,写了也没意义8. Shell 注释,在脚本文件中以 "#" 开头的行就是注释,会被解释器忽略。sh 里没有多行注释,只能每一行开头加一个 # 号   1)每一行开头加个 # 符号太费力了,可以把这一段要注释的代码,定义成一个函数,没有地方调用这个函数,这块代码就不会执行,达到了和注释一样的效果

 

2.  echo、read、printf 命令

1. echo 命令,自带换行功能   1)显示普通字符串,如:      echo "It is a test"  # 双引号可以省略   2)显示转义字符,如:      echo "\"It is a test\""  # 结果:"It is a test"   3)显示不换行,如:      echo -e "OK!\c"  # -e 开启转义,\c 不换行      echo "It it a test"  # 结果:OK! It is a test   4)显示命令执行结果,如:      echo `date`  # 结果将显示当前日期   5)显示变量值,如:      echo ${your_name}   6)显示结果重定向至文件,如:      echo "It is a test" > myfile # > 表示覆盖重定向, >> 表示追加重定向2. read 命令   1)read 命令从标准输入中读取一行,并把输入行的每个字段的值指定给 Shell 变量,如:      #!/bin/bash       read -p "请输入:" str      echo "${str} It is a test"      # 结果      请输入:hello      hello It is a test3. printf 命令   1)默认 printf 不会像 echo 自动添加换行符,我们可以手动添加 \n    2)printf 命令模仿 C 程序库(library)里的 printf() 程序,因此使用 printf 的脚本比使用 echo 移植性好   3)printf 命令的语法:printf 格式控制 参数列表 ,如:      printf "%-6s %-6s %-4s\n" 姓名 性别 体重kg       printf "%-6s %-7s %-4.2f\n" 小明 男 66.1234       # 结果      姓名    性别    体重kg       小明    男      66.12      a. %s %c %d %f 都是格式替代符,格式只指定了一个参数,如果没有 arguments,那么 %s 用 NULL 代替,%d 用 0 代替      b. %-6s 指一个宽度为 6 个字符( - 表示左对齐,没有则表示右对齐),任何字符都会被显示在6个字符宽的字符内,如果不足则自动以空格填充,超过也会将内容全部显示出来      c. %-4.2f 指格式化为小数,其中 .2 指保留 2 位小数

 

3.  Shell 变量

1. 定义变量,变量名前面不加美元符号,如:   your_name="tom"   your_company="alibaba"   注意:变量名和等号之间不能有空格2. 使用一个定义过的变量,只要在变量名前面加美元符号即可,如:   echo $your_name   echo ${your_company}hello   注意:花括号是可选的,为了帮助解释器识别变量的边界。如果不给 your_company 变量加花括号解释器就会把 your_companyhello 当成一个变量。推荐给所有变量加上花括号,这是个好的编程习惯3. 可以将一个命令的执行结果赋值给变量。有两种形式:   1)`commands` ,"`" 是反单引号,如:      dirPath=`pwd`   2)$(commands),如:      dirPath=$(pwd)4. 设置一个变量为只读属性   1)有些重要的 Shell 变量,赋值后不应该修改,那么可设置它为 readonly ,如:         oracle_home=/usr/local/oracle/bin      readonly oracle_home5. Shell 字符串   1)字符串是 Shell 编程中最常用最有用的数据类型,字符串可以用单引号,也可以用双引号,也可以不用引号,如:      str='this is a string'      str="this is a string"      str=this is a string   2)单引号字符串的限制      a. 单引号里的任何字符都会原样输出,即单引号字符串中的变量是无效的      b. 单引号字串中不能出现单引号,对单引号使用转义符后也不行   3)双引号的优点      a. 双引号里可以有变量      b. 双引号里可以出现转义字符   4)获取字符串长度:${#str},如:      string="abcd"       echo ${#string} #输出 4   5)提取子串,如:      string="alibaba is a great company"       echo ${string:1:4} #输出 liba   6)查询子串位置,以下脚本中 "`" 是反单引号,而不是单引号 "'"      string="alibaba is a great company"       echo `expr index "$string" is`6. Shell 数组   1)bash 支持一维数组(不支持多维数组),并且没有限定数组的大小,数组元素的下标从 0 开始编号   2)定义数组,用括号来表示数组,数组元素用 "空格" 符号分割,如:      array_name=(value0 value1 value2 value3)      # 还可以单独定义数组的各个分量:      array_name[0]=value0
      array_name[i]=valuei      # 也可以用 declare 命令显式声明一个数组,一般形式是:declare -a 数组名   3)读取数组元素值,如:      valuen=${array_name[n]}   4)使用 * 或 @ 符号可以获取数组中的所有元素,如:      echo ${array_name[*]}      echo ${array_name[@]}   5)获取数组长度的方法与获取字符串长度的方法相同,如:      # 取得数组元素的个数      length=${#array_name[@]}       # 或者       length=${#array_name[*]}       # 取得数组单个元素的长度       lengthi=${#array_name[i]}    

 

4.  Shell 传递参数

1. 在执行 Shell 脚本时,向脚本传递参数,多个参数用空格分割,脚本内获取参数的格式为:$n,n 是一个数字。其中 $0 为执行的文件名,$1 为执行脚本的第一个参数,$2 为执行脚本的第二个参数,.... 如:test.sh   #!/bin/bash   echo "执行的文件名:$0";   echo "第一个参数为:$1";    echo "第二个参数为:$2";    # 测试结果   # chmod a+x ./test.sh   # ./test.sh hello world   执行的文件名:test.sh   第一个参数为:hello   第二个参数为:world2. 另外,还有几个特殊字符用来处理参数   1)$# 传递到脚本的参数个数   2)$* 以一个字符串形式显示所有向脚本传递的参数。一般在使用时加引号,即 "$*" ,表示以 "$1 $2 ... $n" 的形式输出所有参数,输出结果是一个字符串   3)$@ 以多个字符串形式显示所有向脚本传递的参数。一般在使用时加引号,即 "$@" ,表示以 "$1" "$2" ... "$n" 的形式输出所有参数,输出结果是多个字符串   4)$$ 脚本运行的当前进程 ID 号   5)$! 后台运行的最后一个进程的 ID 号   6)$? 显示最后命令的退出状态。0 表示没有错误,其他任何值表明有错误

 

5.  Shell 函数定义

1. Linux Shell 允许用户定义函数,然后可以在 Shell 脚本中随便调用2. Shell 中函数的定义格式如下:   [ function ] funname [()]{     action;    [return int;]   }   1)可以带 function fun() 定义,也可以直接 fun() 定义,不带任何参数   2)return 函数返回值,如果不加 return,将以最后一条命令的运行结果作为返回值。return 后跟数值   3)函数返回值在调用该函数后通过 $? 来获得3. 在 Shell 中,调用函数时可以向其传递参数。在函数体内部,通过 $n 的形式来获取参数的值,同 Shell 传递参数,如:   #!/bin/bash   funWithParam(){      echo "第一个参数为 ${1}"      echo "第十个参数为 ${10}"      echo "参数总数有 $# 个"      echo "作为一个字符串输出所有参数 $*"   }   funWithParam 1 2 3 4 5 6 7 8 9 10 11   # 结果   第一个参数为 1     第十个参数为 10   参数总数有 11 个   作为一个字符串输出所有参数 1 2 3 4 5 6 7 8 9 10 11

 

6.  Shell 运算符

1. 注意:   1)表达式和运算符之间要有空格,例如 2+2 是不对的,必须写成 2 + 2   2)完整的运算表达式要被反单引号 ` ` 包含,如:`expr $a + $b`   3)条件表达式要放在方括号之间,并且要有空格,例如: [$a==$b] 是错误的,必须写成 [ $a == $b ]   4)条件测试命令 test ,语法:test 表达式 ,效果等同于方括号 []。如:test $a == $b 等价于 [ $a == $b ]2. 算术运算符   假定变量 a 为 10,变量 b 为 20   1)+  加法,如:`expr $a + $b`   2)-  减法,如:`expr $a - $b`   3)*  乘法,如:`expr $a \* $b`,在 MAC 中 Shell 的 expr 语法是:$((表达式)),此处表达式中的 "*" 不需要转义符号 "\"   4)/  除法,如:`expr $b / $a`   5)%  取余,如:`expr $b % $a`   6)=  赋值,如:a=$b   7)== 相等,如:[ $a == $b ] 返回 false   8)!= 不相等,如:[ $a != $b ] 返回 true3. 关系运算符,关系运算符只支持数字,不支持字符串,除非字符串的值是数字   假定变量 a 为 10,变量 b 为 20   1)-eq  相等,如:[ $a -eq $b ] 返回 false   2)-ne  不相等,如:[ $a -ne $b ] 返回 true   3)-gt  大于,如:[ $a -gt $b ] 返回 false   4)-lt  小于,如:[ $a -lt $b ] 返回 true   5)-ge  大于等于,如:[ $a -ge $b ] 返回 false   6)-le  小于等于,如:[ $a -le $b ] 返回 true4. 布尔运算符   假定变量 a 为 10,变量 b 为 20   1)-a  与运算,如:[ $a -lt 20 -a $b -gt 100 ] 返回 false   2)-o  或运算,如:[ $a -lt 20 -o $b -gt 100 ] 返回 true   3) !  非运算,如:[ ! false ] 返回 true5. 逻辑运算符   假定变量 a 为 10,变量 b 为 20   1)&&  逻辑的 AND ,如:[[ $a -lt 100 && $b -gt 100 ]] 返回 false   2)||  逻辑的 OR  ,如:[[ $a -lt 100 || $b -gt 100 ]] 返回 true6. 字符串运算符   假定变量 a 为 "abc",变量 b 为 "efg"   1) =  相等,如:[ $a = $b ] 返回 false   2)!=  不相等,如:[ $a != $b ] 返回 true   3)-z  检测字符串长度是否为 0,如:[ -z $a ] 返回 false   4)-n  检测字符串长度是否不为 0,如:[ -n $a ] 返回 true7. 文件测试运算符用于检测 Linux 文件的各种属性   假定 file="/usr/local/temp/test.sh",它是大小为 100 字节,具有 rwx 权限的文件   1)-d  检测文件是否是目录,如:[ -d $file ] 返回 false   2)-f  检测文件是否是普通文件,如:[ -f $file ] 返回 true   3)-p  检测文件是否是有名管道,如:[ -p $file ] 返回 false   4)-r  检测文件是否可读,如:[ -r $file ] 返回 true   5)-w  检测文件是否可写,如:[ -w $file ] 返回 true   6)-x  检测文件是否可执行,如:[ -x $file ] 返回 true   7)-s  检测文件大小是否大于 0,如:[ -s $file ] 返回 true   8)-e  检测文件或目录是否存在,如:[ -e $file ] 返回 true

 

7.  Shell 流程控制

1. if 语法格式:
   if condition1 
   then 
      command1 
   elif condition2 
   then 
      command2 
   else 
      commandN 
   fi

2. for 语法格式:
   for var in items
   do 
     commands
   done

3. while 语法格式:
   while condition 
   do 
     commands
   done

4. until 语法格式:
   until condition 
   do 
     commands
   done

5. 无限循环语法格式:
   1)while :
      do
        command
      done
   2)while true
      do
        command
      done
   3)for (( ; ; ))

5. case 语法格式:每个 case 分支用右圆括号,用两个分号表示 break
   #!/bin/bash
   while :
   do
       echo -n "输入 1 到 5 之间的数字:"
       read num
       case $num in
           1|2|3|4|5) echo "你输入的数字为 $num!"
           ;;
           *) echo "你输入的数字不是 1 到 5 之间的! 游戏结束"
              break
           ;;
       esac
   done

6. continue 命令与 break 命令类似,只有一点差别,它不会跳出所有循环,仅仅跳出当前循环

 

8.  Shell 输入/输出重定向

1. 一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件:
   1)标准输入文件(stdin ):文件描述符为 0,Unix 程序默认从 stdin 读取数据
   2)标准输出文件(stdout):文件描述符为 1,Unix 程序默认向 stdout 输出数据
   3)标准错误文件(stderr):文件描述符为 2,Unix 程序会向 stderr 流中写入错误信息
   默认情况下,command > file 将 stdout 重定向到 file;command < file 将 stdin 重定向到 file;如果希望 stderr 重定向到 file,可以这样写:command 2 > file2. 重定向命令   1)将输出以覆盖的方式重定向到 file      command > file   2)将输出以追加的方式重定向到 file      command >> file   3)将输入重定向到 file      command <  file    4)将文件描述符为 n 的文件重定向到 file      n >  file   5)将文件描述符为 n 的文件以追加的方式重定向到 file      n >> file    6)将输出文件 m 和 n 合并      n >& m    7)将输入文件 m 和 n 合并      n <& m   8)将开始标记 tag 和结束标记 tag 之间的内容(document) 作为输入传递给 command      command << tag           document       tag          注意:结尾的 tag 一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和 tab 缩进   9)command 命令将 stdin 重定向到 file1,将 stdout 重定向到 file2。即执行 command,从文件 file1 读取内容,然后将输出写入到 file2 中      command < file1 > file2   10)将 stdout 和 stderr 合并后重定向到 file       command > file 2>&1   11)/dev/null 文件是一个特殊的文件,写入到它的内容都会被丢弃;如果尝试从该文件读取内容,那么什么也读不到。但是 /dev/null 文件非常有用,将命令的输出重定向到它,会起到"禁止输出"的效果      a. 如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null :         command > /dev/null      b. 如果希望屏蔽 stdout 和 stderr :         command > /dev/null 2>&1  

 

9.  Shell 文件包含

1. Shell 文件包含的两种语法格式:
   1). filename  注意点号(.)和文件名中间有一空格
   2)source filename2. 实例   1)创建两个 Shell 脚本文件      定义 test1.sh 如下:      #!/bin/bash      url="http://www.baidu.com"      定义 test2.sh 如下:      #!/bin/bash      . ./test1.sh  # 使用 . 号来引用 test1.sh 文件或者使用 source ./test1.sh 包含文件代码      echo "百度地址:$url"   2)测试结果      # chmod +x test2.sh      # ./ test2.sh      百度网址:http://www.baidu.com   3)注意:被包含的文件 test1.sh 不需要可执行权限

 

10.  参考资料

https://www.w3cschool.cn/linux/linux-shell.html
https://www.w3cschool.cn/shellbook/

 

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!