zoukankan      html  css  js  c++  java
  • 《Linux.Shell编程从入门到精通》读书笔记

    第一章 第一个Shell程序

    • 以 #!解析器名称 开头,表示选择哪个解释器解释shell脚本
    • source命令
    • export命令
    • env命令
    • unset命令
      第二章 shell编程基础
    • 函数传递
    • 标准输入输出符号
      第三章 编程的基本元素
    • 获取命令执行返回值
    • $((数值计算)) 获取数值计算结果 如:$((100 - 2*100/400))
    • 替换运算符
    • 模式匹配运算符
    • shift命令可以截取参数列表最左端的一个参数
    • type命令判断被执行命令的来源(别名、关键字、函数、内置命令、外部命令)
    • test命令用于评估表达式,返回零(true)或者非零(false)
    • 逻辑运算符
    • 运算符号
    • 执行反单引号(`)之间的命令,引用结果作为字符串
    • getopt命令用于分析命令标志和参数
      第四章 正则表达式
    • 元字符
    • POSIX字符集
    • 后向引用
    • 交替、分组
      第五章 基本文本处理
    • 排序文本
    • 文本去重
    • 统计文本
    • 打印和格式化输出
    • 提取文本开头和结尾
    • 字段处理
    • 文本替换
    • Linux下的配置文件
      第六章 文件和文件系统
    • 文件
    • 文件系统
      第七章 流编辑器sed
    • 工作地址范围
    • 命令
    • [:特殊字符:]用于匹配特俗字符
      第八章 文本处理利器awk
    • awk代码结构
    • 内建变量
    • 局部变量
    • 字符串函数
      第九章 进程
    • 进程管理命令
    • init进程
    • 调度系统任务
    • 加载proc虚拟文件系统:mount -t proc proc /proc
      第十章 OpenSSH
    • 安装openssh
    • 使用SSH登录远程主机(要求远程主机正在运行sshd)
      第十一章 实用程序(日志处理程序、系统监控程序)
    • 日志清理程序
    • 系统监控程序

    第一个Shell程序

    以 #!解析器名称 开头,表示选择哪个解释器解释shell脚本

    source命令
    使用source执行shell脚本时,不会创建子进程,而在父进程中直接执行。
    当需要在程序中修改当前shell本身的环境变量时,使用source命令
    source命令也可用来读入包含函数的文件
    使用方法:source fileName 或者 . fileName

    export命令
    export命令用于设置或显示环境变量
    使用方法:export [-fnp] [变量名称]=[变量设置值]
    -f 代表[变量名称]中为函数名称
    -n 删除指定的变量。变量实际上并没有删除,只是不会输出到后续指令的执行环境中
    -p 列出所有的shell赋予程序

    env命令
    env命令用于临时改变环境变量值

    unset命令
    从当前shell删除变量或函数

    shell编程基础

    函数传递
    $0 $1 $2 位置参数
    $* 以一个单字符串显示所有向脚本传递的参数
    $@ 所有向脚本传递的参数
    $# 传入函数的参数个数
    $$ 脚本运行的当前进程id号
    $! 后台运行的最后一个进程id号
    $? 显示最后命令的退出状态
    $- 显示shell使用的当前选项

    标准输入输出符号
    0<:标准输入
    1> 或者 >:重定向标准输出
    2>:重定向标准错误
    &>:标准输出和标准错误

    编程的基本元素

    获取命令执行返回值

    1. $(命令) 如:$(date +%Y%m%d%H%M%S)
    2. 命令 如:echo 123

    $((数值计算)) 获取数值计算结果 如:$((100 - 2*100/400))

    替换运算符

    1. ${varname:-word}
      如果varname存在且非null,则返回varname的值;否则,返回word
    2. ${varname:=word}
      如果varname存在且非null,则返回varname的值;否则,将varname的值设置为word,然后返回word
    3. ${varname:?message}
      如果varname存在且非null,则返回varname的值;否则打印message,并退出当前脚本
    4. ${varname:+word}
      如果varname存在且非null,则返回word;否则返回null

    模式匹配运算符

    1. ${varname#pattern}
      如果模式匹配变量取值的开头处,则删除匹配的最短部分,并返回剩下部分
    2. ${varname##pattern}
      如果模式匹配变量取值的开头处,则删除匹配的最长部分,并返回剩下部分
    3. ${varname%pattern}
      如果模式匹配变量取值的结尾处,则删除匹配的最短部分,并返回剩下部分
    4. ${varname%%pattern}
      如果模式匹配变量取值的结尾处,则删除匹配的最长部分,并返回剩下部分
    5. ${varname/pattern/string} ${varname//pattern/string}
      将varname中匹配模式的最长部分替换为string
      第一种格式中,只有匹配的第一部分被替换,第二种格式中,varname中所有匹配的部分都被替换
      如果模式以#开头,则必须匹配varname的开头,如果模式以%开头,则必须匹配varname的结尾

    shift命令可以截取参数列表最左端的一个参数

    type命令判断被执行命令的来源(别名、关键字、函数、内置命令、外部命令)

    test命令用于评估表达式,返回零(true)或者非零(false)

    逻辑运算符

    1. 关于文件与目录的侦测逻辑卷标!
      -f 常用!侦测『文件』是否存在 eg: if [ -f filename ]
      -d 常用!侦测『目录』是否存在
      -b 侦测是否为一个『 block 文件』
      -c 侦测是否为一个『 character 文件』
      -S 侦测是否为一个『 socket 标签文件』
      -L 侦测是否为一个『 symbolic link 的文件』
      -e 侦测『某个东西』是否存在!
    2. 关于程序的逻辑卷标!
      -G 侦测是否由 GID 所执行的程序所拥有
      -O 侦测是否由 UID 所执行的程序所拥有
      -p 侦测是否为程序间传送信息的 name pipe 或是 FIFO
    3. 关于文件的属性侦测!
      -r 侦测是否为可读的属性
      -w 侦测是否为可以写入的属性
      -x 侦测是否为可执行的属性
      -s 侦测是否为『非空白文件』
      -u 侦测是否具有『 SUID 』的属性
      -g 侦测是否具有『 SGID 』的属性
      -k 侦测是否具有『 sticky bit 』的属性
    4. 两个文件之间的判断与比较 ;例如[ test file1 -nt file2 ]
      -nt 第一个文件比第二个文件新
      -ot 第一个文件比第二个文件旧
      -ef 第一个文件与第二个文件为同一个文件( link 之类的文件)
    5. 逻辑的『和(and)』『或(or)』
      && 逻辑的 AND 的意思
      || 逻辑的 OR 的意思

    运算符号
    = 等于 应用于:整型或字符串比较 如果在[] 中,只能是字符串
    != 不等于 应用于:整型或字符串比较 如果在[] 中,只能是字符串
    < 小于 应用于:整型比较 在[] 中,不能使用 表示字符串
    大于 应用于:整型比较 在[] 中,不能使用 表示字符串
    -eq 等于 应用于:整型比较
    -ne 不等于 应用于:整型比较
    -lt 小于 应用于:整型比较
    -gt 大于 应用于:整型比较
    -le 小于或等于 应用于:整型比较
    -ge 大于或等于 应用于:整型比较
    -a 双方都成立(and) 逻辑表达式 –a 逻辑表达式
    -o 单方成立(or) 逻辑表达式 –o 逻辑表达式
    -z 空字符串
    -n 非空字符串

    执行反单引号(`)之间的命令,引用结果作为字符串

    getopt命令用于分析命令标志和参数

    正则表达式

    元字符
    ^ 锁定行或字符串的开始
    $ 锁定行或字符串的结尾
    当^和$结合使用时,意味着模式必须匹配整个串
    . 匹配除了换行符以外的任意字符
    [...] 方括号表达式,匹配括号内任意一个字符;如果^符号位于方括号的开始,则不匹配方括号中的任意字符
    转义字符,用于打开或关闭后续字符的特殊含义
    x{m,n} 区间表达式,匹配x字符出现的次数区间
    ? 匹配前面正则表达式的零个或一个实例

    • 匹配前面正则表达式的一个或多个实例
    • 匹配零个或多个前面字符
      | 匹配前面或后面的正则表达式
      () 匹配括号括起来的正则表达式
       单词锁定符,代表单词的开头和结尾,即单词的分界处
      B 匹配两个单词组成字符间的空字符串
      < > 分别匹配单词开头和单词结尾
      换行符
      d 匹配一位数字
      w 匹配文字和数字字符
      W 匹配一个或多个非单词字符

    POSIX字符集
    [:alnum:] 数字字符
    [:alpha:] 字母字符
    [:blank:] 空格与制表符
    [:cntrl:] 控制字符
    [:digit:] 数字字符
    [:graph:] 非空格
    [:lower:] 小写字母
    [:print:] 可显示的字符
    [:punct:] 标点符号字符
    [:space:] 空白(whitespace)字符
    [:upper:] 大写字母
    [:xdigit:] 十六进制数字
    [. .] 排序符号,如[.cn.]表示cn字符序列,而单独的c和n都不行
    [= =] 等价字符集

    后向引用:匹配之前正则表达式使用(和)括起来选定之后引用的模式,使用1~9来引用选定的模式
    如:(go).*1 匹配一行中前后出现两个go

    交替、分组
    交替|:在不同序列之间用管道符号隔开
    分组():让元字符修饰前置字符串
    如:(man|woman)+ 匹配一个或多个man或者woman字符串

    基本文本处理

    排序文本
    sort命令用于排序文件,对已排序的文件进行合并,并检查文件以确定它们是否已排序

    文本去重
    uniq命令用于文本去重(在使用uniq命令前,先使用sort命令,使所有重复行相邻)

    统计文本
    wc命令用于统计文本行数、字数以及字符数

    打印和格式化输出
    pr命令用于将文本转换成适合打印的文件
    fmt命令用于编排文本文件
    fold命令限制文本宽度

    提取文本开头和结尾
    head命令提取文件开头
    tail命令提取文件结尾

    字段处理
    cut命令用于从一个文本文件或者文本流中提取文本列
    join命令用于根据指定栏位,找到两个文件中指定栏位内容相同的行,将它们合并,并根据要求的格式输出内容

    文本替换
    tr命令用于替换字符

    Linux下的配置文件
    /etc/group 用户组定义
    /etc/passwd 用户信息定义
    /etc/inittab init的配置文件,在Linux启动时扮演重要角色
    /etc/shadow 用户密码的存放地址
    /etc/crontab cron(定期执行命令的程序)的配置文件
    /etc/fstab 文件系统信息

    文件和文件系统

    文件
    ls命令用于列出文件
    chown命令用于改变文件的所有者
    chgrp命令用于改变文件的用户组
    umask命令用于指定哪些权限在新文件的默认权限中被删除
    chmod命令用于修改文件权限
    touch命令更新文件的访问和修改时间
    find命令用于寻找文件
    xargs命令用于遍历处理文件
    comm命令用于比较两个已排序文件之间的差异
    diff命令用于比较两个文件之间的差异

    文件系统
    fdisk命令用于查看/修改系统的分区表
    mkfs命令用于创建文件系统
    mount命令用于加载文件系统到指定的加载点
    umount命令用于卸载已经加载的文件系统
    df命令用于显示当前挂载情况

    流编辑器(sed)

    工作地址范围

    1. 行地址 如:删除第一行 sed -e '1d' filePath
    2. 行范围地址 如:打印1到5行 sed -n -e '1,5p' filePath
    3. 正则表达式地址 如:打印所有以开头的注释行 sed -n -e '/^#/p' filePath
    4. 两个用逗号分开的正则表达式之间的地址 如:打印从包含'BEGIN'的行开始,并且包含'END'的行结束的文本块 sed -n -e '/BEGIN/,/END/p' filePath

    命令

    1. d 删除
    2. p 打印
    3. s/// 替换
    4. = 打印行号
    5. i 插入
    6. a 追加

    [:特殊字符:]用于匹配特俗字符

    文本处理利器(awk)

    awk代码结构

    1. 处理输入前的初始化
      BEGIN{
      ....
      }
    2. 处理输入过程
      [ 条件 ] {
      ...
      }
    3. 处理完所有输入后的扫尾工作
      END{
      ...
      }

    内建变量
    FILENAME 当前输入文件的名称
    FS 字段分隔符(支持正则表达式),默认为空格
    OFS 输出字段分隔字符,默认为空格
    ORS 输出记录分隔字符,默认为
    RS 输入记录分隔字符
    NF 当前记录的字段数
    NR 在工作中的记录数
    FNR 当前输入文件的记录数

    局部变量:列在函数参数列表中并且在字首前置一些额外的空白 如: add(x,y, sum) {}

    字符串函数
    sub(/reg/, newsubstr, str) 只替换第一个匹配字符串
    gsub(/reg/, newsubstr, str) 将字符串str中所有符号/reg/正则的子串替换为字符串newsubstr
    index(str, substr) 返回子串substr在串str中的索引
    length(str) 返回字符串的长度
    match(str, /reg/) 如果在串str中找到正则/reg/匹配的串,则返回出现的位置,未找到则返回0
    split(str, array, sep) 使用分隔符sep把字符串分解成数组array
    substr(str, position[, length]) 返回str中从position开始的length个字符
    toupper(str) 对字符进行大小写转换
    sprintf("format", expr) 对expr使用printf格式说明

    进程

    进程管理命令
    fork函数用于创建进程
    ps命令用于查看系统正在运行的进程
    top命令用于查看系统一段时间进程的动态信息
    pstree命令用于打印进程树形结构
    Ctrl+C快捷键用于中断前台进程
    Ctrl+快捷键用于杀死前台进程
    Ctrl+Z快捷键用于挂起前台进程
    bg命令用于将挂起进程转换为后台进程
    fg命令用于将后台进程转换为前台进程
    jobs命令用于显示当前shell的进程状况
    kill命令用于向指定进程发送信号
    init命令用于进程初始化工具,可切换运行等级

    init进程

    1. /etc/inittab init程序读取的配置文件
      基本格式为 id:runlevels:action:process
      • id为1~2个字符,配置行的唯一标识,在配置文件中不能重复
      • runlevels(运行等级)取值如下
        • 等级0表示:表示关机(千万不能把initdefault 设置为0)
        • 等级1表示:单用户模式
        • 等级2表示:无网络连接的多用户命令行模式
        • 等级3表示:有网络连接的多用户命令行模式
        • 等级4表示:不可用
        • 等级5表示:带图形界面的多用户模式
        • 等级6表示:重新启动(千万不要把initdefault 设置为6)
      • action取值如下
        • respawn 启动并监视第4项指定的process,若process终止则重启它
        • wait 执行第4项指定的process,并等待它执行完毕
        • once 执行第4项指定的process
        • boot 不论在哪个执行等级,系统启动时都会运行第4项指定的process
        • bootwait 不论在哪个执行等级,系统启动时都会运行第4项指定的process,且一直等它执行完备
        • off 关闭任何动作,相当于忽略该配置行
        • ondemand 进入ondemand执行等级时,执行第4项指定的process
        • initdefault 系统启动后进入的执行等级,该行不需要指定process
        • sysinit 不论在哪个执行等级,系统会在执行boot 及bootwait之前执行第4项指定的process
        • powerwait 当系统的供电不足时执行第4项指定的 process,且一直等它执行完毕
        • powerokwait 当系统的供电恢复正常时执行第4项指定的process,且一直等它执行完毕
        • powerfailnow 当系统的供电严重不足时执行第4项指定的process
        • ctrlaltdel 用户按下【Ctrl+Alt+Del】时执行的操作
        • kbrequest 当用户按下特殊的组合键时执行第4项指定的process,此组合键需在keymaps文件定义
      • process为所要执行的shell命令。任何合法的shell语法均适用于该字段。
    2. /etc/rc.d/rcX.d文件(X代表运行等级)含有各个运行等级服务启动和终止配置
      /etc/rc.d/init.d目录下存放着对应运行等级的服务脚本
    3. 修改配置/etc/inittab后马上生效:kill -1 1 或者 init q

    调度系统任务

    1. crontab命令用于调度重复性的任务
      控制访问的文件:cron.allow、cron.deny
    2. at命令用于调度只执行一次的任务
      控制访问的文件:at.deny

    加载proc虚拟文件系统:mount -t proc proc /proc

    SSH

    安装openssh

    • 替换阿里云的源
      echo "http://mirrors.aliyun.com/alpine/latest-stable/main/" > /etc/apk/repositories
      echo "http://mirrors.aliyun.com/alpine/latest-stable/community/" >> /etc/apk/repositories

    • 同步时间
      cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

    • 更新源、安装openssh 并修改配置文件、生成key、启动sshd服务
      apk update &&
      apk add --no-cache openssh-server tzdata &&
      sed -i "s/#PermitRootLogin.*/PermitRootLogin yes/g" /etc/ssh/sshd_config &&
      ssh-keygen -t rsa -P "" -f /etc/ssh/ssh_host_rsa_key &&
      ssh-keygen -t ecdsa -P "" -f /etc/ssh/ssh_host_ecdsa_key &&
      ssh-keygen -t ed25519 -P "" -f /etc/ssh/ssh_host_ed25519_key &&
      /usr/sbin/sshd -D

    使用SSH登录远程主机(要求远程主机正在运行sshd)

    • 基于口令的登录方法
      ssh -l 登录账号 远程主机

    • 基于密钥对的登录方法

      • 生成密钥对:ssh-keygen -d
      • 把公钥上传到服务器上(/.ssh/id_dsa.pub、/.ssh/authorized_keys)
      • 测试自动登录:ssh [登录账号@]远程主机 (需要输入第一步输入的passphrase,若想不输入passphrase可以考虑ssh-agent)

    实用程序

    日志清理程序
    把以下代码保存为log_clean.sh文件中即可使用
    内含操作:备份重要的日志、限制日志目录大小、清理老旧日志

    
    # maximum log size
    alarmrate=500
    # the max size file can reach
    file_max_size=5
    # this is the directory where fresh logs are originally written
    working_dir=/mnt/soho_storage/log
    # this is the frequency our program runs
    SLEEPTIME=5
    
    # append year.month.day and timestamp to log filename
    filenameConvert()
    {
        timestamp=$(date +%Y%m%d%H%M%S)
        timestamp=`echo $timestamp`
        RETVAL=$1.$timestamp
    }
    
    # search dir to fetch the oldest log
    searchdir()
    {
        oldestlog=`ls -rt | head -n 1 | awk '{print $1}'`
    }
    
    # this function clean old logs under working dir if it reaches it's size limitation
    clear_old_log_under_working_dir()
    {
        cd $working_dir
        while true
        do
            logsize=`du -ms $working_dir | awk '{print $1}'`
            if [ $logsize -gt $alarmrate ]
            then
                searchdir
                rm -rf $oldestlog
            else
                break;
            fi
        done
    }
    
    # this is the main process of our log backup activity
    backuplog_process()
    {
        cd $log_ram_dir
        for i in * 
        do
            file_size=`du -m $i | awk '{print $1}'`
            # need to backup log file
            case $i in access.log | error.log | apcupsd.events | soho.log)
                if [ ! -d $working_dir ]
                then
                    mkdir -p $working_dir
                fi
                if [ file_size -gt file_max_size ]
                then
                    filenameConvert $i
                    cp $log_ram_dir/$i $working_dir/$RETVAL
                    echo "" > $log_ram_dir/$i
                    clear_old_log_under_working_dir
                fi
                ;;
            *)
                if [ file_size -gt file_max_size ]
                then
                    echo "" > $log_ram_dir/$i
                fi
        done
    }
    
    while true
    do
        backuplog_process
        sleep $SLEEPTIME
    done
    
    

    系统监控程序
    把以下代码保存为system_monitor.sh文件中即可使用
    内含操作:监控内存、硬盘、CPU、进程,形成状态报告

    
    # maximum ratio of memory usage
    mem_quota=80
    # hard disk
    hd_path=/dev/sda1
    # maximum ratio of hard disk usage
    hd_quota=80
    # maximum ratio of cpu usage
    cpu_quota=80
    # time gap between two times fetching cpu status
    time_gap=60
    # generate report every 10 minutes
    runtime_gap=60
    
    # fetch the ratio of memory usage
    # @return 1: if larger than $mem_quota
              0: if less than $mem_quota
    watch_memory()
    {
        mem_total=`cat /proc/meminfo | grep MemTotal | awk '{print $2}'`
        mem_free=`cat /proc/meminfo | grep MemFree | awk '{print $2}'`
        mem_usage=$((100-mem_free*100/mem_total))
        if [ $mem_usage -gt $mem_quota ]
        then
            mem_message="ALARM!! The memory usage is $mem_usage%!!"
            return 1
        else
            return 0
        fi
    }
    
    # fetch the top 10 most wasting memory process
    proc_memory_top10()
    {
        mem_busiest=`ps aux | sort -nk 4r | head -n 11`
    }
    
    # fetch the ratio of hard disk usage
    # @return 1: if larger than $hd_quota
              0: if less than $hd_quota    
    watch_hd()
    {
        hd_usage=`df | grep $hd_path | awk '{print $5}' | sed 's/%//g'`
        if [ $hd_usage -gt $hd_quota ]
        then
            hd_message="ALARM!! The hard disk usage is $hd_usage%!!"
            return 1
        else
            return 0
        fi
    }
    
    # fetch cpu status at a time point
    # format used unused
    get_cpu_info()
    {
        cat /proc/stat | grep -i "^cpu[0-9]+" | awk '{used+=$2+$3+$4;unused+=$5+$6+$7+$8} END{print used,unused}'
    }
    
    # fetch the ratio of cpu usage
    # fetch cpu stat two times, with time gap, then calculate the average status
    # @return 1: if larger than $cpu_quota
              0: if less than $cpu_quota    
    watch_cpu()
    {
        time_point_1=`get_cpu_info`
        sleep $time_gap
        time_point_2=`get_cpu_info`
        cpu_usage=`echo $time_point_1 $time_point_2 | awk '{used=$3-$1;total+=$3+$4-$2-$1}';print $used*100/total`
        if [ $cpu_usage -gt $cpu_quota ]
        then
            cpu_message="ALARM!! The cpu usage is over $cpu_usage%!!"
            return 1
        else
            return 0
        fi
    }
    
    # fetch the top 10 busiest processes
    proc_cpu_top10()
    {
        proc_busiest=`ps aux | sort -nk 3r | head -n 11`
    }
    
    while true
    do
        # report content
        report=""
        # memory monitor
        if [ `watch_memory` -eq 1 ]
        then
            report=$report'
    '$mem_message
            proc_memory_top10
            report=$report'
    '$mem_busiest
        fi
        # hard disk monitor
        if [ `watch_hd` -eq 1 ]
        then
            report=$report'
    '$hd_message
        fi
        # cpu monitor
        if [ `watch_cpu` -eq 1 ]
        then
            report=$report'
    '$cpu_message
            proc_cpu_top10
            report=$report'
    '$proc_busiest
        fi
        # feedback report
        if [ -n $report ]
        then
            # todo...
        fi
        # sleep time
        sleep $((runtime_gap-time_gap))
    done
    
    
  • 相关阅读:
    Java实现 蓝桥杯 算法提高 队列操作
    DUILIB创建不规则窗体,自定义控件(很不错的几十篇文章)
    修改窗口属性(全部都是SetWindowLong设置)
    搭建DirectUi开发平台
    _CrtSetBreakAlloc简单内存泄漏检测方法,解决Detected memory leaks!问题
    VLD(Visual LeakDetector)内存泄露库的使用
    设计模式之组合模式
    Moq的使用心得
    Moq 测试 属性,常用方法
    C#中Linq查询基本操作
  • 原文地址:https://www.cnblogs.com/phonecom/p/10052319.html
Copyright © 2011-2022 走看看