精华内容
下载资源
问答
  • linux下python脚本编写
    千次阅读
    2022-01-27 16:50:36

    服务器测试中,我们就经常用到shell和python脚本。测试时间长了,这两种语言就有必要学习一下。下面我们将一个简单的shell脚本转化为python。
    比如 一个检测ssd smart log的脚本

    #!/bin/bash
    for ssd in `lsscsi  |grep -i disk |awk '{print $NF}'`
    do
            echo "==========$ssd===========" |tee -a ssd.log
            smartctl -i $ssd |tee -a ssd.log
    done
    
    

    log如下:

    [root@localhost ~]# cat ssd.log
    ==========/dev/sda===========
    smartctl 7.0 2018-12-30 r4883 [x86_64-linux-3.10.0-1160.49.1.el7.x86_64] (local build)
    Copyright (C) 2002-18, Bruce Allen, Christian Franke, www.smartmontools.org
    
    === START OF INFORMATION SECTION ===
    Vendor:               AVAGO
    Product:              MR9361-8i
    Revision:             4.68
    Compliance:           SPC-3
    User Capacity:        479,559,942,144 bytes [479 GB]
    Logical block size:   512 bytes
    Physical block size:  4096 bytes
    Logical Unit id:      0x600605b0110407b02957eacaa6c2f752
    Serial number:        0052f7c2a6caea5729b0070411b00506
    Device type:          disk
    Local Time is:        Thu Jan 27 16:38:04 2022 CST
    SMART support is:     Unavailable - device lacks SMART capability.
    
    ==========/dev/sdb===========
    smartctl 7.0 2018-12-30 r4883 [x86_64-linux-3.10.0-1160.49.1.el7.x86_64] (local build)
    Copyright (C) 2002-18, Bruce Allen, Christian Franke, www.smartmontools.org
    
    === START OF INFORMATION SECTION ===
    Vendor:               AVAGO
    Product:              MR9361-8i
    Revision:             4.68
    Compliance:           SPC-3
    User Capacity:        479,559,942,144 bytes [479 GB]
    Logical block size:   512 bytes
    Physical block size:  4096 bytes
    Logical Unit id:      0x600605b0110407b02957eacba6c8d581
    Serial number:        0081d5c8a6cbea5729b0070411b00506
    Device type:          disk
    Local Time is:        Thu Jan 27 16:38:04 2022 CST
    SMART support is:     Unavailable - device lacks SMART capability.
    
    ==========/dev/sdc===========
    smartctl 7.0 2018-12-30 r4883 [x86_64-linux-3.10.0-1160.49.1.el7.x86_64] (local build)
    Copyright (C) 2002-18, Bruce Allen, Christian Franke, www.smartmontools.org
    
    
    

    现在用python的语言转化一下,用os模块调用指令

    import os
    ssd = os.popen("lsscsi  |grep -i avago |awk '{print $NF}' ").read()
    print ssd
    
    

    打印结果如下:

    [root@localhost ~]# python try.py
    /dev/sda
    /dev/sdb
    /dev/sdc
    /dev/sdd
    /dev/sde
    /dev/sdf
    /dev/sdg
    /dev/sdh
    /dev/sdi
    /dev/sdj
    /dev/sdk
    /dev/sdl
    
    [root@localhost ~]# cat try.py
    
    

    最后一行为空,遍历的时候需要去掉最后一行,然后遍历列表

    import os
    ssd = os.popen("lsscsi  |grep -i avago |awk '{print $NF}' ").read()
    print ssd.split('\n')[:-1]
    

    结果如下:

    [root@localhost ~]# python try.py
    ['/dev/sda', '/dev/sdb', '/dev/sdc', '/dev/sdd', '/dev/sde', '/dev/sdf', '/dev/sdg', '/dev/sdh', '/dev/sdi', '/dev/sdj', '/dev/sdk', '/dev/sdl']
    

    然后 输出 smart log信息

    import os
    ssd = os.popen("lsscsi  |grep -i avago |awk '{print $NF}' ").read()
    for i in ssd.split('\n')[:-1]:
        os.popen("echo ========="+i+"=======>>1.log")
        c = os.popen("smartctl -i {} >> 1.log".format(i)).read()
    

    结果如下:

    [root@localhost ~]# cat 1.log
    =========/dev/sda=======
    smartctl 7.0 2018-12-30 r4883 [x86_64-linux-3.10.0-1160.49.1.el7.x86_64] (local build)
    Copyright (C) 2002-18, Bruce Allen, Christian Franke, www.smartmontools.org
    
    === START OF INFORMATION SECTION ===
    Vendor:               AVAGO
    Product:              MR9361-8i
    Revision:             4.68
    Compliance:           SPC-3
    User Capacity:        479,559,942,144 bytes [479 GB]
    Logical block size:   512 bytes
    Physical block size:  4096 bytes
    Logical Unit id:      0x600605b0110407b02957eacaa6c2f752
    Serial number:        0052f7c2a6caea5729b0070411b00506
    Device type:          disk
    Local Time is:        Thu Jan 27 16:34:40 2022 CST
    SMART support is:     Unavailable - device lacks SMART capability.
    
    =========/dev/sdb=======
    smartctl 7.0 2018-12-30 r4883 [x86_64-linux-3.10.0-1160.49.1.el7.x86_64] (local build)
    Copyright (C) 2002-18, Bruce Allen, Christian Franke, www.smartmontools.org
    
    === START OF INFORMATION SECTION ===
    Vendor:               AVAGO
    Product:              MR9361-8i
    Revision:             4.68
    Compliance:           SPC-3
    User Capacity:        479,559,942,144 bytes [479 GB]
    Logical block size:   512 bytes
    Physical block size:  4096 bytes
    Logical Unit id:      0x600605b0110407b02957eacba6c8d581
    Serial number:        0081d5c8a6cbea5729b0070411b00506
    Device type:          disk
    Local Time is:        Thu Jan 27 16:34:40 2022 CST
    SMART support is:     Unavailable - device lacks SMART capability.
    
    =========/dev/sdc=======
    
    
    更多相关内容
  • Linux下python脚本编写小结 1.如何在linux系统中,看是否安装了python: —which python 或者 which python3 如何在python脚本中使用shell命令: ----通过os模块的os.system()来使用,需要注意的是参数是字符串,...

    Linux下python脚本编写小结

    1.如何在linux系统中,看是否安装了python:
    —which python 或者 which python3

    1. 如何在python脚本中使用shell命令:
      ----通过os模块的os.system()来使用,需要注意的是参数是字符串,返回值是exit code。虽然在pyton解释器中可以显示命令执行结果内容,但shell运行 结果的内容的并不会作为返回值以字符串的形式返回。
      ----如何获取运行shell命令的结果,目前是通过>>重定向输出到指定文本来实现的。

    3.文件操作:
    —python本身有文件操作的,但由于暂未确定如何获取shell命令结果内容,所以使用了linux本身的文件操作。后续有方法可以获取shell命令结果,可以尝试使用pyhon本身的文件操作。

    1. python脚本小结:
      ----演示脚本其实功能很简单,但完成了运维信息收集的基本功能,后期通过增加使用shell命令可以改进成搜集更多运维信息的脚本。
      ----后续需要改进的地方主要是保存信息的文件的循环写入,或者根据文件大小创建新的文件,保证可以持续收集信息。
      ----在后期可以考虑通过tftp等方式把收集的信息传输到远端,控制设备本身因为脚本使用而占用的内容过大。常见的情况下,比如tcpdump抓包,容易导致设备oom.

    一个简单的linux运维脚本实例:
    #!/usr/bin/env python
    import os
    from time import *
    os.system(“cd /tmp”)
    os.system(“echo “the python script is runnuing””)
    os.system(“touch Linux_log.txt”)
    Log_oper=open(“Linux_log.txt”,“a+”)
    for i in range(1,11,2):
    os.system(“pstree >>Linux_log.txt”)
    os.system(“date >>Linux_log.txt”)
    #Log_oper.write(Log_read)
    sleep(5)
    Log_oper.close()
    print(“Script tests ok”)

    运行结果:
    运行结果

    展开全文
  • 主要给大家介绍了关于Linux下Python脚本自启动与定时任务的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用python具有一定的参考学习价值,需要的朋友们下面跟着小编来一起学习学习吧。
  • 主要介绍了Linux下Python脚本自启动和定时启动的详细步骤,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考
  • Linux系统shell脚本、python脚本编写

    千次阅读 2021-10-13 16:43:08
    参考:GPU排队脚本(python脚本) cmd = 'bash run.sh' 该句设置要执行的python脚本 import os import sys import time cmd = 'bash run.sh' #设置运行的脚本 def gpu_info(): gpu_status = os.popen('nvidia-...

    GPU排队脚本

    python脚本

    GPU排队脚本 ---- GPU一旦空闲触发脚本执行程序

    参考: GPU排队脚本(python脚本)

    cmd = 'bash run.sh' 该句设置要执行的python脚本

    import os
    import sys
    import time
    
    cmd = 'bash run.sh' #设置运行的脚本
    
    def gpu_info():
        gpu_status = os.popen('nvidia-smi | grep %').read().split('|')
        gpu_memory = int(gpu_status[2].split('/')[0].split('M')[0].strip())
        gpu_power = int(gpu_status[1].split('   ')[-1].split('/')[0].split('W')[0].strip())
        return gpu_power, gpu_memory
    
    def narrow_setup(interval = 2):
        gpu_power, gpu_memory = gpu_info()
        i = 0
        while gpu_memory > 10000 or gpu_power > 100:  #set waiting condition
            gpu_power, gpu_memory = gpu_info()
            i = i % 5
            symbol = 'monitoring: ' + '>' * i + ' ' * (10 - i - 1) + '|'
            gpu_power_str = 'gpu power: %d W |' % gpu_power
            gpu_memory_str = 'gpu memory: %d MiB |' % gpu_memory
            sys.stdout.write('\r' + gpu_memory_str + '\t' + gpu_power_str + '\t' + symbol)
            sys.stdout.flush()  #sys.stdout.flush()的作用就是显示地让缓冲区的内容输出
            time.sleep(interval)
            i += 1
        print("\n" + cmd)
        os.system(cmd)
    
    if __name__ == '__main__':
        narrow_setup()

    即可 监听nvidia-smi的信息, 以伺机触发python脚本, 当GPU的显存以及功耗低于某个值时,便会触发python脚本。

    shell脚本

    可以在shell脚本中直接添加训练训练模型的语句

    #!/bin/bash
    var=0
    
    while [ $var -eq 0 ]
    do
        count=0
        for i in $(nvidia-smi --query-gpu=memory.used --format=csv,noheader,nounits)
        do
            if [ $i -lt 500 ]
            then
                echo 'GPU'$count' is available'
                bash run.sh #训练模型的语句
                var=1
                break
            fi
            count=$(($count+1))
            #echo $count
        done
    done

    Linux命令

    more命令

    more命令查看文件分页显示

    (more +N file_name 从指定行开始显示)

    (more -N file_name 设置每次屏幕显示的行数)

    • 空格键:查看下一屏
    • 回车键:往下滚动一行
    • b键:往前查看一屏
    • q键:退出

    管道符 |

    命令格式:命令A | 命令B (即命令A的正确输出作为命令B的操作对象)

    cat file | more(先展示了file中的内容,然后more指令再处理file的内容)

    grep指令

    grep(global search regular expression(RE) and print out the line,全面搜索正则表达式并把行打印出来):使用正则表达式搜索文本,并把匹配的行打印出来。

    id    name    java
    1     90      90
    2     lisi    89
    3     wangw   93
    4     zhao    82
    grep -c 字符串 文件名:计算找到搜索字符串的行数
    grep -c "name" student.txt
    #1
    grep -o 字符串 文件名:指出匹配的内容
    grep -o "zhang" student.txt
    #
    grep -o "zh" student.txt
    #zh
    grep -i 字符串 文件名:不区分大小写打印出一行信息
    grep -i "zh" student.txt
    #4    zhao    82
    grep -n 字符串 文件名:显示行号
    grep -n "zh" student.txt
    5:4    zhao    82

    cut指令

    cut:提取某一列

    cut -f 列号:提取第几列

    -d 分隔符:按照指定分隔符分割列

    awk指令

    Shell脚本编写

    Linux之Shell脚本编程(一)

    shell脚本编程快速入门

    Shell是命令解释器(command interpreter),是Unix操作系统的用户接口。

    Shell也是一门编程语言,即shell脚本,shell是解释执行的脚本语言,可直接调用linux命令。一个系统可以存在多个shell,可以通过cat /etc/shells命令查看系统中安装的shell,不同的shell可能支持的命令语法是不相同的。

    一、shell种类

    操作系统内核(kernel)与shell是独立的套件,而且都可以被替换。不同的操作系统使用不同的shell;同一个kernel之上可以使用不同的shell。

    常见的shell分为两大主流:

    sh:

    • Bourne shell (sh), Solaris, hpux 默认shell
    • Bourne again shell (bash), Linux系统默认shell

    csh:

    • C shell(csh)
    • tc shell(tcsh)

    查看使用的shell

    echo $SHELL
    #/bin/bash

    shell环境定义 

    临时环境变量:所谓临时环境变量是指用户在当前登陆环境生效的变量。用户登录系统后,直接在命令行上定义的环境变量只能在当前的登录环境中使用。当退出系统后,环境变量将不能在下次登录时使用

    将环境变量永久生效:通过将环境变量定义写入到配置文件中,用户每次登录时系统自动定义,则无需再到命令行重新定义。定义环境变量的常见配置文件如下:

    /etc/profile 针对系统所有用户生效,此文件应用于所有用户每次登录系统时的环境变量定义

    $HOME_name/.bash_profile 针对特定用户生效,$HOME为用户的宿主目录,当用户登录系统后,首先继承/etc/profile文件中的定义,再应用$HOME/.bash_profile文件中的定义

    系统预定义的环境变量:系统环境变量对所有用户有效,如:$PATH、$HOME、$SHELL、$PWD等等,用echo命令打印上述的系统环境变量

    echo $PATH  #/opt/conda/bin:/usr/local/nvidia/bin:/usr/local/cuda/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
    echo $PWD
    #/workspace
    echo $SHELL
    #/bin/bash
    echo $HOME
    #/root

    shell脚本编程 

    同传统的编程语言一样,shell提供了很多特性,这些特性可以使得shell脚本编程更为有用。

    创建shell脚本

    • 首行:第一行内容在脚本的首行左侧,表示脚本将要调用的shell解释器,内容如下:#!/bin/bash,  #! 符号能够被内核识别是一个脚本的开始,这一行必须位于脚本的首行, /bin/bash 是bash程序的绝对路径,在这里表示后续的内容将通过bash程序解释执行。
    • 注释:注释符号 # 放在需注释内容的前面, 多行注释:需要注释多行代码:<<EOF    EOF将多行注释的内容嵌套在里面
    • 内容:可执行内容和shell结构

    shell脚本的权限

    一般情况下,默认创建的脚本是没有执行权限的。没有权限不能执行,需要赋予可执行权限。

    chmod +x test.sh

    shell脚本的执行 

    1.输入脚本的绝对路径或相对路径

    • /workspace/test.sh
    • ./test.sh

    2.bash或sh + 脚本(当脚本没有x权限时,root和文件所有者通过该方式可以正常执行)

    • bash test.sh
    • sh test.sh

    3. 在脚本的路径前加“.”或source

    • source /workspace/test.sh
    • . test.sh

    第一种和第二种会新开一个bash,不同bash中的变量无法共享。但是使用. ./test.sh 这种方式是在同一个shell里面执行的。

    二、shell变量

    变量:是shell传递数据的一种方式,用来代表每个取值的符号名。当shell脚本需要保存一些信息时,即将它存放在一个变量中。

    变量设置规则:

    • 变量名称可以由字母,数字和下划线组成,但是不能以数字开头,环境变量名建议大写,便于区分
    • 在bash中,变量的默认类型都是字符串型,如果要进行数值运算,则必须指定变量类型为数值型
    • 变量用等号连接,等号左右两侧不能有空格
    • 变量的值如果有空格,需要使用单引号或者双引号包括

    变量分类:

    Linux Shell中的变量分为用户自定义变量,环境变量,位置参数变量和预定义变量。可以通过set命令查看系统中存在的所有变量。

    • 系统变量:保存和系统操作环境相关的数据。$HOME, $PWD, $SHELL, $USER等等。
    • 位置参数变量:主要用来向脚本中传递参数或数据,变量名不能自定义,变量作用固定。
    • 预定义变量:是Bash中已经定义好的变量,变量名不能自定义,变量作用也是固定的。

    用户自定义变量

    用户自定义的变量由字母或下划线开头,由字母,数字或下划线序列组成,并且大小写字母意义不同,变量名长度没有限制。只读类型变量,使用readonly命令

    设置变量,习惯上用大写字母来命名变量。变量名以字母表示的字符开头,不能用数字。

    变量调用,在使用变量时,要在变量名前加上前缀"$"。使用echo命令查看变量值,eg: echo $A

    变量赋值

    • 定义时赋值:变量=值(等号两侧不能有空格)eg:STR="hello world"        A=9
    • 将一个命令的执行结果赋值给变量:
      • A=`ls -la`反引号,运行里面的命令,并把结果返回给变量A
      • A=$(ls -la)等价于反引号  eg:aa=$((4+5))    bb=`expr 4 + 5`
      • 将一个变量赋值给另一个变量  eg:A=$STR

    变量叠加

    aa=123
    echo $aa
    #123
    cc="$aa"456
    echo $cc
    #123456
    dd=${aa}789
    echo $dd
    #123789

    单引号和双引号的区别:

    现象:单引号里的内容会全部输出,而双引号里的内容会有变化

    原因:单引号会将所有特殊字符脱意 

    • 在对变量进行取值时,使用"#"符号对字符串进行取值
    • 提取子字符串,使用字符串的截取命令,用于提取部分字符串 str:k1:k2
    • 查找字符串,用于查找字符的位置,输出结果为字符在字符串中所占的数据位置。如果查找多个字符,哪个字母先出现即先计算哪个
    NUM=10
    SUM="$NUM hehe"
    echo $SUM
    #10 hehe
    SUM2='$NUM hehe'
    echo $SUM2
    #$NUM hehe
    string="abcd"
    echo ${#string}    #4
    string="this is a test"
    echo ${string:2:6}    #is is
    string="this is a test"
    echo `expr index "$string" "it"`    #1

    列出所有的变量, set

    删除变量,unset NAME(unset撤销变量,对于readonly B=2声明静态的变量B=2,不能unset)

    用户自定义的变量,作用域为当前的shell环境

    环境变量

    用户自定义变量只在当前的shell中生效,而环境变量会在当前shell和其子shell中生效,如果把环境变量写入相应的配置文件,那么这个环境变量就会在所有的shell中生效。

    export 变量名=变量值        申明变量

    预定义变量

    $?    执行上一个命令的返回值,执行成功,返回0, 执行失败,返回非0

    $$    当前进程的进程号(PID),即当前脚本执行时生成的进程号

    $!    后台运行的最后一个进程的进程号(PID),最近一个被放入后台执行的进程

    expr命令:四则运算和字符串运算

    expr的字符串运算能力

    • match  match STRING REGEXP STRING中匹配REGEXP字符串并返回匹配字符串的长度
    • substr  substr STRING POS LENGTH 从POS位置获取长度为LENGTH的字符串
    • index  index STRING SUBSTR 查找子字符串的起始位置
    • length  length STRING 计算字符串的长度

    三、shell数组

    在bash下,仅仅支持一维数组,并且没有限定数组的大小,不支持多维数组。类似于C语言,数组元素的下标由0开始编号。获取数组中的元素要利用下标,下标可以是整数或者算术表达式,其值应当大于或等于0。

    定义数组:在shell中,用()来定义数组,数组中元素用"空格"符号分割开。定义数组一般形式为:

    数组的三种定义形式;读取数组和读取变量名相同,使用$符号;获取数组长度的方法与获取字符串长度的方法相同。

    #!/bin/bash
    
    array_name=(value1 value2 value3 value4)
    array_test=(
    value1
    value2
    value3
    value4
    )
    array_text[0]=value0
    array_text[1]=value1
    array_text[3]=value3
    
    valuen=${array_name[2]}
    echo $valuen    #输出    value3
    
    echo ${array_name[n]}    #输出    value1
    echo ${array_name[@]}    #输出    value1 value2 value3 value4
    
    length=${#array_name[@]}
    echo $length    #输出    4
    length=${#array_name[*]}
    echo $length    #输出    4
    length=${#array_name[0]}
    echo $length    #输出    6

    四、shell传递参数 

    在执行shell脚本时,向脚本传递参数,脚本内获取参数的格式为:$n。n代表一个数字,1为执行脚本的第一个参数,2为执行脚本的第二个参数,以此类推……

    在使用shell传递参数时,需要用到以下的几个字符来处理参数 

    • $#:传递到脚本的参数个数
    • $$:脚本运行的当前进程ID号
    • $!:后台运行的最后一个进程的ID号
    • $?:显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误
    • $*:以一个单字符串显示所有向脚本传递的参数
    • $@:与*相同,添加引号,在引号中返回每个参数
    #!/bin/bash
    echo "传递参数实例!";
    echo "执行的文件名:$0";
    echo "第一个参数为:$1";
    echo "第二个参数为:$2";
    echo "第三个参数为:$3";
    
    echo "参数个数为:$#";
    echo "脚本运行的进程ID号:$$";
    echo "后台运行的最后一个进程的ID号:$!";
    echo "显示最后命令的退出状态:$?";
    
    echo "输出向脚本传递的参数:$*"
    echo "输出向脚本传递的参数:$@"
    
    #执行 bash test.sh 1 2 3
    
    #输出
    传递参数实例!
    执行的文件名:test.sh
    第一个参数为:1
    第二个参数为:2
    第三个参数为:3
    参数个数为:3
    脚本运行的进程ID号:24610
    后台运行的最后一个进程的ID号:
    显示最后命令的退出状态:0
    输出向脚本传递的参数:1 2 3
    输出向脚本传递的参数:1 2 3

    五、shell运算符

    shell运算符种类,shell同样支持多种运算符

    • 算数运算符
    • 关系运算符
    • 布尔运算符
    • 逻辑运算符
    • 字符串运算符
    • 文件测试运算符

    shell想要使用这些运算符,需要结合其他命令和工具来使用,使用算术运算符需要搭配的常用两种工具是:awk、expr

    • 表达式和运算符之间必须要用空格(必须写成3 + 2)        
    • 完整的表达式要被两个"`"包含

    运算符和数之间必须用空格隔开

    算数运算符

    +        -        *        /        %        =        ==        !=

            备注:算数运算符中的乘号(*)前面必须加反斜杠才能实现乘法运算

    关系运算符

    shell中使用特殊的字符表示关系运算符,并且只支持数字,不支持字符串,除非字符串是数字

    -eq        -ne        -gt        -lt        -ge        -le

    布尔运算符

    ! (非运算)       -o (或运算)       -a(与运算)

    逻辑运算符

    &&(逻辑中的AND)        ||(逻辑中的OR)

    此处使用两层的[]符号,将两次关系运算的结果保存在条件句中

    字符串运算符

    =        !=        -z        ​​​​​​​-n        $(检测字符串是否为空)

    文件测试运算符

    shell中的文件测试运算符用于检测在类unix系统中,文件的各种属性

    #!/bin/bash
    
    val=`expr 3 + 2`
    echo "两个数和为:$val" #两个数和为:5
    
    a=10
    b=20
    
    if [ $a -eq $b ]
    then
        echo "$a -eq $b : a 等于 b"
    else
        echo "$a -eq $b :a 不等于 b"
    fi
    #10 -eq 20 :a 不等于 b
    
    if [ $a -ne $b ]
    then
        echo "$a -ne $b : a 不等于 b"
    else
        echo "$a -ne $b : a 等于 b"
    fi
    #10 -ne 20 : a 不等于 b
    
    a=10
    b=20
    if [ $a -eq 10 -o $b -eq 20 ]
    then
        echo "TRUE"
    else
        echo "FALSE"
    fi
    #TRUE
    
    if [[ $a -lt 100 && $b -gt 100 ]]
    then
        echo "返回 true"
    else
        echo "返回 false"
    fi
    #返回 false
    
    a="abc"
    b="efg"
    if [ $a != $b ]
    then
        echo "$a != $b : a 不等于 b"
    else
        echo "$a != $b : a 等于 b"
    fi
    #abc != efg : a 不等于 b
    
    file="./test.sh"
    if [ -r $file ]
    then
        echo "文件可读"
    else
        echo "文件不可读"
    fi
    #文件可读

    六、 shell编程中的命令

    echo命令(echo命令在shell中用于字符串的输出,调用的格式:echo string)

    >        结果定向重定向至文件

    -e        表示开启转义

    #!/bin/bash
    echo "this is a test"
    echo \"this is a test\"
    name="ohuohuo"
    echo "your name is $name"
    echo -e "Right! \n" # -e 表示开启转义
    echo "this is other line"
    echo "this is a test" > testfile
    echo `date`
    #执行命令
    bash test.sh
    #输出:
    this is a test
    "this is a test"
    your name is ohuohuo
    Right!
    
    this is other line
    Mon 18 Oct 2021 10:06:50 PM HKT

    printf命令 (shell中的printf命令如同C语言中的一样,不过不会自动调用换行符号,调用的格式:printf format-string [arguments...](format-string格式控制字符串, arguments参数列表))

    printf命令可以使用较为强大的转义字符

    echo "Hello, Shell"
    #输出:Hello, Shell
    printf "Hello, Shell\n"
    #输出:Hello, Shell 

    test命令

    shell中的test命令用于检查某个条件是否成立,可以进行数值、字符和文件三个方面的测试

    数值测试命令表

    参数说明
    -eq(equal)等于则为真
    -ne(no equal)不等于则为真
    -gt(great than)大于则为真
    -ge(great and equal)大于等于则为真
    -lt(low than)小于则为真
    -le(low and equal)小于等于则为真
    #!/bin/bash
    
    num1=100
    num2=100
    if test $[num1] -eq $[num2]
    then
        echo '两个数相等!'
    else
        echo '两个数不相等!'
    fi
    #输出:两个数相等!

    字符串测试表 

    参数说明
    =等于则为真
    !=不相等则为真
    -z 字符串字符串长度为零则为真
    -n 字符串字符串长度bu'wei'l
    num1="name"
    num2="function"
    if test $num1 = $num2
    then
        echo '两个字符串相等!'
    else
        echo '两个字符串不相等!'
    fi
    #输出:两个字符串不相等!

     文件测试表

    参数说明
    -e 文件名如果文件存在则为真
    -r 文件名如果文件存在且可读则为真
    -w 文件名如果文件存在且可写则为真
    -x 文件名如果文件存在且可执行则为真
    -s 文件名如果文件存在且至少有一个字符则为真
    -d 文件名如果文件存在且为目录则为真
    -f 文件名如果文件存在且为普通文件则为真
    -c 文件名如果文件存在且为字符型特殊文件则为真
    -b 文件名如果文件存在且为块特殊文件则为真
    #!/bin/bash
    if test -e ./test.sh
    then
        echo '文件已存在!'
    else
        echo '文件不存在!'
    fi
    #输出:文件已存在!

     七、shell流程控制

    shell作为一种脚本语言,有着自己的流程控制,而shell中的流程控制主要由条件、循环组成。

    if else条件

    条件模板为 if - then - elif - then - else - fi

    #!/bin/bash
    num1=$[6]
    num2=$[8]
    if test $[num1] -eq $[num2]
    then
        echo "两个数字相等"
    else
        echo "两个数字不相等"
    fi
    #两个数字不相等

    case条件

    • 取值后面需要加上in
    • 每一模式必须以右括号结束
    • 每个模式结束后使用;;符号结尾
    • 如果没有找到对应的模式。以*结尾,并跳出case
    • case需要搭配esac结尾,与C语言中的switch … case语句类似

    case中想要跳出循环有两个命令:break和continue

    break命令:允许跳出所有循环(中止执行后面所有的循环)

    continue命令:不会跳出所有循环,仅仅跳出当前循环,与其他类型的语言相同

    #!/bin/bash
    echo '输入1到4之间的数字:'
    echo '你输入的数字为:'
    read num
    case $num in
        1)  echo '你选择了1'
        ;;
        2)  echo '你选择了2'
        ;;
        3)  echo '你选择了3'
        ;;
        4)  echo '你选择了4'
        ;;
        *)  echo '你没有输入1-4之间的数字'
        ;;
    esac
    #输出:
    输入1到4之间的数字:
    你输入的数字为:
    3
    你选择了3
    
    while :
    do
        echo "输入1-4之间的数字:"
        read num
        case $num in
            1|2|3|4) echo "你输入的数字为 $num !"
            ;;
            5) echo "你输入的数字是5"
                continue
                echo "游戏结束"
            ;;
            *) echo "你输入的数字不是1-5之间的!游戏结束"
                break
            ;;
        esac
    done
    #输出
    输入1-4之间的数字:
    5
    你输入的数字是5
    输入1-4之间的数字:
    3
    你输入的数字为 3 !
    输入1-4之间的数字:
    6
    你输入的数字不是1-5之间的!游戏结束

    for循环 

    条件模板 for var in item1 item2 ... itemN -- do command1 -- done

    while循环

    条件模板 while condition -- do command -- done

    until循环

    条件模板 until condition -- do command -- done

    for num in 1 2 3 4 5
    do
        echo "The value is : $num"
    done
    #输出:
    The value is : 1
    The value is : 2
    The value is : 3
    The value is : 4
    The value is : 5
    
    num=1
    while(( $num <= 5 ))
    do
        echo $num
        let "num++"
    done
    #输出:
    1
    2
    3
    4
    5
    
    a=0
    until [ ! $a -lt 5 ]
    do
        echo $a
        a=`expr $a + 1`
    done
    #输出
    0
    1
    2
    3
    4

    八、shell函数

    Linux中的shell同样可以定义函数,然后在函数中调用执行相关的shell命令,完成功能。

    所有的函数在使用前必须定义,因为shell解释器是顺序逐层执行的,当shell解释器发现定义的函数时,才会找到对应的功能,进而执行。

    [function] funname[()]
    {
        action;
        [return int;]
    }
    function fun()表示有返回参数的函数
    fun()表示无返回参数的函数
    使用return可以返回参数值,如果不使用,将默认以最后一条命令运行的结果作为返回值
    #!/bin/bash
    
    FunReturn(){
        echo "两个数字进行相加运算..."
        echo "输入第一个数字:"
        read num
        echo "输入第二个数字:"
        read anothernum
        echo "两个数字分别为 $num 和 $anothernum "
        return $(( $num + $anothernum ))    #分别返回数值
    }
    
    FunReturn   #调用函数
    echo "输入的两个数字之和为 $? !"    #使用通配符获取上一条指令的返回值
    #输出
    两个数字进行相加运算...
    输入第一个数字:
    3
    输入第二个数字:
    4
    两个数字分别为 3 和 4
    输入的两个数字之和为 7 !

    九、shell重定向 

    Linux命令中的shell重定向

    Python脚本编写

    python的sys、os、time模块的使用

    sys模块

    1. sys.argv:实现从程序外部向程序传递参数。

    位置参数argv[0]代表py文件本身, 运行方法python test.py 参数1, 参数2

    # test.py
    import sys
    if __name__ == "__main__":
        self = sys.argv[0]
        name = sys.argv[1]
        age = sys.argv[2]
        print(self, name, age)
    # 运行程序
    python test.py xiaoming 18
    

    2. sys.getdefaultencoding():获取系统当前编码,一般默认为ascii。

    print(sys.getdefaultencoding())

    3. sys.path:获取指定模块搜索路径的字符串集合

    print(sys.path)

    4.sys.platform:获得当前系统平台

    print(sys.platform)

    5.sys.exit():执行到主程序末尾,解释器自动退出,但是如果需要中途退出程序,可以调用sys.exit()函数,带有一个可选的整数参数返回给调用它的程序, 表示在主程序中捕获对sys.exit()的调用 

    import os
    if __name__ == "__main__":
        for i in range(1, 10):
            print("第%s次:"%i)
            if i == 5:
                print("第五次退出")
                sys.exit(0)

    os模块

    1.os.name: 判断现在正在使用的平台,Windows返回'nt', Linux返回’posix‘

    print(os.name)    #posix

    2.os.getcwd():得到当前工作的目录

    print(os.getcwd())    #/workspace/CCF_2021/question_matching

     3. os.listdir():指定所有目录下所有的文件和目录名

    print(os.listdir('.'))

    4. os.remove():删除指定文件

    os.remove('test.txt')

    5.os.rmdir():删除指定目录(不能够嵌套删除目录)

    os.rmdir('test')

    6.os.mkdir():创建目录(该方法只能建立一层目录,递归建立使用os.makedirs())

    os.mkdir('test')
    os.makedirs('test/test')

    7.os.path.isfile():判断指定对象是否为文件。是则返回True, 否则False

    print(os.path.isfile('test.py'))

    8.os.path.isdir():判断指定对象是否为目录。是则返回True, 否则False

    print(os.path.isdir('test'))

    9.os.path.exists():判断指定对象是否存在。是则返回True,否则False(判断文件夹或者文件等是否存在)

    os.path.exists(test)

     10.os.path.split():返回路径的目录和文件名

    os.path.split('/workspace/CCF_BDCI2021/question_matching/data')
    #输出:('/workspace/CCF_BDCI2021/question_matching', 'data')

    11.os.getcwd():获得当前工作的目录

    print(os.getcwd())

    12.os.system():执行shell命令

    var = 123
    os.environ['var'] = str(var)    #注意此处[]内的是“字符串”
    os.system('echo $var')
    #输出:
    123
    0

    13.os.chdir():用于改变当前工作目录到指定的目录(将工作目录改到指定目录)

    print(os.getcwd())
    #输出:/workspace/CCF_BDCI2021/question_matching/test
    os.chdir('/workspace')
    print(os.getcwd())
    #输出:/workspace

    14.os.path.getsize():获得文件的大小

    print(os.path.getsize('test.py'))

    15.os.path.abspath('.'):获得绝对路径

    print(os.path.abspath('.'))
    #输出:/workspace/CCF_BDCI2021/question_matching

    16.os.path.join(path, name):连接目录和文件名

    os.path.join('/workspace/CCF_BDCI2021/question_matching', 'file')
    #输出:'/workspace/CCF_BDCI2021/question_matching/file'

    17.os.path.realpath():获得文件所在的目录

    import os
    import sys
    if __name__ == "__main__":
        print(sys.argv[0])    #文件的名字
        print(os.path.realpath(sys.argv[0]))    #文件的路径
        print(os.path.split(os.path.realpath(sys.argv[0])))    #将文件的路径和文件名分割开
        print(os.path.split(os.path.realpath(sys.argv[0]))[0])    #输出文件的路径
    
    
    #输出:
    test.py
    /workspace/CCF_BDCI2021/question_matching/test.py
    ('/workspace/CCF_BDCI2021/question_matching', 'test.py')
    /workspace/CCF_BDCI2021/question_matching

    18.os.path.basename():获得路径中文件名        os.path.dirname():获得文件路径名

    print(os.path.basename('/workspace/CCF_BDCI2021/question_matching/test.py'))
    #输出:test.py
    print(os.path.dirname('/workspace/CCF_BDCI2021/question_matching/test.py'))
    #输出:/workspace/CCF_BDCI2021/question_matching

    time模块

    获取时间

    import time
    
    ticks = time.time()
    print(ticks)    
    
    localtime = time.localtime(time.time())
    print(localtime)    
    
    localtime = time.asctime(time.localtime(time.time()))
    print(localtime)
    
    #1634397810.7200205
    #time.struct_time(tm_year=2021, tm_mon=10, tm_mday=16, tm_hour=23, tm_min=23, tm_sec=55, tm_wday=5, tm_yday=289, tm_isdst=0)
    #Sat Oct 16 23:24:41 2021

    格式化日期

    import time
    
    print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
    print(time.strftime("%a %b %d %H:%M:%S %Y", time.localtime()))
    
    import calendar
    cal = calendar.month(2021, 10)
    print(cal)
    
    
    #输出
    2021-10-16 23:39:59
    Sat Oct 16 23:40:51 2021
        October 2021
    Mo Tu We Th Fr Sa Su
                 1  2  3
     4  5  6  7  8  9 10
    11 12 13 14 15 16 17
    18 19 20 21 22 23 24
    25 26 27 28 29 30 31
    

    python脚本编写实际操作

    sys.stdout.write()将str写到输出流(只能输出一个str, 原封不动输出, 不会默认添加'\n')

    sys.stdout.flush()的作用是显示地让缓冲区中的内容输出(如果缓冲区的内容新增了换行符, 那么stdout就会自动将缓冲区内的内容输出)

    python中执行shell命令

    • 使用os.system()命令, os.system('cat /proc/cpuinfo')
    • 使用os.popen()命令,output = os.popen('cat /proc/cpuinfo')        print(output.read()),通过os.popen()返回的是file read的对象, 对其进行读取read()的操作可以看到执行的输出,但是无法读取程序执行的返回值。

    展开全文
  • 涉及的内容都是编写python运维脚本常用的一些知识点及Demo 理解不足小伙伴帮忙指正 生命完美的答案,无非走过没有遗憾 —《天蓝》 脚本编程与系统管理 解析命令行选项 如何能够解析脚本运行命令行选项(位于 sys....

    写在前面

    • 对于自动化运维来讲Python是一个利器
    • 常用的自动化运维工具Ansible就是通过python编写
    • 博文为《Python Cookbook》读书笔记整理而来
    • 涉及的内容都是编写python运维脚本常用的一些知识点及Demo
    • 理解不足小伙伴帮忙指正

    生命完美的答案,无非走过没有遗憾 —《天蓝》


    脚本编程与系统管理

    解析命令行选项

    如何能够解析脚本运行命令行选项(位于 sys.argv 中)

    argparse 模块可被用来解析命令行选项

    常用来定义一个脚本的说明文档,一般我们写python脚本会通过if..else 的方式来提供一个脚本说明文档,python不支持switch。所有很麻烦,其实,我们可以通过argparse来编写说明文档。

    我们来看看执行一个python脚本

    对于熟悉Linux的小伙伴下面的文档在熟悉不过了,这个一个标准Linxu软件包的说明文档,文档中定义是软件包的说明

    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$./demo.py -h
    usage: demo.py [-h] -p pattern [-v] [-o OUTFILE] [--speed {slow,fast}]
                   [filename [filename ...]]
    
    Search some files
    
    positional arguments:
      filename
    
    optional arguments:
      -h, --help            show this help message and exit
      -p pattern, --pat pattern
                            text pattern to search for
      -v                    verbose mode
      -o OUTFILE            output file
      --speed {slow,fast}   search speed
    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$
    

    来看看这个脚本是如何编写的

    #!/usr/bin/env python3
    
    
    import argparse
    # 脚本的描述
    parser = argparse.ArgumentParser(description='Search some files')
    # 脚本接收的全部参数,用`filenames`接收
    parser.add_argument(dest='filenames', metavar='filename', nargs='*')
    
    # 脚本接收
    parser.add_argument('-p', '--pat', metavar='pattern', required=True,
                        dest='patterns', action='append',
                        help='text pattern to search for')
    parser.add_argument('-v', dest='verbose', action='store_true',
                        help='verbose mode')
    parser.add_argument('-o', dest='outfile', action='store',
                        help='output file')
    parser.add_argument('--speed', dest='speed', action='store',
                        choices={'slow', 'fast'}, default='slow',
                        help='search speed')
    args = parser.parse_args()
    # Output the collected arguments
    print(args.filenames)
    print(args.patterns)
    print(args.verbose)
    print(args.outfile)
    print(args.speed)
    
    

    为了解析命令行选项, 首先要创建一个ArgumentParser实例, 并使用add_argument() 方法声明你想要支持的选项。在每个add-argument()调用中:

    dest参数指定解析结果被指派给属性的名字。 metavar 参数被用来生成帮助信息。

    action 参数指定跟属性对应的处理逻辑,通常的值为 store , 被用来存储某个值或将多个参数值收集到一个列表中

    nargs 参数收集所有剩余的命令行参数到一个列表中。在本例中它被用来构造一个文件名列表

    parser.add_argument(dest='filenames',metavar='filename', nargs='*')
    
    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$python3 demo.py  -p spam --pat=eggs  foo.txt bar.txt
    ['foo.txt', 'bar.txt']
    ['spam', 'eggs']
    False
    None
    slow
    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$
    

    action='store_true' 根据参数是否存在来设置一个 Boolean 标志:

    parser.add_argument('-v', dest='verbose', action='store_true', help='verbose mode')
    
    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$python3 demo.py -v -p spam --pat=eggs foo.txt bar.txt
    ['foo.txt', 'bar.txt']
    ['spam', 'eggs']
    True
    None
    slow
    

    action='store' 参数接受一个单独值并将其存储为一个字符串

    parser.add_argument('-o', dest='outfile', action='store', help='output file')
    
    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$python3 demo.py -v -p spam --pat=eggs -o liruilong  foo.txt bar.txt
    ['foo.txt', 'bar.txt']
    ['spam', 'eggs']
    True
    liruilong
    slow
    
    • action='append' 参数说明允许某个参数重复出现多次,并将它们追加到一个列表中去。
    • required 标志表示该参数至少要有一个-p --pat 表示两个参数名形式都可使用。
    parser.add_argument('-p', '--pat', metavar='pattern', required=True,
                        dest='patterns', action='append',
                        help='text pattern to search for')
    
    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$python3 demo.py  -p spam   foo.txt bar.txt
    ['foo.txt', 'bar.txt']
    ['spam']
    False
    None
    slow
    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$python3 demo.py  --pat=eggs  foo.txt bar.txt
    ['foo.txt', 'bar.txt']
    ['eggs']
    False
    None
    slow
    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$python3 demo.py  -p spam --pat=eggs  foo.txt bar.txt
    ['foo.txt', 'bar.txt']
    ['spam', 'eggs']
    False
    None
    slow
    

    如果一个都没有,会提示缺少参数 -p/--pat

    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$python3 demo.py   foo.txt bar.txt
    usage: demo.py [-h] -p pattern [-v] [-o OUTFILE] [--speed {fast,slow}]
                   [filename [filename ...]]
    demo.py: error: the following arguments are required: -p/--pat
    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$
    

    choices={'slow', 'fast'}, 参数说明接受一个值,但是会将其和可能的选择值做比较,以检测其合法性:

    parser.add_argument('--speed', dest='speed', action='store',
                        choices={'slow', 'fast'}, default='slow',
                        help='search speed')
    
    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$python3 demo.py  --pat=eggs --speed 123  foo.txt bar.txt
    usage: demo.py [-h] -p pattern [-v] [-o OUTFILE] [--speed {slow,fast}]
                   [filename [filename ...]]
    demo.py: error: argument --speed: invalid choice: '123' (choose from 'slow', 'fast')
    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$python3 demo.py  --pat=eggs --speed fast  foo.txt bar.txt
    ['foo.txt', 'bar.txt']
    ['eggs']
    False
    None
    fast
    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$
    

    一旦参数选项被指定,你就可以执行parser.parse()方法了。它会处理sys.argv的值并返回一个结果实例。每个参数值会被设置成该实例中add_argument()方法的 dest 参数指定的属性值。

    还很多种其他方法解析命令行选项。可以会手动的处理 sys.argv 或者使用 getopt 模块。但是,如果你采用本节的方式,将会减少很多冗余代码,底层细节argparse 模块已经帮你处理了。你可能还会碰到使用optparse库解析选项的代码。尽管 optparse 和 argparse 很像,但是后者更先进,因此在新的程序中你应该使用它。

    运行时弹出密码输入提示

    你写了个脚本,运行时需要一个密码。此脚本是交互式的,因此不能将密码在脚本中硬编码,而是需要弹出一个密码输入提示,让用户自己输入。

    Python 的 getpass 模块正是你所需要的。你可以让你很轻松的弹出密码输入提示,并且不会在用户终端回显密码。

    #!/usr/bin/env python3
    # -*- encoding: utf-8 -*-
    
    import getpass
    
    def svc_login(user, passwd):
        return user == passwd
    
    user = getpass.getuser()
    passwd = getpass.getpass()
    if svc_login(user, passwd):
        print('Yay!')
    else:
        print('Boo!')
    

    代码中getpass.getuser()不会弹出用户名的输入提示。它会根据该用户的 shell 环境或者会依据本地系统的密码库(支持 pwd 模块的平台)来使用当前用户的登录名

    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$./pass.py
    Password: #root
    Yay!
    

    通过重定向/管道/文件接受输入

    在bash中编写pytohn脚本接收外部数据的方式,一般情况下,对于一般变量,我们用命令行变量的方式比较多(手动的处理 sys.argv ),对于文件内容或者bash命令输出直接通过脚本内部获取需要的数据。

    其实python 脚本也可以用其他方式来接收 传递给他的文件数据或者bash命令输出,包括将命令行的输出通过管道传递给该脚本、重定向文件到该脚本,或在命令行中传递一个文件名文件名列表给该脚本。

    这里通过 Python 内置的 fileinput 模块,可以实现重定向,管道,文佳输出的方式传递数据到脚本内部

    #!/usr/bin/env python3
    # -*- encoding: utf-8 -*-
    """
    @File    :   filein.py
    @Time    :   2022/05/01 06:05:43
    @Author  :   Li Ruilong
    @Version :   1.0
    @Contact :   1224965096@qq.com
    @Desc    :   None
    """
    
    # here put the import lib
    
    import fileinput
    with fileinput.input() as f_input:
        for line in f_input:
            print("脚本输出", line, end='')
    
    

    使用fileinput.input()方法可以获取当前输入脚本的数据,脚本里面用一个FileInput迭代器接收

    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$vim filein.py
    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$chmod +x filein.py
    

    文件直接接收

    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$./filein.py /etc/passwd
    脚本输出 root:x:0:0:root:/root:/bin/bash
    脚本输出 bin:x:1:1:bin:/bin:/sbin/nologin
    脚本输出 daemon:x:2:2:daemon:/sbin:/sbin/nol
    。。。。
    

    重定向接收

    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$./filein.py <  /etc/passwd
    脚本输出 root:x:0:0:root:/root:/bin/bash
    脚本输出 bin:x:1:1:bin:/bin:/sbin/nologin
    。。。。。。
    

    管道方式接收

    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$df -h
    文件系统        容量  已用  可用 已用% 挂载点
    /dev/sda1       150G   22G  129G   15% /
    devtmpfs        983M     0  983M    0% /dev
    tmpfs           993M     0  993M    0% /dev/shm
    tmpfs           993M   17M  976M    2% /run
    tmpfs           993M     0  993M    0% /sys/fs/cgroup
    overlay         150G   22G  129G   15% /var/lib/docker/overlay2/9fbd33d3485f02eadef6907a5b4eaead4a384684b66c572d822a2942a82ca0d5/merged
    overlay         150G   22G  129G   15% /var/lib/docker/overlay2/85ff22ccaf2db68a0a863bc404d79d72fa6c8744424f50ba8fb6bfa83d56b56a/merged
    tmpfs           199M     0  199M    0% /run/user/0
    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$df -h |  ./filein.py
    脚本输出 文件系统        容量  已用  可用 已用% 挂载点
    脚本输出 /dev/sda1       150G   22G  129G   15% /
    脚本输出 devtmpfs        983M     0  983M    0% /dev
    脚本输出 tmpfs           993M     0  993M    0% /dev/shm
    脚本输出 tmpfs           993M   17M  976M    2% /run
    脚本输出 tmpfs           993M     0  993M    0% /sys/fs/cgroup
    脚本输出 overlay         150G   22G  129G   15% /var/lib/docker/overlay2/9fbd33d3485f02eadef6907a5b4eaead4a384684b66c572d822a2942a82ca0d5/merged
    脚本输出 overlay         150G   22G  129G   15% /var/lib/docker/overlay2/85ff22ccaf2db68a0a863bc404d79d72fa6c8744424f50ba8fb6bfa83d56b56a/merged
    脚本输出 tmpfs           199M     0  199M    0% /run/user/0
    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$
    

    fileinput.input() 创建并返回一个FileInput类的实例,该实例可以被当做一个上下文管理器使用。因此,整合起来,如果我们要写一个打印多个文件输出的脚本,那么我们需要在输出中包含文件名和行号

    >>> import fileinput
    >>> with fileinput.input("/etc/passwd") as f:
    ...     for line in f:
    ...             print(f.filename(),f.fileno(),f.lineno(),line,end='')
    ...
    /etc/passwd 3 1 root:x:0:0:root:/root:/bin/bash
    /etc/passwd 3 2 bin:x:1:1:bin:/bin:/sbin/nologin
    /etc/passwd 3 3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
    /etc/passwd 3 4 adm:x:3:4:adm:/var/adm:/sbin/nologin
    /etc/passwd 3 5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
    /etc/passwd 3 6 sync:x:5:0:sync:/sbin:/bin/sync
    

    执行外部命令并获取它的输出

    你想执行一个外部命令并以 Python 字符串的形式获取执行结果。

    使用subprocess.check_output()函数。

    #!/usr/bin/env python3
    # -*- encoding: utf-8 -*-
    
    import subprocess
    out_bytes = subprocess.check_output(['netstat','-a'])
    out_text = out_bytes.decode('utf-8')
    print(out_text)
    
    
    

    执行下试试

    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$./py_sh.py
    Active Internet connections (servers and established)
    Proto Recv-Q Send-Q Local Address           Foreign Address         State
    tcp        0      0 localhost:2379          0.0.0.0:*               LISTEN
    tcp        0      0 vms55.rhce.cc:2379      0.0.0.0:*               LISTEN
    tcp        0      0 localhost:2380          0.0.0.0:*               LISTEN
    tcp        0      0 vms55.rhce.cc:2380      0.0.0.0:*               LISTEN
    tcp        0      0 0.0.0.0:webcache        0.0.0.0:*               LISTEN
    tcp        0      0 0.0.0.0:http            0.0.0.0:*               LISTEN
    

    如果被执行的命令以非零码返回,就会抛出异常。下面的例子捕获到错误并获取返回码:

    try:
        out_bytes = subprocess.check_output(['cmd','arg1','arg2'])
    except subprocess.CalledProcessError as e:
        out_bytes = e.output # Output generated before error
        code = e.returncode # Return code
    

    默认情况下,check_output() 仅仅返回输入到标准输出的值。如果你需要同时收集标准输出和错误输出,使用stderr参数:

    out_bytes = subprocess.check_output(['cmd','arg1','arg2'],stderr=subprocess.STDOUT)
    

    如果你需要用一个超时机制来执行命令,使用 timeout 参数:

    try:
        out_bytes = subprocess.check_output(['cmd','arg1','arg2'], timeout=5)
    except subprocess.TimeoutExpired as e:
        ....
    

    通常来讲,命令的执行不需要使用到底层 shell 环境(比如 sh、bash)。一个字符串列表会被传递给一个低级系统命令,比如 os.execve()

    如果你想让命令被一个shell 执行,传递一个字符串参数,并设置参数 shell=True . 有时候你想要Python去执行一个复杂的 shell 命令的时候这个就很有用了,比如管道流、I/O 重定向和其他特性。例如:

    out_bytes = subprocess.check_output('grep python | wc > out', shell=True)
    

    是在 shell 中执行命令会存在一定的安全风险,特别是当参数来自于用户输入时。这时候可以使用 shlex.quote() 函数来将参数正确的用双引用引起来。

    使用 check_output() 函数是执行外部命令并获取其返回值的最简单方式。但是,如果你需要对子进程做更复杂的交互,比如给它发送输入,你得采用另外一种方法。这时候可直接使用subprocess.Popen类。

    #!/usr/bin/env python3
    # -*- encoding: utf-8 -*-
    
    import subprocess
    # Some text to send
    text = b'''
    hello world
    this is a test
    goodbye
    '''
    # Launch a command with pipes
    p = subprocess.Popen(['wc'],
                         stdout=subprocess.PIPE,
                         stdin=subprocess.PIPE)
    # Send the data and get the output
    stdout, stderr = p.communicate(text)
    # To interpret as text, decode
    out = stdout.decode('utf-8')
    err = stderr.decode('utf-8')
    

    关于子进程,简单来看下

    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$(pwd;echo $BASH_SUBSHELL;ps --forest)
    /root/python_demo
    1
       PID TTY          TIME CMD
      9324 pts/0    00:00:00 bash
     49906 pts/0    00:00:00  \_ bash
     49907 pts/0    00:00:00      \_ ps
    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$pwd;echo $BASH_SUBSHELL;ps --forest
    /root/python_demo
    0
       PID TTY          TIME CMD
      9324 pts/0    00:00:00 bash
     49908 pts/0    00:00:00  \_ ps
    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$
    

    也可以进程列表同协程结合的方式。你既可以在子shell中 进行繁重的处理工作,同时也不会让子shell的I/O受制于终端。

    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$coproc (sleep 10;ps --forest;sleep 10;ps --forest)
    [1] 50326
    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$jobs
    [1]+  运行中               coproc COPROC ( sleep 10; ps --forest; sleep 10; ps --forest ) &
    

    如果直接丢到后台会自动在终端输出IO

    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$( sleep 10; ps --forest; sleep 10; ps --forest ) &
    [1] 50335
    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$ps --forest
       PID TTY          TIME CMD
      9324 pts/0    00:00:00 bash
     50335 pts/0    00:00:00  \_ bash
     50336 pts/0    00:00:00  |   \_ sleep
     50337 pts/0    00:00:00  \_ ps
    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$   PID TTY          TIME CMD
      9324 pts/0    00:00:00 bash
     50335 pts/0    00:00:00  \_ bash
     50340 pts/0    00:00:00      \_ ps
    
    [1]+  完成                  ( sleep 10; ps --forest; sleep 10; ps --forest )
    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$
    

    subprocess 模块对于依赖 TTY 的外部命令不合适用。例如,你不能使用它来自动化一个用户输入密码的任务(比如一个 ssh 会话)。这时候,你需要使用到第三方模块了,比如基于著名的 expect 家族的工具(pexpect 或类似的)(pexpect可以理解为Linux下的expect的Python封装、通过pexpect可以实现对ssh、ftp、passwd、telnet等命令行进行自动交互,而无需人工干涉来达到自动化的目的。比如我们可以模拟一个FTP登录时所有交互,包括输入主机地址、用户名、密码、上传文件等,待出现异常还可以进行尝试自动处理。)

    终止程序并给出错误信息

    你想向标准错误打印一条消息并返回某个非零状态码来终止程序运行

    通过 pythonraise SystemExit(3)命令可以主动抛出一个错误,通过sys.stderr.write将命令写到标准的输出端

    #!/usr/bin/env python3
    
    import sys
    sys.stderr.write('It failed!\n')
    raise  SystemExit(3)
    
    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$vim err.py
    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$./err.py
    It failed!
    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$echo $?
    3
    

    直接将消息作为参数传给SystemExit(),那么你可以省略其他步骤

    #!/usr/bin/env python3
    
    raise SystemExit('It failed!')
    

    抛出一个 SystemExit 异常,使用错误消息作为参数,它会将消息在sys.stderr中打印,然后程序以状态码1退出

    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$./err.py
    It failed!
    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$echo $?
    1
    

    获取终端的大小

    你需要知道当前终端的大小以便正确的格式化输出。

    使用 os.get terminal size() 函数来做到这一点。

    #!/usr/bin/env python3
    # -*- encoding: utf-8 -*-
    
    import os
    sz = os.get_terminal_size()
    print(sz)
    print(sz.columns)
    print(sz.lines)
    
    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$./tim.py
    os.terminal_size(columns=99, lines=30)
    99
    30
    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$./tim.py
    os.terminal_size(columns=165, lines=30)
    165
    30
    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$
    

    复制或者移动文件和目录

    复制或移动文件和目录,但是又不想调用 shell 命令。

    shutil 模块有很多便捷的函数可以复制文件和目录。使用起来非常简单

    #!/usr/bin/env python3
    # -*- encoding: utf-8 -*-
    
    import shutil
    # Copy src to dst. (cp src dst)
    shutil.copy(src, dst)
    # Copy files, but preserve metadata (cp -p src dst)
    shutil.copy2(src, dst)
    # Copy directory tree (cp -R src dst)
    shutil.copytree(src, dst)
    # Move src to dst (mv src dst)
    shutil.move(src, dst)
    
    

    这里不多讲,熟悉Linux的小伙伴应该不陌生。

    默认情况下,对于符号链接这些命令处理的是它指向的东西文件。例如,如果源文件是一个符号链接,那么目标文件将会是符号链接指向的文件。如果你只想复制符号链接本身,那么需要指定关键字参数 follow_symlinks

    shutil.copytree(src, dst, symlinks=True)
    

    copytree() 可以让你在复制过程中选择性的忽略某些文件或目录。你可以提供一个忽略函数,接受一个目录名和文件名列表作为输入,返回一个忽略的名称列表。例如:

    def ignore_pyc_files(dirname, filenames):
        return [name in filenames if name.endswith('.pyc')]
    shutil.copytree(src, dst, ignore=ignore_pyc_files)
    

    对于文件元数据信息,copy2() 这样的函数只能尽自己最大能力来保留它。访问时间、创建时间和权限这些基本信息会被保留,但是对于所有者、ACLs、资源 fork 和其他更深层次的文件元信息就说不准了

    通常不会去使用 shutil.copytree() 函数来执行系统备份。当处理文件名的时候,最好使用os.path中的函数来确保最大的可移植性

    >>> filename = '/etc/docker/daemon.json'
    >>> import os.path
    >>> os.path.basename(filename)
    'daemon.json'
    >>> os.path.dirname(filename)
    '/etc/docker'
    >>> os.path.split(filename)
    ('/etc/docker', 'daemon.json')
    >>> os.path.join('/new/dir', os.path.basename(filename))
    '/new/dir/daemon.json'
    >>> os.path.expanduser('~/guido/programs/daemon.json')
    '/root/guido/programs/daemon.json'
    >>>
    

    使用copytree()复制文件夹的一个棘手的问题是对于错误的处理,可以使用异常块处理,或者通过 参数 ignore dangling symlinks=True忽略掉无效符号链接。

    try:
        shutil.copytree(src, dst)
    except shutil.Error as e:
        for src, dst, msg in e.args[0]:
        # src is source name
        # dst is destination name
        # msg is error message from exception
        print(dst, src, msg)
    

    创建和解压归档文件

    创建或解压常见格式的归档文件(比如.tar, .tgz 或.zip)

    shutil 模块拥有两个函数—— make archive() 和 unpack archive() 可派上用场,

    >>> import shutil
    >>> shutil.unpack_archive('Python-3.3.0.tgz')
    >>> shutil.make_archive('py33','zip','Python-3.3.0')
    '/Users/beazley/Downloads/py33.zip'
    
    

    make archive() 的第二个参数是期望的输出格式。可以使用get archive formats()获取所有支持的归档格式列表。

    >>> import shutil
    >>> shutil.get_archive_formats()
    [('bztar', "bzip2'ed tar-file"), ('gztar', "gzip'ed tar-file"), ('tar', 'uncompressed tar file'), ('xztar', "xz'ed tar-file"), ('zip', 'ZIP file')]
    >>>
    

    通过文件名查找文件

    你需要写一个涉及到文件查找操作的脚本,比如对日志归档文件的重命名工具,你不想在 Python 脚本中调用 shell,或者你要实现一些 shell 不能做的功能。

    查找文件,可使用 os.walk() 函数,传一个顶级目录名给它

    #!/usr/bin/env python3
    
    import os,sys
    
    def findfile(start, name):
        for relpath, dirs, files in os.walk(start):
            if name in files:
                full_path = os.path.join(start, relpath, name)
                print(os.path.normpath(os.path.abspath(full_path)))
    
    if __name__ == '__main__':
        findfile(sys.argv[1], sys.argv[2])
    

    os.walk() 方法为我们遍历目录树,每次进入一个目录,它会返回一个三元组,包含相对于查找目录的相对路径,一个该目录下的目录名列表,以及那个目录下面的文件名列表。

    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$./find.py /etc/ passwd
    /etc/passwd
    /etc/pam.d/passwd
    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$
    

    对于每个元组,只需检测一下目标文件名是否在文件列表中。如果是就使用os.path.join() 合并路径。为了避免奇怪的路径名比如 ././foo//bar ,使用了另外两个函数来修正结果

    • 第一个是os.path.abspath(), 它接受一个路径,可能是相对路径,最后返回绝对路径。
    • 第二个是os.path.normpath(),用来返回正常路径,可以解决双斜杆、对目录的多重引用的问题等。

    os.walk(start)还有跨平台的优势。并且,还能很轻松的加入其他的功能。我们再演示一个例子,下面的函数打印所有最近被修改过的文件:

    #!/usr/bin/env python3
    import os
    import time
    import sys
    
    def modified_within(top, seconds):
        now = time.time()
        for path, dirs, files in os.walk(top):
            for name in files:
                fullpath = os.path.join(path, name)
                if os.path.exists(fullpath):
                    mtime = os.path.getmtime(fullpath)
                    if mtime > (now - seconds):
                        print(fullpath)
    
    
    if __name__ == '__main__':
        if len(sys.argv) != 3:
            print('Usage: {} dir seconds'.format(sys.argv[0]))
            raise SystemExit(1)
        modified_within(sys.argv[1], float(sys.argv[2]))
    

    打印10分钟之前被修改的数据

    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$./find.py /etc/ 10
    /etc/mtab
    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$ll /etc/mtab
    lrwxrwxrwx. 1 root root 17 1018 2018 /etc/mtab -> /proc/self/mounts
    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$ll /proc/self/mounts
    -r--r--r-- 1 root root 0 52 01:18 /proc/self/mounts
    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$
    

    读取配置文件

    怎样读取普通.ini 格式的配置文件?

    configparser 模块能被用来读取配置文件

    编写配置文件

    ; config.ini
    ; Sample configuration file
    [installation]
    library=%(prefix)s/lib
    include=%(prefix)s/include
    bin=%(prefix)s/bin
    prefix=/usr/local
    
    # Setting related to debug configuration
    [debug]
    log_errors=true
    show_warnings=False
    
    [server]
    port: 8080
    nworkers: 32
    pid-file=/tmp/spam.pid
    root=/www/root
    signature:
        =================================
        Brought to you by the Python Cookbook
        =================================
    
    >>> from configparser import ConfigParser
    >>> cfg = ConfigParser()
    >>> cfg.read('config.ini')
    ['config.ini']
    >>> cfg.sections()
    ['installation', 'debug', 'server']
    >>> cfg.get('installation','library')
    '/usr/local/lib'
    >>> cfg.getboolean('debug','log_errors')
    True
    >>> cfg.getint('server','port')
    8080
    >>> cfg.getint('server','nworkers')
    32
    >>> print(cfg.get('server','signature'))
    
    =================================
    Brought to you by the Python Cookbook
    =================================
    >>>
    

    如果有需要,你还能修改配置并使用cfg.write()方法将其写回到文件中

    >>> from configparser import ConfigParser
    >>> cfg = ConfigParser()
    >>> cfg.read('config.ini')
    ['config.ini']
    >>> cfg.set('server','port','9000')
    >>> cfg.set('debug','log_errors','False')
    >>> import sys
    >>> cfg.write(sys.stdout)
    [installation]
    library = %(prefix)s/lib
    include = %(prefix)s/include
    bin = %(prefix)s/bin
    prefix = /usr/local
    
    [debug]
    log_errors = False
    show_warnings = False
    
    [server]
    port = 9000
    nworkers = 32
    pid-file = /tmp/spam.pid
    root = /www/root
    signature =
            =================================
            Brought to you by the Python Cookbook
            =================================
    
    >>>
    
    • 配置文件中的名字是不区分大小写
    • 解析值的时候,getboolean() 方法查找任何可行的值。
    • ConfigParser 能一次读取多个配置文件然后合并成一个配置。后面读取的配置文件会覆盖前面的配置文件

    给简单脚本增加日志功能

    你希望在脚本和程序中将诊断信息写入日志文件。

    python 脚本打印日志最简单方式是使用 logging 模块

    #`!/usr/bin/env python3
    # -*- encoding: utf-8 -*-
    
    import logging
    
    
    def main():
        # Configure the logging system
        logging.basicConfig(filename='app.log',
                            level=logging.ERROR)
        # Variables (to make the calls that follow work)
        hostname = 'www.python.org'
        item = 'spam'
        filename = 'data.csv'
        mode = 'r'
        # Example logging calls (insert into your program)
        logging.critical('Host %s unknown', hostname)
        logging.error("Couldn't find %r", item)
        logging.warning('Feature is deprecated')
        logging.info('Opening file %r, mode=%r', filename, mode)
        logging.debug('Got here')
        
    if __name__ == '__main__':
        main()                    
    
    

    五个日志调用(critical(), error(), warning(), info(), debug())以降序方式表示不同的严重级别。 basicConfig() level参数是一个过滤器。所有级别低于此级别的日志消息都会被忽略掉。每个logging操作的参数是一个消息字符串,后面再跟一个或多个参数。构造最终的日志消息的时候我们使用了% 操作符来格式化消息字符串。

    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$./logger.py
    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$cat app.log
    CRITICAL:root:Host www.python.org unknown
    ERROR:root:Couldn't find 'spam'
    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$
    

    如果你想使用配置文件,可以像下面这样修改basicConfig()调用:

    import logging
    import logging.config
    def main():
        # Configure the logging system
        logging.config.fileConfig('logconfig.ini')
    

    logconfig.ini

    [loggers]
    keys=root
    [handlers]
    keys=defaultHandler
    [formatters]
    keys=defaultFormatter
    [logger_root]
    level=INFO
    handlers=defaultHandler
    qualname=root
    [handler_defaultHandler]
    class=FileHandler
    formatter=defaultFormatter
    args=('app.log', 'a')
    [formatter_defaultFormatter]
    format=%(levelname)s:%(name)s:%(message)s
    
    

    在调用日志操作前先执行下 basicConfig() 函数方法,可以找标准输出或者文件中输出

    basicConfig() 在程序中只能被执行一次。如果你稍后想改变日志配置,就需要先获取 root logger ,然后直接修改它。

    logging.getLogger().level = logging.DEBUG
    

    更多见日志模块文档https://docs.python.org/3/howto/logging-cookbook.html

    给函数库增加日志功能

    你想给某个函数库增加日志功能,但是又不能影响到那些不使用日志功能的程序。

    对于想要执行日志操作的函数库,你应该创建一个专属的logger对象,并且像下面这样初始化配置:

    #!/usr/bin/env python3
    # -*- encoding: utf-8 -*-
    
    import logging
    log = logging.getLogger(__name__)
    log.addHandler(logging.NullHandler())
    
    # Example function (for testing)
    def func():
        log.critical('A Critical Error!')
        log.debug('A debug message')
    
    func()
    

    使用这个配置,默认情况下不会打印日志,只有配置过日志系统,那么日志消息打印就开始生效

    logging.basicConfig()
    
    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$./logg.py
    CRITICAL:__main__:A Critical Error!
    

    通常来讲,不应该在函数库代码中自己配置日志系统,或者是已经有个已经存在的日志配置了。调用getLogger( name )创建一个和调用模块同名的 logger 模块。由于模块都是唯一的,因此创建的 logger 也将是唯一的。所以当前进程中只有一个logging会生效。

    log.addHandler(logging.NullHandler()) 操作将一个空处理器绑定到刚刚已经创建好的 logger 对象上。一个空处理器默认会忽略调用所有的日志消息。因此,如果使用该函数库的时候还没有配置日志,那么将不会有消息或警告出现。

    在这里,根日志被配置成仅仅输出 ERROR 或更高级别的消息。不过,somelib 的日志级别被单独配置成可以输出 debug 级别的消息,它的优先级比全局配置高。像这样更改单独模块的日志配置对于调试来讲是很方便的,因为你无需去更改任何的全局日志配置——只需要修改你想要更多输出的模块的日志等级。(这个还有待研究)

    实现一个计时器

    你想记录程序执行多个任务所花费的时间

    time 模块包含很多函数来执行跟时间有关的函数。尽管如此,通常我们会在此基础之上构造一个更高级的接口来模拟一个计时器。

    #!/usr/bin/env python3
    # -*- encoding: utf-8 -*-
    
    import time
    
    
    class Timer:
        def __init__(self, func=time.perf_counter):
            self.elapsed = 0.0
            self._func = func
            self._start = None
    
        def start(self):
            if self._start is not None:
                raise RuntimeError('Already started')
            self._start = self._func()
    
        def stop(self):
            if self._start is None:
                raise RuntimeError('Not started')
            end = self._func()
            self.elapsed += end - self._start
            self._start = None
    
        def reset(self):
            self.elapsed = 0.0
    
        @property #类的属性私有化,那么可以使用@property 使属性可以被外部访问并修改
        def running(self):
            return self._start is not None
    
        def __enter__(self):
            self.start()
            return self
    
        def __exit__(self, *args):
            self.stop()
    
    

    这个类定义了一个可以被用户根据需要启动、停止和重置的计时器。它会在elapsed 属性中记录整个消耗时间。下面是一个例子来演示怎样使用它:

    #!/usr/bin/env python3
    # -*- encoding: utf-8 -*-
    
    import time
    
    
    class Timer:
        def __init__(self, func=time.perf_counter):
            self.elapsed = 0.0
            self._func = func
            self._start = None
    
        def start(self):
            if self._start is not None:
                raise RuntimeError('Already started')
            self._start = self._func()
    
        def stop(self):
            if self._start is None:
                raise RuntimeError('Not started')
            end = self._func()
            self.elapsed += end - self._start
            self._start = None
    
        def reset(self):
            self.elapsed = 0.0
    
        @property #类的属性私有化,那么可以使用@property 使属性可以被外部访问并修改
        def running(self):
            return self._start is not None
    
        def __enter__(self):
            self.start()
            return self
    
        def __exit__(self, *args):
            self.stop()
    
    def countdown(n):
        while n > 0:
            n -= 1
    # Use 1: Explicit start/stop
    t = Timer()
    t.start()
    countdown(1000000)
    t.stop()
    print(t.elapsed)
    # Use 2: As a context manager
    with t:
        countdown(1000000)
    print(t.elapsed)
    with Timer() as t2:
        countdown(1000000)
    print(t2.elapsed)
    
    

    这里通过__enter__,__exit__ ,使用with 语句以及上下文管理器协议可以省略计时器打开和关闭操作。(关于上下文管理协议,即with语句,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法,,__enter__在出现with语句被调用,__exit__在代码执行完毕被调用,可以参考open()方法)

    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$./times.py
    0.05191648800246185
    0.12038616700374405
    0.06592946800083155
    

    在计时中要考虑一个底层的时间函数问题。 一般来说, 使用 time.time()time.clock()计算的时间精度因操作系统的不同会有所不同。而使用time.perf_counter() 函数可以确保使用系统上面最精确的计时器

    限制脚本的内存和CPU的使用量

    你想对在 Unix 系统上面运行的程序设置内存或 CPU 的使用限制。

    cpu 限制

    resource 模块能同时执行这两个任务。例如,要限制 CPU 时间,下面的代码在windows平台执行不了,但是Linux是可以的。

    #!/usr/bin/env python3
    # -*- encoding: utf-8 -*-
    
    import signal
    import resource  
    import os
    def time_exceeded(signo, frame):
        print("Time's up!")
        raise SystemExit(1)
    def set_max_runtime(seconds):
        # 安装信号处理程序并设置资源限制  
        soft, hard = resource.getrlimit(resource.RLIMIT_CPU)
        # 限制CUP使用时间为15秒
        resource.setrlimit(resource.RLIMIT_CPU, (seconds, hard))
        # 进程即将结束,给一个信号量,加一个回调
        signal.signal(signal.SIGXCPU, time_exceeded)
    
    if __name__ == '__main__':
        set_max_runtime(15)
        while True:
            pass
    

    程序运行时,SIGXCPU 信号在时间过期时被生成,然后执行清理并退出。

    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$vim cpu.py
    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$chmod +x cpu.py
    ┌──[root@liruilongs.github.io]-[~/python_demo]
    └─$./cpu.py
    Time's up!
    

    内存限制

    这暂时没有好的Demo…

    #!/usr/bin/env python3
    # -*- encoding: utf-8 -*-
    
    
    import resource
    
    def limit_memory(maxsize):
            soft, hard = resource.getrlimit(resource.RLIMIT_AS)
            resource.setrlimit(resource.RLIMIT_AS, (maxsize, hard))
    
    # 0.5 * 1024 ^ 6 = 576460752303423488 设置最大内存500M
    limit_memory(576460752303423488)
    

    程序运行到没有多余内存时会抛出 MemoryError 异常。

    setrlimit() 函数被用来设置特定资源上面的软限制和硬限制

    • 软限制是一个值,当超过这个值的时候操作系统通常会发送一个信号来限制或通知该进程.
    >>> resource.RLIMIT_AS
    9
    
    • 硬限制是用来指定软限制能设定的最大值。通常来讲,这个由系统管理员通过设置系统级参数来决定。尽管硬限制可以改小一点,但是最好不要使用用户进程去修改。
    >>> resource.getrlimit(resource.RLIMIT_AS)
    (-1, -1)
    

    setrlimit() 函数还能被用来设置子进程数量、打开文件数以及类似系统资源的限制(cgroup)

    启动一个WEB浏览器

    通过脚本启动浏览器并打开指定的 URL 网页

    webbrowser 模块能被用来启动一个浏览器,并且与平台无关

    Windows PowerShell
    版权所有 (C) Microsoft Corporation。保留所有权利。
    
    尝试新的跨平台 PowerShell https://aka.ms/pscore6
    
    PS E:\docker> python
    Python 3.9.0 (tags/v3.9.0:9cf6752, Oct  5 2020, 15:23:07) [MSC v.1927 32 bit (Intel)] on win32
    Type "help", "copyright", "credits" or "license" for more information.
    >>>
    >>> import webbrowser
    >>> webbrowser.open('http://www.python.org')
    True
    >>>
    
    

    新窗口打卡网站

    webbrowser.open_new('http://www.python.org')
    

    当前窗口打开一个tab页

    webbrowser.open_new_tab('http://www.python.org')
    

    指定浏览器类型,可以使用 webbrowser.get() 函数

    >>> c = webbrowser.get('firefox')
    >>> c.open('http://www.python.org')
    True
    >>> c.open_new_tab('http://docs.python.org')
    True
    >>>
    
    展开全文
  • 本篇中,我们会讨论控制流(根据...在“Linux平台下Python脚本编程入门”系列之前的文章里,我们向你介绍了 Python的简介,它的命令行shell和IDLE(LCTT译注:python自带的一个IDE)。我们也演示了如何进行算术运算、如何
  • Linux下不支持QQ等功能丰富的IM,虽然可以通过wine运行QQ2012,但是还是喜欢在gtalk群中聊天,gtalk群不支持图片方式,这就要靠我们大家自己来解决了,eleven开放了一个Image上传和显示接口,提供了使用curl来解决,但是...
  • 3 案例3:模拟cp操作 3.1 问题 创建cp.py文件,实现以下目标: 将/bin/ls“拷贝”到/root/目录 不要修改原始文件 12 3.2 方案 获取用户原文件名和新文件名,打开...步骤一:编写脚本 [root@localhost day03]# vim cp
  • 然后使用vim编辑器:vim test.py 就创建了python脚本文件,并且进入编辑状态2、编辑好之后按Esc切换到命令模式,然后输入:wq 回车就自动保存完成了,然后输入python test.py运行程序(前提是linux环境装好python) ...
  • 今天小编就为大家分享一篇python脚本当作Linux中的服务启动实现方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
  • 主要介绍了Python脚本判断 Linux 是否运行在虚拟机上,本文讲解了判断 OpenVZ/Xen PV/UML、判断 VMware/Xen HVM/KVM、判断 VirtualBox/Virtual PC等方法,需要的朋友可以参考
  • 本文介绍一下使用Python脚本实现对Linux服务器CPU...Python是由GuidovanRossum开发的、可免费获得的、非常高级的解释型语言。其语法简单易懂,而其面向对象的语义功能强大(但又灵活)。Python可以广泛使用并具有...
  • Linux 有一些使用 Python 语言编写Linux 系统监控工具 比如 inotify-sync(文件系统安全监控软件)、glances(资源监控工具)在实际工作中,Linux 系统管理员可以根据自己使用的服务器的具体情况编写一下简单...
  • PYTHON脚本实现对LINUX服务器的监控
  • python脚本编写

    万次阅读 多人点赞 2019-03-29 22:37:20
    Python 是一种“脚本语言”。脚本,对应的英文是:script。一般人看到script这个英文单词,或许想到的更多的是:电影的剧本,就是一段段的脚本,所组成的。电影剧本的脚本,决定了电影中的人和物,都做哪些事情,...
  • linux定时执行python脚本

    千次阅读 2021-05-16 17:47:14
    每天清晨 4:00:01,用python执行/opt/aa.py文件。...如果执行的文件在当前目录的二级目录,则需要先cd进入相应目录,再python:*/5 * * * * cd /home/iris/; python aa.pycrontab命令格式:* * * * * command...
  • python脚本编写与执行

    千次阅读 2020-12-29 03:42:24
    Python不使用括号来表示代码的类和函数定义块或流程控制...Python中命名规则Python脚本与其它语言的脚本的基本格式完全一样,本身都是纯文字文件,而在文件头要以#!指定直译程序(解释器)的位置:[root@importer1~]#...
  • 一、python3安装 1、yum安装依赖包 yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel mysql-devel 2、wget...
  • Linux下Python脚本自启动和定时启动

    千次阅读 2018-11-18 15:16:04
    一、Python开机自动运行 自启动脚本为auto.py 用root权限编辑以下文件 sudo vim /etc/rc.local 在exit 0上面编辑启动脚本的命令 /usr/bin/python3 /home/edgar/auto.py &gt; /home/edgar/auto.log 给rc....
  • 安装完python后,把python的include和lib拷贝到自己的工程目录 然后在工程中包括进去 2.例子 先写一个python的测试脚本,如下 这个脚本里面定义了两个函数Hello()和_add()。我的脚本的文件名叫mytest.py C++...
  • Daml-shell包装器,用于python脚本编写 先决主义者 posix合规性:(Linux或理论上为Mac OS,后者未经测试) python 3.6+ pgrep (用于查找daml shell进程) sudo权限(请参阅下面的说明) (可选)ipython 用法 ...
  • 此项目是对在Linux运维工作所能用到的Shell脚本和Python脚本的归纳和总结。 大部分源码均出自生产系统并经过比较严谨的测试,少部分脚本是用于学习或者测试目的。 遵循实用并尽可能的pythonic的原则。 为什么有...
  • 最近增加了纯真库的IP接口,需要定时更新生成的IP文件,需要服务器定时运行python脚本。因此,简单记录步骤。 1.编辑crontab配置 服务器一般会安装好crontab,若没有安装请按命令安装 yum install crontabs ...
  • Linux下shell脚本编写

    2022-05-01 11:34:11
    长用的脚本有shell、python… 学习shell脚本的第一天 掌握知识有: shell脚本的组成(如何编写一个shell脚本) shell脚本的执行(两种1.给予执行权限;2.解释器运行,不需要全权限 shell中的符号 shell中管道的使用 ...
  • Linux下执行Python脚本

    万次阅读 多人点赞 2017-12-15 11:24:14
    Linux系统一般集成Python,如果没有安装,可以手动安装,联网状态可直接安装。Fedora使用yum install,Ubuntu使用apt-get install,前提都是root权限。安装完毕,可将Python加入环境变量,这样在使用Python时...
  • 一个简单的开源OTP和呼叫泛滥脚本用于使用Python3编写的基于Linux的终端 笔记: :gear: 免责声明: 对于由海啸引起的任何误用或损坏,开发人员概不负责,也不承担任何责任。 请不要使用此脚本对某人进行复仇。 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 81,509
精华内容 32,603
关键字:

linux下python脚本编写