美文网首页
shell 语言相关

shell 语言相关

作者: 土卡拉 | 来源:发表于2019-04-12 08:43 被阅读0次

    shell学习记录

    shell是什么

    简单来说,shell是一个命令解释器,将用户输入的命令解释给操作系统内核。它既是命令语言又是程序设计语言。Shell 同时也是一个程序,它的一端连接着 UNIX/Linux 内核,另一端连接着用户和其它应用程序;换句话说,Shell 是用户和应用程序与内核沟通的桥梁。
    类型:sh、bash、ash、csh(tcsh)、ksh、zch

    shell的功能

    • Shell 除了能解释用户输入的命令,将它传递给内核,还可以:
      调用其他程序,给其他程序传递数据或参数,并获取程序的处理结果;
      在多个程序之间传递数据,把一个程序的输出作为另一个程序的输入;
      Shell 本身也可以被其他程序调用。
    • 可以用shell做的事情: Linux 的日常管理工作,如文本或字符串检索、文件的查找或创建、大规模软件的自动部署、更改系统设置、监控服务器性能、发送报警邮件、抓取网页内容、压缩文件等。

    linux运维工程师的工作细节

    • 安装操作系统,例如 CentOS、Ubuntu 等。
    • 部署代码运行环境,例如网站后台语言采用 PHP,就需要安装 Nginx、Apache、MySQL、PHP 运行时等。
    • 及时修复漏洞,防止服务器被攻击,这包括 Linux 本身漏洞以及各个软件的漏洞。
    • 根据项目需求升级软件,例如 PHP 7.0 在性能方面获得了重大突破,如果现在服务器压力比较大,就可以考虑将旧版的 PHP 5.x 升级到 PHP 7.0。
    • 监控服务器压力,别让服务器宕机。例如淘宝双十一的时候就会瞬间涌入大量用户,导致部分服务器宕机,网页没法访问,甚至连支付宝都不能使用。
    • 分析日志,及时发现代码或者环境的问题,通知相关人员修复。

    什么是脚本

    简而言之,脚本就是可执行的代码 shell脚本扩展名一般就是.sh(从上到下,逐句执行)

    shell相关操作(交互)

    • 查看当前使用的shell:echo $SHELL
    • 查看系统可用的shell:cat /etc/shells
    • 编写一个简单脚本:
      touch 脚本名.sh
      vi 脚本名.sh

      !/bin/bash ————第一行必须以特殊注释

      脚本内容
      :wq或者x ————保存退出
      chmod a+x 脚本名.sh ————添加可执行权限
      ./脚本名.sh ————执行脚本

    不想修改权限的操作:/bin/bash 脚本名.sh

    • 进入shell的方法:
      1、进入linux控制台 :ctrl+alt+F123456 +7切换回图形化界面
      输入账户和密码进入控制台模式,然后出现$ (shell命令提示符)
      2、终端

    对于普通用户,Base shell 默认的提示符是美元符号$;对于超级用户(root 用户),Bash Shell 默认的提示符是井号#。该符号表示 Shell 等待输入命令。

    shell相关语法

    • 输出命令 echo
      (未理解)Shell 通过PS1和PS2两个环境变量来控制提示符格式:
      PS1 控制最外层命令行的提示符格式。
      PS2 控制第二层命令行的提示符格式。

    • Shell 使用以\为前导的特殊字符来表示命令提示符中包含的要素,这使得 PS1 和 PS2 的格式看起来可能有点奇怪。下表展示了可以在 PS1 和 PS2 中使用的特殊字符。

    • read输入文件读取键盘输入

      !/bin/bash

      echo "what is your name?"
      read PERSON
      echo "Hello,$PERSON"

    • 获取当前进程pid echo $$(进程的pid一样就是在同一个进程)

    • source命令 强制执行脚本文件中的全部命令,而忽略脚本文件的权限。
      语法:source 文件名 简写 . 文件名(点和文件名中间有个空格)
      注意:应该是要切换到脚本所在的目录

    • 注释 #

    变量与变量作用域

    变量

    • 定义变量的三种方式
      变量名=变量值,变量名='变量值',变量名="变量值"

    赋值号 = 的周围不能有空格, 值没有空白符变量可以不用引号,值有空白符一定要用引号,单引号不能解释特殊变量(原样输出使用),所以建议使用双引号

    • 变量的命名规则
      变量名由数字、字母、下划线组成;
      必须以字母或者下划线开头;
      不能使用 Shell 里的关键字(通过 help 命令可以查看保留关键字)。
    • 使用变量变量名的前面加上$符号即可,为了帮助解释器识别变量边界可以加个{},推荐给所有变量加上花括号{ },这是个良好的编程习惯。
    • 修改变量 ———> 对变量重新赋值即可
    • 命令赋值给变量 变量名=命令名(这是反引号) 或者 变量名=(命令名) echo变量名 => 输出的命令执行的内容
    • 只读变量 定义变量后,下一行添加readonly 变量名(值不可变)
    • 删除变量 同只读变量一样 添加unset 变量名(可以选择不去定义)

    特殊变量

    位置参数(与Python中的关键字参数)与特殊参数

    • 位置参数:通过$n的形式来接收的参数
    • 特殊参数:0(当前脚本文件名)#(传给的参数个数)
      *(传递的所有参数)@(传递的所有参数)
      $?(上个命令的退出状态,或者函数的返回值)
      $$(当前进程的pid)

    不用双引号时候没有区别(都是将接收到的每个参数看做一份数据,彼此之间以空格来分隔),当它们被双引号" "包含时,就会有区别了(需要通过for循环才能看出区别):
    "*"会将所有的参数从整体上看做一份数据,而不是把每个参数都看做一份数据。 "@"仍然将每个参数都看作一份数据,彼此之间是独立的。
    "?",所谓退出状态,就是上一个命令执行后的返回结果。退出状态是一个数字,一般情况下,大部分命令执行成功会返回 0,失败返回 1 "?",获取函数的返回值

    #!/bin/bash
    #得到两个数相加的和
    function add(){
        return `expr $1 + $2`
    }
    add 23 50  #调用函数
    echo $?  #获取函数返回值
    

    变量作用域

    有的变量可以在当前 Shell 会话中使用,这叫做全局变量(global variable),函数中变量名前面未加local的也是全局变量,全局变量只在当前 Shell 会话中有效,如果使用export命令(export 变量名)将它导出,那么它就在所有的子 Shell 中也有效了,这称为“环境变量”(环境变量只能向下传递而不能向上传递,即“传子不传父”。可以通过exit层层退出shell);
    有的变量只能在函数内部使用,这叫做局部变量(local variable);
    而有的变量还可以在其它 Shell 中使用,这叫做环境变量(environment variable)。

    如果想让环境变量在所有 Shell 中都有效,并且能够永久保存,在关闭 Shell 后也不丢失,那么就需要把环境变量写入启动文件。

    字符串

    • 字符串的定义,字符串的定义形式和变量的定义一样
    1. 由单引号' '包围的字符串:
      任何字符都会原样输出,在其中使用变量是无效的。
      字符串中不能出现单引号,即使对单引号进行转义也不行。
    2. 由双引号" "包围的字符串:
      如果其中包含了某个变量,那么该变量会被解析(得到该变量的值),而不是原样输出。
      字符串中可以出现双引号,只要它被转义了就行。
    3. 不被引号包围的字符串
      不被引号包围的字符串中出现变量时也会被解析,这一点和双引号" "包围的字符串一样。
      字符串中不能出现空格,否则空格后边的字符串会作为其他变量或者命令解析。
    • 获取字符串的长度 ${#字符串名}
    • 字符串拼接(只有不加引号或者加双引号) 两个字符串并排放在一起就能实现拼接,双引号中的变量名一定要用{}划分边界
    • 字符串的截取:
    1. 指定位置开始截取:
      • 字符创左边开始截取:{string: start :length}string 是要截取的字符串,start 是起始位置(从左边开始,从 0 开始计数),length 是要截取的长度(省略的话表示直到字符串的末尾) 字符串右边开始截取:{string: 0-start :length}

    从左边开始计数时,起始数字是 0(这符合程序员思维);从右边开始计数时,起始数字是 1(这符合常人思维)。计数方向不同,起始数字也不同。
    不管从哪边开始计数,截取方向都是从左到右。

    1. 制定字符开始截取
      • 使用 # 号截取右边字符 ${string#*chars} 忽略第一个chars左边所有字符(截取内容不包含这个chars) 用## 匹配最后一个才会结束
      • 使用 % 号截取左边字符 ${string%chars* } 请注意 * 的位置,因为要截取 chars 左边的字符,而忽略 chars 右边的字符,所以*应该位于 chars 的右侧。
    八种用法:
    ${string: start :length}    从 string 字符串的左边第 start 个字符开始,向右截取 length 个字符。
    ${string: start}    从 string 字符串的左边第 start 个字符开始截取,直到最后。
    ${string: 0-start :length}  从 string 字符串的右边第 start 个字符开始,向右截取 length 个字符。
    ${string: 0-start}  从 string 字符串的右边第 start 个字符开始截取,直到最后。
    ${string#*chars}    从 string 字符串第一次出现 *chars 的位置开始,截取 *chars 右边的所有字符。
    ${string##*chars}   从 string 字符串最后一次出现 *chars 的位置开始,截取 *chars 右边的所有字符。
    ${string%*chars}    从 string 字符串第一次出现 *chars 的位置开始,截取 *chars 左边的所有字符。
    ${string%%*chars}   从 string 字符串最后一次出现 *chars 的位置开始,截取 *chars 左边的所有字符。
    

    数组

    常用的 Bash Shell 只支持一维数组,不支持多维数组

    • 定义数组 用括号( )来表示数组,数组元素之间用空格来分隔
      数组名=(元素1 元素2 ...)
    • 获取数组元素用:使用下标[ ],下标可以是一个整数,也可以是一个结果为整数的表达式;当然,下标必须大于等于 0。${array_name[index]},使用@或*代替下标可以获取数组中的所有元素。
    • 添加元素:数组名[长度]=元素值,会在数组后面添加元素
    • 修改数组:数组名=([下标]=值 ...)
    • 获取数组长度:利用@或 * ,可以将数组扩展成列表,然后使用#来获取数组元素的个数,格式如下:{#array_name[@]}或者{#array_name[ * ]}
    • 数组拼接:先利用@或,将数组扩展成列表,然后再合并到一起
      array_new=({array1[@]}{array2[@]})
      array_new=({array1[*]}{array2[
      ]})
    • 删除数组元素 unset array_name[index]
    • 删除数组 unset array_name
    • 关联数组 关联数组必须使用带有-A选项的 declare 命令创建。
      访问关联数组元素 array_name["index"] 获取值$(array_name["index"])

    运算符与表达式

    • 数学运算
    shell默认所有变量都是字符串,执行数学计算需要用[]括起来
    a=100
    echo $[$a+10]
    echo $[$a / 2]
    echo $[$a * 2]
    echo $[$a - 80]
    echo $[10 % 2]
    
    echo $((3 + 5))
    echo $((10/2))
    echo $((10/3))  #3 整除
    echo $((10*3))
    echo $((10%3))
    
    let a=5+6
    echo $a
    let a+=10
    echo $a
    
    echo `expr 3 + 5`  #也可以用expr进行计算
    
    • 关系运算

      运算符 说明 举例
      -eq ==,相等返回 true。 [ $a -eq $b ] 返回 false。
      -ne !=,不相等返回 true。 [ $a -ne $b ] 返回 true。
      -gt >,如果是,则返回 true。 [ $a -gt $b ] 返回 false。
      -lt <,如果是,则返回 true。 [ $a -lt $b ] 返回 true。
      -ge >=,如果是,则返回 true。 [ $a -ge $b ] 返回 false。
      -le <=,如果是,则返回 true。 [ $a -le $b ] 返回 true。
    • 逻辑运算

      运算符 说明 举例
      && 逻辑的 AND [[ $a -lt 100 && $b -gt 100 ]] 返回 false
      || 逻辑的 OR [[ a -lt 100|b -gt 100 ]] 返回 true
    • 字符串判断

      运算符 说明 举例
      = 检测两个字符串是否相等,相等返回 true。 [$a = $b ] 返回 false。
      != 检测两个字符串是否相等,不相等返回 true。 [ a !=b ] 返回 true。
      -z 检测字符串长度是否为0,为0返回 true。 [ -z $a ] 返回 false。
      -n 检测字符串长度是否为0,不为0返回 true。 [ -n "$a" ] 返回 true。
      str 检测字符串是否为空,不为空返回 true。 [ $a ] 返回 true。
    • 文件判断

      操作符 说明 举例
      -d file 检测文件是否是目录,如果是,则返回 true。 [ -d $file ] 返回 false。
      -f file 检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 true。 [ -f $file ] 返回 true。
      -r file 检测文件是否可读,如果是,则返回 true。 [ -r $file ] 返回 true。
      -w file 检测文件是否可写,如果是,则返回 true。 [ -w $file ] 返回 true。
      -x file 检测文件是否可执行,如果是,则返回 true。 [ -x $file ] 返回 true。
      -s file 检测文件是否为空(文件大小是否大于0),不为空返回 true。 [ -s $file ] 返回 true。
      -e file 检测文件(包括目录)是否存在,如果是,则返回 true。 [ -e $file ] 返回 true。

    分支语句

    一、单分支if语句

    1. 语法格式
      复制代码
      if [ 条件判断式 ]; then
      程序
      fi

    或者

    if [ 条件判断式 ]
    then
    程序
    fi

    注意:中括号和条件判断式之间必须有空格
    复制代码

    1. 示例1:判断登陆的用户是否是root
      复制代码

    !/bin/bash

    if [ "$USER" == root ];then
    echo "Login User is root"
    fi

    #########或者#########

    !/bin/bash

    if [ "$USER" == root ]
    then
    echo "Login User is root"
    fi
    复制代码

    1. 示例2:判断分区使用率
      复制代码

    !/bin/bash

    test=(df -h | grep sda1 | awk '{print5}' | cut -d '%' -f 1)

    if [ $test -ge 90 ];then
    echo "Warning! /dev/sda1 is full!"
    fi
    复制代码

    二、双分支if语句

    1. 语法格式
      复制代码
      if [ 条件判断式 ]; then
      条件成立时,执行的程序
      else
      条件不成立时,执行的程序
      fi

    或者

    if [ 条件判断式 ]
    then
    条件成立时,执行的程序
    else
    条件不成立时,执行的程序
    fi
    复制代码

    1. 示例1:输入一个文件,判断是否存在
      复制代码

    !/bin/bash

    read -p "Please input a file:" file

    if [ -f file ]; then echo "File:file exists!"
    else
    echo "File: $file not exists!"
    fi
    复制代码

    1. 示例2:判断apache服务是否启动了,如果没有启动,就代码启动
      复制代码

    !/bin/bash

    test=$(ps aux | grep httpd | grep -v 'grep' | wc -l)

    if [ test -gt 0 ]; then echo "(date) httpd is running!"
    else
    echo "$(date) httpd isn't running, will be started!"
    /etc/init.d/httpd start
    fi
    复制代码

    三、多分支if语句

    1. 语法格式
      复制代码
      if [ 条件判断式1 ]; then
      当条件判断式1成立时,执行程序1
      elif [ 条件判断式2 ]; then
      当条件判断式2成立时,执行程序2
      .....省略更多条件.....
      else
      当所有条件都不成立时,最后执行此程序
      fi
      复制代码
    1. 示例:实现计算器
      复制代码

    !/bin/bash

    输入数字a,数字b和操作符

    read -p "Please input number a:" a
    read -p "Please input number b:" b
    read -p "Please input operator[+|-|*|/]:" opt

    判断输入内容的正确性

    testa=(echoa | sed 's/[0-9]//g')
    testb=(echoa | sed 's/[0-9]//g')
    testopt=(echoopt | sed 's/[+|-|*|/]//g')

    if [ -n "testa" -o -n "testb" -o -n "testopt" ]; then echo "input content is error!" exit 1 elif [ "opt" == "+" ]; then
    result=((a+b)) elif [ "opt" == "-" ]; then
    result=((a-b)) elif [ "opt" == "" ]; then
    result=((a
    b)) else result=((a/b))
    fi

    echo "a opt b =result"
    复制代码

    四、case语句
    case语句和if...elif...else语句都是多分支条件语句,不过和if多分支条件语句不同的是,case语句只能判断一种条件关系,而if语句可以判断多种条件关系。

    1. 语法格式
      复制代码
      case $变量名 in
      "值1")
      如果变量的值等于值1,则执行程序1
      ;;
      "值2")
      如果变量的值等于值2,则执行程序2
      ;;
      .....省略其他分支.....
      *)
      如果变量的值都不是以上的值,则执行此程序
      ;;
      esac
      复制代码
    1. 示例:判断用户输入
      复制代码

    !/bin/bash

    read -p "Please choose yes/no:" cmd

    case $cmd in
    "yes")
    echo "Your choose is yes!"
    ;;
    "no")
    echo "Your choose is no!"
    ;;
    *)
    echo "Your choose is error!"
    ;;
    esac
    复制代码

    循环语句

    一、for循环

    1. 语法格式1
      for 变量 in 值1 值2 值3 ...
      do
      程序
      done
      说明:程序将遍历所有的值,赋值给变量,然后在执行程序。也就是说,后面接多少个值,程序就循环多少次。

    2. 示例1:遍历5个数,进行输出
      复制代码

    !/bin/bash

    for i in 1 2 3 4 5
    do
    echo $i
    done

    输出结果

    1
    2
    3
    4
    5
    复制代码

    1. 示例2:遍历目录下的所有文件,进行输出文件名

    !/bin/bash

    for file in (ls) #注:ls会将当前目录下的所有文件列出来,然后逐个赋值给file,就可以逐个输出了 do echofile
    done

    1. 语法格式2
      for (( 初始值;循环控制条件;变量变化 ))
      do
      程序
      done

    说明:这种格式和C语言for循环的格式是一样的,区别只是需要用双括号括住循环条件。

    1. 示例1:计算1到100的总和
      复制代码

    !/bin/bash

    sum=0
    for ((i=1;i<=100;i=i+1))
    do
    sum=((sum+i)) #同样可以使用,sum=[sum+i]
    done

    echo $sum

    输出

    5050
    复制代码

    二、while循环

    1. 语法格式
      while [条件判断式]
      do
      程序
      done

    说明:当条件判断式成立时,才会执行程序,直到条件判断式不成立时,才退出循环。

    1. 示例:计算1到100的总和
      复制代码

    !/bin/bash

    i=1
    sum=0

    while [ i -le 100 ] do sum=(( sum+i ))
    i=$(( i+1 ))
    done

    echo $sum

    输出

    5050
    复制代码

    三、until循环

    1. 语法格式
      until [条件判断式]
      do
      程序
      done

    说明:until循环和while循环是相反的,当条件判断式不成立时,才会执行程序,直到条件判断式成立,才退出循环。

    1. 示例:计算1到100的总和
      复制代码

    !/bin/bash

    i=1
    sum=0

    until [ i -gt 100 ] do sum=(( sum+i ))
    i=$(( i+1 ))
    done

    echo $sum

    输出结果

    5050
    复制代码

    函数(实现模块化)

    • 函数的定义
      • name() {
        statements
        [return value]
        }
        -function name {
        statements
        [return value]
        }
    • 函数的调用
      直接函数名调用
      带参数:函数名 参数1 参数2 ... (参数之间空格隔开即可)
      输出返回值 可以转为全局变量输出,或者用echo函数和printf命令

    shell常用内置命令

    • 别名
      添加别名 alias 命名名=‘别名’
      删除别名 unalias 别名
    • 输出
      echo
    • 输入
      read [-options] [variables]
      options表示选项,如下表所示;variables表示用来存储数据的变量,可以有一个,也可以有多个。
      options和variables都是可选的,如果没有提供变量名,那么读取的数据将存放到环境变量 REPLY 中。
    • 退出进程
      exit
    • 设置变量属性
      declare [+/-] [aAfFgilprtux] [变量名=变量值]

    相关文章

      网友评论

          本文标题:shell 语言相关

          本文链接:https://www.haomeiwen.com/subject/amhqwqtx.html