• Linux-SHELL脚本学习


    0.<<内联输入重定向, 是从命令行, 而不是文件指定重定向的数据,”EOF“通常与”<<“结合使用,“<<EOF“表示后续的输入作为子命令或子shell的输入,直到遇到”EOF“,再次返回到主调shell,可将其理解为分界符(delimiter)。

    $ wc -l << EOF
    > a
    > b
    > c
    > d
    > e
    > EOF
    5

    1.一个shell中的系统环境变量只对该shell和其子shell有效

      子shell只能继承父shell的属性, 不能更改父shell的属性

      查看shell执行情况可以用sh -x a.sh

    2.位置变量和特殊变量

      $$: 这个程序的PID

      $?: 上次命令的执行结果返回值

      $0: 参数情况下表示文件名, 命令下表示当前shell

      $1: 第一个参数

      $*: 返回一个字符串, 所有参数和空格连接起来 "$1 $2 ..."

      $@: 返回多个字符串 "$1" "$2" ...

      $#: 返回参数个数

      $_: 上一条命令的最后一个参数
    3.普通变量导为环境变量(局部变量和全局变量)

      全局变量: 对所有shell及其创建的子进程(子shell)可见

      局部变量: 只对创建他们的shell可见

      export PATH=$PATH:/usr/local/bin #记住赋值、删除和导出的时候没有$符号

    4.读取变量

      read name #参数-t(表示等待多少秒输入)等

    5.查看变量

      set命令查看所有已经定义的变量

      env命令查看所有环境变量

    6.使用变量

      变量都是以字符串形式赋值的,默认把变量值当作字符串,declare -i age=22,这里就用 -i 选项把age定义为整型的了。此后每次运算,都把age的右值识别为算术表达式或数字。

    age=20
    age=${age}+1
    echo ${age} #输出"20+1"
    
    declare -i age=20
    age=${age}+1
    echo ${age} #输出21

      单引号不解释变量

      双引号解释变量

      为与PHP不相混, 最好统一使用 ${varname}, {$varname}在shell中不解释{}

      unset var 清除变量

      readonly var 变为只读变量

    7.数组

    #索引数组
    arr=(1 2 3) 
    arr[3]=4 #数组赋值
    
    #关联数组
    declare -A arr
    arr=([name]=John [age]=18)
    arr[sex]=male
    
    #数组赋值
    newarr=`(echo ${arr[*]})`
    newarr=(${arr[@]}) ${
    !array[*]} #取关联数组所有键,单个字符串格式 ${!array[@]} #取关联数组所有键,多个字符串格式 ${array[*]} #取关联数组所有值,单个字符串格式 ${array[@]} #取关联数组所有值,多个字符串格式 ${#array[*]} #关联数组的长度 ${#array[@]} #关联数组的长度
    ${arrary[@]:1:2} #切片操作。1表示索引起始位置,2表示切片长度
    echo ${arr[0]} #注意花括号使用 echo ${arr[*]} #打印整个数组 for k in ${!arr[@]}; do echo $k echo ${arr[$k]} done for v in ${arr[@]}; do #遍历数组值 echo $v done abc() { newarr=(`echo "$@"`) #重新把参数转为数组 }

    a=($@) #把参数转为数组

    8.表达式

      expr: 对整数型变量进行算术运算 #变量与操作符之间必须以空格分开, 变量用$

        expr `expr 2 + 3` / 5

      let: 同expr一样为计算功能, 但与expr相反, 不能用空格分开参数, 变量可以不用$, 但为了统一可以用

        let c=2+3

        let c=a+b

        let c=$a+$b

      $((...)): $(($a - $b))

      $[...]: $[$a - $b]

      以上几种都只支持整数运算, 以下语句支持浮点数运算

      var=`echo "scale=1;$var*2.0"|bc`  #bc(bash calculater)为内置bash计算器, 用内建变量 scale 指定小数点下位数, 默认值为 0(默认输出整数) , 可以在shell直接输入bc命令实战下

      var=`echo "$var 1"|awk '{printf("%g",$1+$2)}'`

      var=$(awk 'BEGIN{print 7.01*5-4.01 }')

      点击查看各个括号与表达式之间区别

    9.表达式执行

      `cmd`或者$(cmd) #重新开启一个子SHELL去执行

      l=`ls /`; echo $l;

    10.测试语句(一般不会单独使用, 会配合if, while等使用)

      test: 测试范围整数、字符串、文件

      整数:

        test $a -[ eq|ne|lt|gt|ge|le ] $b;

      字符串:

        test $a -[ >|<|=|!=|>=|<= ] $b; #大于号小于号要加转义, 否则表示重定向, "="表示比较而非赋值

        test $str1==$str2; test $str1; test -n $str1; test -z $str1; echo $?;

      文件:

        test -[ d|f|x|r|w|a|s空文件|O属于当前用户|G属于当前用户所属用户组 ] $file

        test $file1 -[ nt|ot ] $file2 文件创建时间比较

      以上可以用[]进行简化, 两者等同

        如: test -d $file 等价于 [ -d $file ] #一定要使用空格

          test [ -d $dir -o -f $file ] #-o表示逻辑或 -a表示逻辑与

    11.控制语句

      if语句, 用来测试命令执行成功与失败(直接使用命令),  或者执行判断数值-字符串-文件(test/[]形式), 或双小括号内表达式形式"(( 1 + 2 < 3))", 或双中括号"[[ $file = "r*" ]]"

      可以在多行定义多个语句, 只返回最后一个语句的状态码

     1   if [ -d $file ] ; then
     2 
     3     ...
     4 
     5   elif ...; then
     6 
     7     ...
     8 
     9   else
    10 
    11     ...
    12 
    13   fi

        如果条件为命令, 则命令执行后$? == 0为真, 否则为假

    if ls > aaaa; then
        echo 'aaaa'
    else
        echo 'bbbb'
    fi
    #输出aaaa

      for语句

    1 #for 变量名 in 名字列表/路径匹配/数组/{1..10}
    2 #do
    3 #    ...
    4 #done
    5 
    6 for day in mon tue wed thu fri sat sun
    7 do
    8     echo $day
    9 done

      case语句

     1 #case 变量 in
     2 #    字符串1)
     3 #        ...
     4 #     ;;
     5 #     字符串n)
     6 #         ...
     7 #     ;;
     8 # esac
     9 
    10 case $op in
    11     a|b|c)
    12         echo 'c';;
    13     d)
    14         echo 'd';;
    15     *)
    16         echo '*'17 esac

      while语句

     1 #while 条件
     2 #do
     3 #    命令
     4 #done
     5  
     6 while [ -d /etc ]
     7 do
     8     ls -ld /etc
     9 done
    10 
    11 num=1
    12 while [ $num -le 10 ]
    13 do
    14     sum=`expr $num * $num`
    15     echo $sum
    16     num=`expr $num + 1`
    17 done

      until语句

     1 #until 条件
     2 #do
     3 #    命令
     4 #done
     5 
     6 until [ -x /etc/inittab ]
     7 do
     8     /bin/ls -l /etc/inittab
     9     exit 0
    10 done
    11 
    12 read input
    13 until [ "$input" == "Y" ] || [ "$input" == "y" ]
    14 do 
    15     echo "Error"
    16     read input
    17 done

    break, continue跳出循环

    shift指令: 参数左移, 每执行一次, 参数序列顺序依次左移一个位置, $#的值减1; 用于分别处理每个参数, 移出去的参数不可再用;

     1 if [ $# -le 0 ]; then
     2     echo 'Not enough parameters'
     3     exit 0
     4 fi
     5 
     6 sum=0
     7 while [ $# -gt 0 ]
     8 do
     9     sum=`expr $sum + $1`
    10     shift
    11 done
    12 echo $sum

    函数的定义

     1 #函数名() {
     2 #    命令
     3 #}
     4 
     5 #函数的调用不带()
     6 #函数名 参数1 参数2
     7 
     8 #函数中的变量
     9 #变量均为全局, 没有局部变量
    10 
    11 help() {
    12     echo 'abcd'
    13 }
    14 
    15 调用: help

    函数的返回值

      1.默认返回值是最后一条语句返回的状态码

      2.return语句, 但是返回值必须在0~255之间, 用$?检查后是返回值

      3.使用输出(比如echo语句)作为返回值

    作用域

      默认情况下, 你在脚本中定义的任何变量都是全局变量, 在函数外定义的变量可以在函数内部正常访问

    abc() {
        a=10
    }
    abc
    echo $a #会输出10

       local关键字把变量限制在函数内, 即局部变量

    递归

    factorial() {
        if [ $1 -eq 1 ]; then
            echo 1
        else
            local temp=$[ $1 - 1 ]
            local result=`factorial $temp`
            echo $[ $result * $1 ]
        fi
    }

    使用库文件

      一个文件定义了各种函数, 怎么导入?直接执行?会创建一个新的shell并在新的shell中运行此脚本, 为新的shell定义几个变量或者函数, 不会用到本shell

      解决: 使用 source命令, 或者别名 "."

    使用 select in 创建菜单

    #option的值是字符串, 而非选择的整数值
    select option in "Display Errors" "Display Warnings" "Display Notice"
    do
        case $option in
            "Display Errors")
                echo "Errors";;
            "Display Warnings")
                echo "Warnings";;
            "Display Notice")
                echo "Notice";;
            *)
                echo "Wrong";;
        esac
    done

    菜单也可以使用dialog库来创建

    a=$' ' #单引号

    for时如果每次都有输出, 可以在done之后添加重定向

    利用read读取文件

    count=1
    cat test |while read line
    do
        echo "Line ${count}: ${line}"
        count=$[ $count + 1 ]
    done
    echo "Finished processing the file"

    重定向到其他文件描述符, 使用 >&1、>&2

    echo 'aaaaa' >&2

    永久重定向

    exec 0<testlog
    exec 1>testlog

      看例子

    exec 0<testlog
    count=1
    while read line
    do
        echo "Line ${count}: ${line}"
        count=$[ $count + 1 ]
    done
    echo "Finished processing the file"

    从永久重定向的文件描述符中恢复, 创建文件描述符

    exec 3>&1
    echo 'aaaa' >&3
    exec 1>testinfo
    exec 1>&3

       先将STDIN文件描述符保存到另外一个文件描述符, 读取完文件之后再将STDIN恢复到它原来的位置

    exec 6<&0
    exec 0<testlog
    
    count=1
    while read line
    do
        echo "Line #$count: $line"
        count=$[ $count + 1 ]
    done
    
    exec 0<&6

       关闭文件描述符

    exec 3>&-

    查看文件描述符列表

    lsof -p $$
    bash    4179 root    0u   CHR  136,1      0t0       4 /dev/pts/1
    bash    4179 root    1u   CHR  136,1      0t0       4 /dev/pts/1
    bash    4179 root    2u   CHR  136,1      0t0       4 /dev/pts/1
    bash    4179 root  255u   CHR  136,1      0t0       4 /dev/pts/1
    #因为STDIN, STDOUT, STDERR都指向终端, 所以文件名为终端设备名

    快速删除和创建文件(清空文件内容)

    cat /dev/null > filename

    mktemp在/tmp创建临时文件, 如果要指定文件名, 需要在文件名后加6个X, 从而保证文件名在此文件夹中是唯一的

    mktemp
    mktemp test.XXXXXX    #tmp.z8mAKO
    mktemp -d test.XXXXXX #创建临时文件夹
    mktemp -t test.XXXXXX #强制在系统的/tmp文件夹内创建临时文件

    tee 将输出一边发送到标准输出一边发送到文件, 默认是覆盖文件, 追加使用 -a 选项

    who |tee fname
    root     pts/1        2015-09-22 09:22 (xx.xx.xx.xx)

    信号: 用于进程间通讯

    strap捕捉信号 strap "处理信号命令行" 信号列表

    #!/bin/bash
    
    #程序执行完退出时的信号为EXIT
    trap "count=10" SIGINT SIGTERM
    #trap "echo 'Sorry! I have trapped the Ctrl-C'"
    echo This is a test program
    count=1
    while [ $count -le 10 ]
    do
        echo "Loop #$count"
        sleep 5
        count=$[ $count + 1]
    done
    trap - SIGINT #移除信号
    echo This is the end of the test program

    nice, renice用来修改优先级, -20 <= 优先级 <= 20, 越小优先级越高(好人难做)

    at可以指定某个时间执行某执行令, 该指令会被提交到作业队列中, 作业队列会保存通过at命令提交的待处理的作业, at的守护进程atd会以后台模式运行, 并检查作业队列来运行作业;  但是作业在Linux系统上运行时, 没有屏幕会关联到改作业, Linux会将提交该作业用户的E-mail地址作为STDOUT, STDERR, 任何发送到STDOUT, STDERR的输出都会通过邮件发送给该用户

    atq列出等待的作业

    atrm 作业号 删除作业

      at.sh

    #!/bin/bash
    
    echo This script ran at `date`
    echo This is the end of the scripit >&2

      定时执行

    at -f at.sh 10:39

      HH:MM 在今日的 HH:MM 时刻进行, 若该时刻已超过, 则明天的 HH:MM 进行此任务

      HH:MM YYYY-MM-DD 强制规定在某年某月的某一天的特殊时刻进行该项任务

      HH:MM[am|pm] [Month] [Date] 强制在某年某月某日的某时刻进行该项任务

      HH:MM[am|pm] + number [minutes|hours|days|weeks] 在某个时间点再加几个时间后才进行该项任务

  • 相关阅读:
    题库重整
    计算几何练习题――直线交点
    An Easy Task
    简单排序
    IBM Minus One
    Binary Numbers
    去掉VS2010代码中文注释的红色下划线
    【转】Windows socket基础
    【STL】vector的insert方法详解
    window7下 cocos2dx android交叉编译环境部署小结
  • 原文地址:https://www.cnblogs.com/JohnABC/p/3343970.html
Copyright © 2020-2023  润新知