Shell

1.概述

  • shell是一个命令行解释器,接收应用程序/用户的命令,然后调用操作系统内核
  • 还是一个功能强大的编程语言,易编写,易调试,灵活性强

2.Shell解释器

  • linux提供的解释器有

    cat /etc/shells
    /bin/sh
    /bin/bash
    /sbin/nologin
    /bin/dash
    /bin/tcsh
    /bin/csh
    
  • bash和sh的关系

    • ll | grep bash

3.Shell中的变量

  • 系统变量

    • $HOME、$PWD、$SHELL、$USER等
      
  • 案例实操

    • 查看系统变量的值

      echo $HOME
      /home/atguigu
      
    • 显示当前Shell中所有的变量:set

      set
      BASH=/bin/bash
      BASH_ALIASES=()
      BASH_ARGC=()
      BASH_ARGV=()
      
      
  • 自定义变量

  • 基本语法

    • 定义变量:变量=值
    • 撤销变量:unset 变量
    • 声明静态变量:readonly变量,注意:不能unset 4
  • 变量定义规则

    • 变量名称可以由字母、数字和下划线组成,但是不能以数字开头,环境变量名建议大写。
    • 等号两侧不能有空格
    • 在bash中,变量默认类型都是字符串类型,无法直接进行数值运算。
    • 变量的值如果有空格,需要使用双引号或单引号括起来。
  • 可以把变量提升为全局环境变量,可供其他Shell程序使用

    • export 变量名
  • 特殊变量:$n

    • 基本语法

      • $n   (功能描述:n为数字,$0代表该脚本名称,$1- 9 代 表 第 一 到 第 九 个 参 数 , 十 以 上 的 参 数 , 十 以 上 的 参 数 需 要 用 大 括 号 包 含 , 如 9代表第一到第九个参数,十以上的参数,十以上的参数需要用大括号包含,如 9{10})

        touch parameter.sh
        vim parameter.sh
        
        #!/bin/bash
        echo  "$0 $1 $2"
        
        chmod 777 parameter.sh
        ./parameter.sh cls xz
        ./parameter.sh cls xz
        
        
  • 特殊变量:$#

  • 基本用法

    • $#   (功能描述:获取所有输入参数个数,常用于循环)。

      vim parameter.sh
      
      #!/bin/bash
      echo "$0  $1   $2"
      echo $#
      
      chmod 777 parameter.sh
      ./parameter.sh cls  xz
      parameter.sh cls xz 
      2
      
      
  • 特殊变量: ∗ , *, ,@

  • 基本语法

    • $*   (功能描述:这个变量代表命令行中所有的参数,$*把所有的参数看成一个整体)

    • $@  (功能描述:这个变量也代表命令行中所有的参数,不过$@把每个参数区分对待)

      vim parameter.sh
      
      #!/bin/bash
      echo "$0  $1   $2"
      echo $#
      echo $*
      echo $@
      
      bash parameter.sh 1 2 3
      
      parameter.sh  1   2
      3
      1 2 3
      1 2 
      
      
  • 特殊变量:$?

  • 基本语法

    • $?  (功能描述:最后一次执行的命令的返回状态。如果这个变量的值为0,证明上一个命令正确执行;如果这个变量的值为非0(具体是哪个数,由命令自己来决定),则证明上一个命令执行不正确了。)

    • 判断helloworld.sh脚本是否正确执行

      ./helloworld.sh 
      echo $?
      

4.运算符

  • 基本语法

    • ( ( 运 算 式 ) ) ” 或 “ ((运算式))”或“ (())[运算式]”
    • expr  + , - , *,  /,  %    加,减,乘,除,取余
      • 注意:expr运算符间要有空格
  • 案例实操

    # 计算3+2
    expr 2+3
    
    # 计算(2+3)*4
    expr `expr 2 + 3` \* 4
    S=$[(2+3)*4]
    echo $S
    

5.条件判断

  • 1.基本语法

    • [ condition ](注意condition前后要有空格
    • 注意:条件非空即为true,[ hello ]返回true,[] 返回false。
  • 常用条件判断

    • 两个整数之间比较
      • =字符串比较
      • -lt 小于(less than)
      • -le 小于等于(less equal)
      • -eq 等于(equal)
      • -gt 大于(greater than)
      • -ge 大于等于(greater equal)
      • -ne 不等于(not equal)
    • 按照文件权限进行判断
      • -r 有读的权限(read)
      • -w 有写的权限(write)
      • -x 有执行的权限(execute)
    • 按照文件类型进行判断
      • -f 文件存在并且是一个常规的文件(file)
      • -e 文件存在(existence)
      • -d 文件存在并且是一个目录(directory)
  • 案例

    # 23是否大于22
    [ 23 -ge 22 ]
    echo $?
    0
    
    # helloword.sh是否具有写权限
    [ -w helloworld.sh ]
    echo $?
    0
    
    # /home/data/cls.txt目录中的文件是否存在
    [ -e /home/data/cls.txt ]
    echo $?
    1
    
    # 多条件判断(&&表示前一条命令执行成功时,才执行后一条命令,||表示上一条命令执行失败后,才执行下一条命令)
    [ condition ] && echo OK || echo notok
    OK
    [ condition ] && [ ] || echo notok
    notok
    

6.流程控制

  • if判断

    • 基本语法

      if [ 条件判断式 ];then 
        程序 
      fi 
      或者 
      if [ 条件判断式 ] 
        then 
          程序 
      fi
      
    • 注意事项

      • [ 条件判断式 ],中括号和条件判断式之间必须有空格
      • if后面要有空格
    • 案例

      # 输入一个数字,如果是1,则输出aaa,如果是2,则输出bbb,如果是其他,什么也不输出
      touch if.sh
      vim if.sh
      
      #!/bin/bash
      
      if [ $1 -eq "1" ]
      then
      	echo "aaa"
      elif [ $1 -eq "2" ]
      then 
      	echo "bbb"
      fi
      
      chmod 777 if.sh
      ./if.sh 1
      aaa
      
  • case 语句

    • 基本语法

      case $变量名 in 
        "值1") 
          如果变量的值等于值1,则执行程序1 
          ;; 
        "值2") 
          如果变量的值等于值2,则执行程序2 
          ;; 
        …省略其他分支… 
        *) 
          如果变量的值都不是以上的值,则执行此程序 
          ;; 
      esac
      
    • 注意事项

      • case行尾必须为单词“in”,每一个模式匹配必须以右括号“)”结束。
      • 双分号“;;”表示命令序列结束,相当于java中的break。
      • 最后的“*)”表示默认模式,相当于java中的default。
    • 案例

      # 输入一个数字,如果是1,则输出aaa,如果是2,输出bbb.如果是其他,输出ccc
      
      #!/bin/bash
      
      case $1 in
      "1")
      	echo "aaa"
      ;;
      "2")
      	echo "bbb"
      ;;
      *)
      	echo "ccc"
      ;;
      esac
      
      chmod 777 case.sh
      ./case.sh 1
      aaa
      
  • for循环

    • 基本语法1

      for (( 初始值;循环控制条件;变量变化 )) 
        do 
          程序 
        done
      
    • 案例

      # 从1加到100
      touch for1.sh
      vim for1.sh
      
      #!/bin/bash
      
      s=0
      for((i=0;i<=100;i++))
      do
      	s=$[$s+$i]
      done
      echo $s
      chmod 777 for1.sh
      ./for1.sh
      "5050"
      
    • 基本语法2

      for 变量 in 值1 值2 值3...
        do
          程序
        done
      
    • 案例

      # 打印所有输入的参数
      
      touch for2.sh
      vim for2.sh
      
      #!/bin/bash
      
      for i in $@
              do
                      echo "i love $i"
              done
      
      for j in $*
              do
                      echo "j love $i"
              done
      	
      chmod 777 for2.sh
      bash for2.sh aaa bbb ccc
      i love aaa
      i love bbb
      i love ccc
      
    • 比较$*和$@的区别

      (a)$*和$@都表示传递给函数或脚本的所有参数,不被双引号“”包含时,都以$1 $2 …$n的形式输出所有参数。
      (b)当它们被双引号“”包含时,“$*”会将所有的参数作为一个整体,以“$1 $2 …$n”的形式输出所有参数;“$@”会将各个参数分开,以“$1” “$2”…”$n”的形式输出所有参数。
      
      vim for.sh
      
      #!/bin/bash 
      
      for i in "$*" 
      #$*中的所有参数看成是一个整体,所以这个for循环只会循环一次 
              do 
                      echo "ban zhang love $i"
              done 
      
      for j in "$@" 
      #$@中的每个参数都看成是独立的,所以“$@”中有几个参数,就会循环几次 
              do 
                      echo "ban zhang love $j" 
      done
      
      chmod 777 for.sh
      bash for.sh aaa bbb ccc
      
      ban zhang love aaa bbb ccc
      ban zhang love aaa
      ban zhang love bbb
      ban zhang love ccc
      
  • while循环

    • 基本语法

      while [ 条件判断式 ]
      	do
      	  程序
      	done
      
    • 案例

      # 从1加到100
      touch while.sh
      vim while.sh
      
      #!/bin/bash
      
      s=0
      i=1
      while [ $i -le 100 ]
      do
              s=$[$s+$i]
              i=$[$i+1]
      done
      echo $s
      
      
      chmod 777 while.sh 
      ./while.sh 
      5050
      

7.read读取控制台输入

  • 基本语法

    • read(选项)(参数)
      • 选项
        • -p:指定读取值时的提示符
        • -t:指定读取值时等待的时间(秒)
      • 参数
        • 变量:指定读取值的变量名
  • 案例

    # 提示7秒内,读取控制台输入的名称
    touch read.sh
    vim read.sh
    
    #!/bin/bash
    
    read -t 7 -p "Enter your name in 7 seconds" NAME
    echo $NAME
    
    ./read.sh
    Enter your name in 7 seconds coco
    coco
    

8.函数

  • 系统函数

    • basename基本语法

      basename[string/pathname][suffix] 
      功能描述:
      	basename命令会删掉所有的前缀包括最后一个/字符,然后将字符串显示出来
      选项:
      	suffix为后缀,如果suffix被指定了,basename会将pathname或string中的suffix去掉
      
    • 案例

      # 截取/home/testdata/banzhang.txt路径下的文件名称
      basename /home/testdata/banzhang.txt
      banzhang.txt
      basename /home/testdata/banzhang.txt .txt
      banzhang
      
    • dirname基本语法

      dirname 文件绝对路径
      功能描述:
      	从给定的包含绝对路径的文件名中去除文件名(非目录部分),然后返回剩下的路径(目录部分)
      
    • 案例

      # 获取banzhang.txt文件的路径
      dirname /home/testdata/banzhang.txt
      /home/testdata
      
  • 自定义函数

    • 基本语法

      [ function ]funname[()]
      {
      	action;
      	[return int;]
      }
      funname
      
    • 经验技巧

      • 必须在调用函数的地方之前,先声明函数,shll脚本是逐行运行.不会像其他语言一样先编译
      • 函数返回值,只能通过$?系统变量获得,可以显示加:return返回,如果不加,将以最后一条命令的运行结果,作为返回值.return后跟数值n(0-255)
    • 案例

      # 计算两个输入参数的和
      touch fun.sh
      vim fun.sh
      
      #!/bin/bash
      function sum()
      {
      	s=0
      	s=$[$1+$2]
      	echo "$s"
      }
      
      read -p "please input the number1:" n1;
      read -p "please input the number2:" n2;
      sum $n1 $n2;
      
      chmod 777 fun.sh
      ./fun.sh
      Please input the number1: 2
      Please input the number2: 5
      7
      

9.Shell工具

  • cut

    • cut的工作就是剪,具体来说就是在文件中负责剪切数据用的.cut命令从文件的每一行剪切字节,字符和字段并将这些字节,字符和字段输出

    • 基本用法

      • cut[选项参数] filename
      • 说明:默认分割符是制表符
    • 选项参数说明

      • -f 列号,提取第几行
      • -d 分隔符,按照指定分隔符分隔列
    • 案例

      touch cut.txt
      vim cut.txt
      
      dong shen
      guan zhen
      wo  wo
      lai  lai
      le  le
      
      # 切割cut.txt第一列
      cut -d " " -f 1 cut.txt
      dong
      guan
      wo
      lai
      le
      
      # 切割cut.txt第二,三列
      cut -d " " -f 2,3 cut.txt
      shen
      zhen
       wo
       lai
       le
      
      # 在cut.txt文件中切割出guan
      cat cut.txt|grep "guan"|cut -d " " -f 1
      guan
      
      # 选取系统PATH变量值,第二个:开始后的所有路径
      echo $PATH
      echo $PATH | cut -d: -f 2-
      
      # 切割ifconfig后打印的IP地址
      ifconfig|grep "inet addr"|cut -d: -f 2|cut -d " " -f1
      192.168.0.101
      127.0.0.1
      ifconfig eth0|grep "inet addr"|cut -d: -f 2|cut -d " " -f 1
      192.168.0.101
      
  • sed

    • sed是一种流编辑器,它一次处理一行内容,处理时,把当前处理的行存储在临时缓存区中,称为"模式空间",接着用sed命令处理缓冲区的内容,处理完成之后,把缓冲区的内容送往屏幕.接着处理下一行,这样不断重复,直到文件末尾.文件内容并没有改变,除非使用重定向存储输出

    • 基本用法

      • sed[选项参数] ‘command’ filename
    • 选项参数说明

      • -e 直接在指令列模式上进行sed的动作编辑
    • 命令功能描述

      • a 新增,a的前面可以接字符串,在下一行出现
      • d 删除
      • s 查找并替换
    • 案例

      touch sed.txt
      vim sed.txt
      
      dong shen
      guan zhen
      wo  wo
      lai  lai
      
      le  le
      
      # 将"mei nv"这个单词插入到sed.txt第二行下,打印
      sed '2a mei nv' sed.txt 
      dong shen
      guan zhen
      mei nv
      wo  wo
      lai  lai
      
      le  le
      cat sed.txt
      dong shen
      guan zhen
      wo  wo
      lai  lai
      
      le  le
      
      !!!注意:文件内容并没有改变
      
      # 删除sed.txt文件中所有包含wo的行
      sed '/wo/d' sed.txt
      
      dong shen
      guan zhen
      lai  lai
      
      le  le
      
      # 将sed.txt文件中wo替换为ni
      sed 's/wo/ni/g' sed.txt
      dong shen
      guan zhen
      ni  ni
      lai  lai
      
      le  le
      
      !!!注意:g表示global,全部替换
      
      # 将sed.txt文件中的第二行删除并将wo替换为ni
      sed -e '2d' -e 's/wo/ni/g' sed.txt 
      dong shen
      ni  ni
      lai  lai
      
      le  le
      
      
      
  • awk

    • 一个强大的文件分析工具,把文件逐行读入,以空格为默认符将每行切片,切开的部分在进行分析处理

    • 基本用法

      • awk[选项参数] ‘pattern1{action1} pattern2{action2}…’ filename
      • pattern:表示AWK在数据中查找的内容,就是匹配模式
      • action:在找到匹配内容时所执行的一系列命令
    • 选项参数说明

      • -F 指定输入文件分隔符
      • -v 赋值一个用户定义变量
    • 案例

      # 数据准备
      sudo cp /etc/passwd ./
      # 搜索passwd文件以root关键字开头的所有行,并输出该行的第七列
      awk -F: '/^root/{print $7}' passwd 
      /bin/bash
      
      # 搜索passwd文件以root关键字开头的所有行,并输出该行的第一列和第七列,中间以,分割
      awk -F: '/^root/{print $1","$7}' passwd
      root,/bin/bash
      
      !!!注意:只有匹配了pattern的行才会执行action
      
      # 只显示/etc/passwd的第一列和第七列,以逗号分割,且在所有行前面加列名user,shell在最后一行添加"aaa, /bin/bbb"
      awk -F: 'BEGIN{print "user,shell"} {print $1","$7} END{print "aaa,/bin/bbb"}' passwd
      user,shell
      root,/bin/bash
      bin,/sbin/nologin
      daemon,/sbin/nologin
      adm,/sbin/nologin
      lp,/sbin/nologin
      sync,/bin/sync
      shutdown,/sbin/shutdown
      halt,/sbin/halt
      mail,/sbin/nologin
      uucp,/sbin/nologin
      operator,/sbin/nologin
      games,/sbin/nologin
      gopher,/sbin/nologin
      ftp,/sbin/nologin
      nobody,/sbin/nologin
      dbus,/sbin/nologin
      rpc,/sbin/nologin
      vcsa,/sbin/nologin
      abrt,/sbin/nologin
      rpcuser,/sbin/nologin
      nfsnobody,/sbin/nologin
      haldaemon,/sbin/nologin
      ntp,/sbin/nologin
      saslauth,/sbin/nologin
      postfix,/sbin/nologin
      sshd,/sbin/nologin
      oprofile,/sbin/nologin
      tcpdump,/sbin/nologin
      apache,/sbin/nologin
      aaa,/bin/bbb
      
      !!!注意:BEGIN在所有数据读取行之前执行,END在所有数据执行之后执行
      
      # 将passwd文件中的用户id增加数值1并输出
      awk -v i=1 -F: '{print $3+i}' passwd
      1
      2
      3
      4
      5
      6
      7
      8
      9
      11
      12
      13
      14
      15
      100
      82
      33
      70
      174
      30
      65535
      69
      39
      500
      90
      75
      17
      73
      49
      
    • awk内置变量

      • FILENAME: 文件名
      • NR: 已读的记录数
      • NF: 浏览记录的域的个数(切割后,列的个数)
    • 案例

      # 统计passwd文件名,每行的行号,每行的列数
      awk -F: '{print "filename:"  FILENAME ", linenumber:" NR  ",columns:" NF}' passwd 
      filename:passwd, linenumber:1, columns:7
      filename:passwd, linenumber:2, columns:7
      filename:passwd, linenumber:3, columns:7
      filename:passwd, linenumber:4, columns:7
      filename:passwd, linenumber:5, columns:7
      filename:passwd, linenumber:6, columns:7
      filename:passwd, linenumber:7, columns:7
      filename:passwd, linenumber:8, columns:7
      filename:passwd, linenumber:9, columns:7
      
      
      # 切割IP
      ifconfig eth0|grep "inet addr" |awk -F: '{print $2}'|awk -F " " 'print $1'
      192.168.0.101
      
      # 查询sed.txt中空行所在的行号
      awk '/^$/{print NR}' sed.txt
      5
      
  • sort

    • sort命令可以将文件进行排序,并将排序结果标准输出

    • 基本用法

      • sort(选项)(参数)

        选项说明
        -n依照数值的大小排序
        -r以相反的顺序来排序
        -t设置排序时所用的分隔字符
        -k指定需要排序的列
    • 案例

      # 数据准备
      touch sort.sh
      vim sort.sh 
      
      bb:40:5.4
      bd:20:4.2
      xz:50:2.3
      cls:10:3.5
      ss:30:1.6
      
      # 按照:分割后的第三列倒序排序
      sort -t : -nrk 3  sort.sh 
      
      bb:40:5.4
      bd:20:4.2
      cls:10:3.5
      xz:50:2.3
      ss:30:1.6
      

10.小试牛刀

  • 使用linux命令查询file1中空行所在的行号

    awk '/^$/{print NR}' sed.txt
    
  • 计算下面文件的第二列的和并输出

    vi chengji.txt
    张三 40
    李四 50
    王五 60
    
    # 计算第二列的和并输出
    awk -F " " '{sum+=$2} END{print sum}' chengji.txt
    150
    
  • shell脚本中如何检查一个文件是否存在,如果不存在该如何处理

    #!/bin/bash
    
    if [ -f file.txt ]; then
    	echo "文件存在!"
    else
    	echo "文件不存在!"
    fi
    
  • 用shell写一个脚本,对文本中无序的一列数字排序

    vi test.txt
    9
    8
    7
    6
    5
    4
    3
    2
    10
    1
    
    sort -n test|awk '{a+=$0;print $0} END{print "SUM="a}'
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    SUM=55
    
  • 用shell脚本写出查找当前文件夹(/home)下所有的文本文件内容中包含有字符shen的文件名称

    grep -r "shen" |cut -d ":" -f 1
    
    sed.txt
    cut.txt
    
  • 用shell写一个脚本统计用逗号隔开的单词的个数

    # 数据准备
    vi word.txt
    a,b,c,d,e,f,g,h,i,j,k,l,a,a,a,a,b,b,b,c,c,d
    
    cat word.txt|awk -F "," '{for (i=1;i<=NF;i++){a[$i]++}}END{for (i in a){print i,a[i]}}'|sort -nr -t " " -k 2
    
  • 现在有个word.txt文件,里面是各种单词,单词之间以一个空格分隔,不含标点符号,需要统计每个单词出现的次数,并按照次数倒序排列展示

    # 数据准备
    vi word.txt
    today is a good day
    but i dont feel very well
    well i think i was sick
    this sick day
    
    # 首先需要将多行单词合并为一行
    cat word.txt|sed ':a;N;$!ba;s/\n/ /g'  # :a;N;$!ba; 到了最后一行不执行跳转,即把所有的行全读入pattern space中
    
    or
    
    cat word.txt |tr "\n" " "
    
    # 接着利用awk统计词频
    指定空格为分隔符后,用for循环读取全部单词,NF为最后一个单词所在位置,因此需要循环NF次。接着将读取到的单词作为key写入到数组a中,value就是该单词出现的次数。读取完所有单词后,再利用一个for循环去读取数组a中的所有key和value,即单词及其出现次数。最后使用sort并指定第二列的出现次数字段倒序排列。
    
    cat word.txt | sed ':a;N;$!ba;s/\n/ /g'|awk 'BEGIN{FS=" "}{for(i=1;i<=NF;i++){a[$i]++}}END{for(i in a){print i,a[i]}}' |sort -n -t " " -k 2 -r
    
    i 3
    well 2
    sick 2
    day 2
    was 1
    very 1
    today 1
    this 1
    think 1
    is 1
    good 1
    feel 1
    dont 1
    but 1
    a 1
    
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Shell脚本高级编程教程,希望对你有所帮助。 Example 10-23. Using continue N in an actual task: 1 # Albert Reiner gives an example of how to use "continue N": 2 # --------------------------------------------------------- 3 4 # Suppose I have a large number of jobs that need to be run, with 5 #+ any data that is to be treated in files of a given name pattern in a 6 #+ directory. There are several machines that access this directory, and 7 #+ I want to distribute the work over these different boxen. Then I 8 #+ usually nohup something like the following on every box: 9 10 while true 11 do 12 for n in .iso.* 13 do 14 [ "$n" = ".iso.opts" ] && continue 15 beta=${n#.iso.} 16 [ -r .Iso.$beta ] && continue 17 [ -r .lock.$beta ] && sleep 10 && continue 18 lockfile -r0 .lock.$beta || continue 19 echo -n "$beta: " `date` 20 run-isotherm $beta 21 date 22 ls -alF .Iso.$beta 23 [ -r .Iso.$beta ] && rm -f .lock.$beta 24 continue 2 25 done 26 break 27 done 28 29 # The details, in particular the sleep N, are particular to my 30 #+ application, but the general pattern is: 31 32 while true 33 do 34 for job in {pattern} 35 do 36 {job already done or running} && continue 37 {mark job as running, do job, mark job as done} 38 continue 2 39 done 40 break # Or something like `sleep 600' to avoid termination. 41 done 42 43 # This way the script will stop only when there are no more jobs to do 44 #+ (including jobs that were added during runtime). Through the use 45 #+ of appropriate lockfiles it can be run on several machines 46 #+ concurrently without duplication of calculations [which run a couple 47 #+ of hours in my case, so I really want to avoid this]. Also, as search 48 #+ always starts again from the beginning, one can encode priorities in 49 #+ the file names. Of course, one could also do this without `continue 2', 50 #+ but then one would have to actually check whether or not some job 51 #+ was done (so that we should immediately look for the next job) or not 52 #+ (in which case we terminate or sleep for a long time before checking 53 #+ for a new job).
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值