《信息安全与设计》第十章学习笔记

第十章:sh编程

知识总结

1.sh脚本
sh脚本是一个包含sh语句的文本文件,命令行解释程序sh要执行该语句。
创建sh文件:
#! /bin/bash
使用 chmod -x mysh 使其可执行,然后运行该sh文件。

2.sh脚本与C程序
通过学习,我明白了sh脚本和C程序有一些相似之处,但它们在根本上是不同的。sh是一个解释程序,逐行读取sh脚本文件并直接执行这些行。若是可执行命令且为内置命令则直接执行,否则复刻一个子进程来执行命令,并等待子进程终止再继续,每个变量都是字符串,sh脚本不需要main函数,第一个可执行语句是程序的入口点。而C语言必须先编译链接到一个二进制可执行文件,然后通过主sh的子进程运行二进制可执行文件,每个变量必须有一个类型,必须有main()函数。

3.命令行参数
可使用与运行sh命令完全相同的参数调用sh脚本,以mysh文件举例
mysh one two three
可通过位置参数$0、$1、$2等访问命令行参数,10以上参数必须称为${n},可用内置变量$#和$*计数并显示命令行参数

  • $# = 命令行参数$1到$n的数量
  • $* = 所以命令行参数,包括$0
  • $S = 执行sh的进程PID
  • $? = 最后一个命令执行的退出状态

4.sh变量
(1)内置变量
PATH、HOME、TERM等
(2)变量赋值
variable=string

5.sh中的引号
sh中的特殊字符,如$、/、*、>、<等,要想把它们用作普通字符,可使用\或单引号来引用它们。
内置命令

  • .file:读取并执行文件
  • break [n]:从最近的第n个嵌套循环中退出
  • cd [dirname]:更换目录
  • continue [n]:重启最近的第n个嵌套循环
  • eval [arg...]:计算一次参数并让sh执行生成的命令。
  • exec [arg...]:通过这个sh执行命令,sh将会退出。
  • exit [n]:使sh退出,退出状态为n。
  • export [var…]:将变量导出到随后执行的命令.
  • read [var...]:从stdin 中读取一行并为变量赋值。
  • set [arg...]:在执行环境中设置变量。
  • shift:将位置参数$2 $3...重命名为 $1 $2...。
  • trap [arg] [n]:接收到信号n后执行参数。
  • umask [ddd]:将掩码设置为八进制数 ddd 的。
  • wait pid]: 等待进程 pid,如果没有给出pid,则等待所有活动子进程。
  • read命令:当sh执行read命令时,它会等待来自stdin的输入行。

6.Linux命令
(1)echo命令
echo只是将参数字符串作为行回显到stdout,通常将相邻的多个空格压缩为一个空格,除非有冒号

(2)expr命令
将两个参数字符串转换为数字,然后对数字执行操作OP,再将得到的数字转换回字符串
expr string1 op string2

(3)管道命令
在sh中经常使用管道作为过滤器
ps -ax | grep httpd
cat file | grep word

7.命令替换
在sh中,$A会被替换成A值。同样,当sh遇到‘cmd’或$(cmd)时,它会先执行cmd,然后用执行的结果字符串替换成$(cmd)。
echo $(ls dir)

8.sh控制语句
(1)if-else-fi语句

  if [condition]
    then
      statemates
    else
      statements
  fi

(2)if-elif-else-fi语句

if [condition]
    then
      statemates
    else
      statements
  fi

(3)for语句

for VARIABLE in string1 string2 ... stringn
   do
     commands
   done

(4)while语句

while [condition]
  do 
    commands
  done

(5)until-do语句

until [$ANS = "give up"]
  do
    echo -n "enter your answer"
    read ANS
  done

(6)case 语句

  case $variable in
    pattern1)  commands;
    pattern2)  commands;
    patternn)  commands;
  esac

9.I/O重定向

  • file :stdout转向文件,如果文件不存在,将会创建文件

  • file:stdout追加文件

  • <file :将文件用作stdin;文件必须存在并具有r权限
  • <<word :从“here”文件中获取输入,直到包含“word”的行

10.sh函数
sh函数定义

func()
 {  
   # function code
 }

11.sh通配符

  • file *:列出当前目录中所有文件的信息
  • ls *.c:列出当前目录中所有以.c结尾的文件
  • ?通配符:查询某文件名中的字符
  • []通配符:查询文件名中一对[]中的字符
  • file ???:有三个字符的所有文件名
  • ls *.??:点号后有2个字符的所有文件名
  • file [ab]:包含字符a或b的所有文件名
  • ls [xyz]:列出所有包含x、y或z的文件名
  • ls [a-m]:列出包含a到m范围内字符的所有文件名

12.eval语句
eval是sh的一个内置命令,将输入参数字符串连接到一个字符串中,然后给出结果字符串

13.调试sh脚本
bash -x mysh

收获
本章主要介绍sh脚本和不同版本的sh;比较了sh脚本与C程序,并指出了解释语言和编译语言的区别;详细说明了如何编写sh脚本,包括sh变量、sh语句、sh内置命令、常规系统命令和命令替换;解释了sh控制语句,其中包括测试条件、for循环、while循环、do-until 循环、case语句等;说明了如何编写sh函数以及使用参数调用sh函数。sh脚本和C语言存在相似之处,但本质不同。 首先,sh是一个解释程序,逐行读取sh脚本文件并直接执行这些行。如果行是可执行命令且为内置命令,那么sh可直接执行。否则,它会复刻一个子进程来执行命令,并等待子进程终止后再继续,这与它执行单个命令行完全一样。 相反,C程序必须先编译链接到一个二进制可执行文件,然后通过主sh的子进程运行二进制可执行文件。总之,可能目前学习较为基础,因为有编程基础,sh编程给我的感觉是不是很难的。
此外,shell就是一个包含若干行Shell或者Linux命令的文件。对于一次编写,多次使用的大量命令,就可以使用单独的文件保存下来,以便日后使用。通常shell脚本以.sh为后缀。在编写shell时,第一行一定要指明系统需要哪种shell解释用户的shell程序,如:#!/bin/sh,#!/bin/bash,#!/bin/csh,,#!/bin/tcsh和,#!/bin/ksh等。下面的run.sh则指明使用bash执行。

问题
1.运行课本第一节sh脚本时候出现问题:找不到目录或者文件。

查询原因后是因为没有找到相关目录,文件没有在桌面文件目录下,我是新建了一个叫sh的文件。所以用
cd sh
先转到相应目录后在用编译代码后就可以。编译成功后用./mysh.sh代码即可

2.执行shell脚本时,用bash和source有什么区别?
在用bash调用脚本的时候,父进程接收到命令,发现不是内建命令,于是会创建一个和自己一模一样的shell进程来执行这个外部命令。这个子进程中设置了自己的运行的变量。而在此时,父进程的变量并没有改变。子进程执行完毕,消亡。这是一直等待的父进程来继续接收命令。
而在用source来执行脚本的时候,不会创建子进程,而是在父进程中直接执行。所以当需要程序修改当前shell本身的变量的时候,使用source命令。
例子:

实践

课本函数和关键字的运用
(1)转义echo字符运用

  #! /bin/bash
  
  echo hello world!\nI am 20201319
  echo echo -e:
  echo -e hello world!\nI am 20201319
  echo 添加双引号:
  echo "hello world!\nI am 20201319"
  echo echo -e 添加双引号:
  echo -e "hello world!\nI am 20201319"

(2)readonly关键字运用

#! /bin/bash
readonly a=1234qwer
echo $a
a=1234
echo $a

(3)unset关键字运用

  #! /bin/bash

  a=20201319
  echo $a
  unset a
  echo unset之后的输出:
  echo $a

(4)case函数的运用

   #! /bin/bash
   echo "请输入1到4之间的数字"
   read a
   case $a in
           1) echo "你选择了1"
           ;;
           2)echo "你选择了2"
           ;;
           3)echo "你选择了3"
           ;;
           4)echo "你选择了4"
          ;;
          *)echo "你没有输入1到4之间的数字"
  esac

(5)数组遍历

#!/bin/bash


days=(2 0 2 0 1 3 1 9)
#for循环遍历
for day in ${days[*]}  #或${days[@]}
do
        echo $day
done
echo "***************"
#fou循环带下标遍历
for i in ${!days[@]}
do
        echo ${days[$i]}
done

(6)函数调用

#! /bin/bash

   myadd(){
           echo "该函数计算两个数字的和"
           echo "请输入第一个数字"
           read a
           echo "请输入第二个数字"
           read b
           return $(($a+$b))
  }
  myadd
  echo "两个数字的和是$?"

(7)文件信息查询

#!/bin/bash
   
   file="diaoyong.sh"
   if [ -r $file ]
   then
      echo "文件可读"
   else
      echo "文件不可读"
   fi
   if [ -w $file ]
   then
      echo "文件可写"
   else
      echo "文件不可写"
   fi
   if [ -x $file ]
   then
      echo "文件可执行"
   else
      echo "文件不可执行"
   fi
   if [ -f $file ]
   then
      echo "文件为普通文件"
   else
      echo "文件为特殊文件"
   fi
   if [ -d $file ]
   then
      echo "文件是个目录"
   else
      echo "文件不是个目录"
   fi
   if [ -s $file ]
   then
      echo "文件不为空"
   else
      echo "文件为空"
   fi
   if [ -e $file ]
   then
      echo "文件存在"
   else
      echo "文件不存在"
   fi

2.拓展实践:简单数字排序

#!/bin/bash
 
# 依次提示用户输入 3 个整数,脚本根据数字大小依次排序输出 3 个数字
read -p "请输入一个整数:" num1
read -p "请输入一个整数:" num2
read -p "请输入一个整数:" num3
# 不管谁大谁小,最后都打印 echo "$num1,$num2,$num3"
# num1 中永远存最小的值,num2 中永远存中间值,num3 永远存最大值
# 如果输入的不是这样的顺序,则改变数的存储顺序,如:可以将 num1 和 num2 的值对调
tmp=0
# 如果 num1 大于 num2,就把 num1 和和 num2 的值对调,确保 num1 变量中存的是最小值
if [ $num1 -gt $num2 ];then   
	tmp=$num1
	num1=$num2
	num2=$tmp
fi
# 如果 num1 大于 num3,就把 num1 和 num3 对调,确保 num1 变量中存的是最小值
if [ $num1 -gt $num3 ];then   
  	tmp=$num1
  	num1=$num3
  	num3=$tmp
fi
# 如果 num2 大于 num3,就把 num2 和 num3 对标,确保 num2 变量中存的是小一点的值
if [ $num2 -gt $num3 ];then
  	tmp=$num2
  	num2=$num3
  	num3=$tmp
fi
echo "排序后数据(从小到大)为:$num1,$num2,$num3"

posted @ 2022-09-18 12:24  20201319吴向林  阅读(40)  评论(0编辑  收藏  举报