016-pysftp SFTP

pysftp SFTP

  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
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155

import pysftp
import os
import sys
import time
import gnupg

from etc import config
import utils
from utils import logger_web
from utils import logger_lms as logger


# -----------------------------
broker=config.LMS["broker"]
notifier_list=config.Notifier
notifier_list2=config.Notifier2
# -----------------------------

class SFTPClient:
    def __init__(self, host,port, username, password, upload_dir, download_dir,gpg_key_id='D7B7817A'):
        self.host = host
        self.port = port
        self.username = username
        self.password = password
        self.upload_dir = upload_dir
        self.download_dir = download_dir
        self.sftp = None
        self.gpg = gnupg.GPG(gnupghome="/root/.gnupg")
        self.gpg_key_id=gpg_key_id
        self.max_retries = 3
        self.retry_delay = 5
        # 禁用主机密钥检查
        self.cnopts = pysftp.CnOpts()
        self.cnopts.hostkeys = None
        self.connect()

    def ensure_connected(self):
        """确保SFTP连接是活跃的,如果断开则重连"""
        try:
            self.sftp.listdir()
        except Exception as e:
            logger.error("SFTPClient connection check failed, error={}".format(e))
            self.connect()
            time.sleep(3)

    def connect(self):
        """建立SFTP连接,包含重试机制"""
        for attempt in range(self.max_retries):
            try:
                if self.sftp:
                    try:
                        self.sftp.close()
                    except Exception as e:
                        logger.error("SFTPClient during disconnect error: {}".format(e))
                self.sftp = pysftp.Connection(
                    host=self.host,
                    port=self.port,
                    username=self.username,
                    password=self.password,
                    cnopts=self.cnopts
                )
                logger.info("SFTPClient connected to {}, connected success ...".format(self.host))
                return True
            except Exception as e:
                logger.error("SFTPClient connection attempt {} failed, error={}".format(attempt+1, e))
                if attempt < self.max_retries-1:
                    logger.error("SFTPClient Retrying in {} seconds...".format(self.retry_delay))
                    time.sleep(self.retry_delay)
        return False

    def upload_file(self, local_path):
        logger.info("SFTPClient start upload file={} to remote_path={}".format(local_path, self.upload_dir))
        if not os.path.exists(local_path):
            logger.error("SFTPClient UploadFile ={} does not exist".format(local_path))
            return False

        for attempt in range(self.max_retries):
            try:
                self.ensure_connected()
                self.sftp.chdir(self.upload_dir)
                filename = os.path.basename(local_path)
                self.sftp.put(local_path)
                logger.info("SFTPClient Successfully upload file={} to remote_path={}".format(filename, self.upload_dir))
                self.close()
                utils.send_message('markdown', "{} SFTP upload_file".format(broker),
                           "## {} SFTP upload_file success\nFtpSide={}\nFtpUser={}\nfile={}\n".format(broker,
                            config.LMS['ftp_url'],config.LMS['ftp_user'],filename),notifier_list)
                local_csvfile=local_path.replace(".pgp",'')
                utils.weichat_send_file(local_csvfile)
                return True
            except Exception as e:
                logger.error("SFTPClient Failed upload file={}, attempt {} error={}".format(local_path, attempt+1, str(e)))
                if attempt < self.max_retries-1:
                    logger.error("SFTPClient Retrying upload file={}, seconds...".format(local_path))
                    time.sleep(self.retry_delay)
        return False

    def search_file(self, filename):
        logger.info("SFTPClient start search remote_path={}/{} ...".format(self.download_dir, filename))
        for attempt in range(self.max_retries):
            try:
                self.ensure_connected()
                self.sftp.chdir(self.download_dir)
                files = self.sftp.listdir()
                logger.info(f"----------listdir-----------------{self.download_dir}---------------------------")
                logger.info(f"-------------------------{filename}---------------------{attempt+1}--------------------")
                logger.info(files)
                logger.info("--------------------------------------------------------------------")
                logger.info("--------------------------------------------------------------------")
                logger.info("--------------------------------------------------------------------")
                if filename in files:
                    logger.info("SFTPClient search remote_path={}/{} ****** find ******".format(self.download_dir, filename))
                    return True
                return False
            except Exception as e:
                logger.error("SFTPClient search failed remote_path={}/{}, attempt {}, error={}".format(
                    self.download_dir, filename, attempt+1, str(e)))
                if attempt < self.max_retries-1:
                    time.sleep(self.retry_delay)
        return False

    def download_file(self, remote_filename, local_file):
        logger.info("SFTPClient start download remote_path={}/{} to {}".format(
            self.download_dir, remote_filename, local_file))
        for attempt in range(self.max_retries):
            try:
                self.ensure_connected()
                self.sftp.chdir(self.download_dir)
                self.sftp.get(remote_filename, local_file)
                logger.info("SFTPClient Successfully downloaded {} to {}".format(remote_filename, local_file))
                self.close()
                utils.send_message('markdown', "{} SFTP download_file".format(broker),
                           "## {} SFTP download_file success\nFtpSide={}\nFtpUser={}\nfile={}\n".format(broker,
                            config.LMS['ftp_url'],config.LMS['ftp_user'],remote_filename),notifier_list)
                return True
            except Exception as e:
                logger.error("SFTPClient Download failed remote_path={}/{}, attempt {}, error={}".format(
                    self.download_dir, remote_filename, attempt+1, str(e)))
                if attempt < self.max_retries-1:
                    time.sleep(self.retry_delay)
                    if os.path.exists(local_file):
                        try:
                            os.remove(local_file)  # 删除可能的部分下载文件
                        except Exception as e:
                            logger.error("SFTPClient Download failed remote_path={}/{}, remove partial download local_path={}, error={}".format(
                                self.download_dir, remote_filename, local_file, str(e)))
        return False

    def close(self):
        if self.sftp:
            try:
                self.sftp.close()
            except Exception as e:
                logger.error("SFTPClient close has error:{}".format(e))

009-C++标准库中的<algorithm>头文件提供的常用算法

Cpp标准库中的头文件提供的常用算法

1: 介绍

  • 在 c++中, <algorithm> 头文件提供了一系列用于操作序列(如 array,vector,列表 list)的算法;
  • 这些算法可以极大的帮助我们简单高效的处理数据,提高代码的可读性和可维护性;

2: 查找算法 search

2.1 std::find

  • std::find 是一个线性查找算法,用于在序列中查找特定元素;
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#include <algorithm>
#include <iostream>
#include <vector>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};
    int val = 3;

    // 使用std::find查找val在vec中的位置
    auto it = std::find(vec.begin(), vec.end(), val);
    if (it != vec.end()) {
        std::cout << "找到元素 " << val << " 在位置 " << std::distance(vec.begin(), it) << std::endl;
    } else {
        std::cout << "未找到元素 " << val << std::endl;
    }
    return 0;
}

2.2 std::find_if

  • std::find_if 允许你根据特定条件在序列中查找元素;
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
#include <algorithm>
#include <vector>
#include <iostream>

bool is_even(int i) {
    return (i % 2) == 0;
}

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};

    // 使用std::find_if查找第一个偶数元素
    auto it = std::find_if(vec.begin(), vec.end(), is_even);

    if (it != vec.end()) {
        std::cout << "找到第一个偶数 " << *it << " 在位置 " << std::distance(vec.begin(), it) << std::endl;
    } else {
        std::cout << "未找到偶数" << std::endl;
    }
    return 0;
}

3: 排序算法 sort

3.1 std::sort

  • std::sort 是一个高效的排序算法,通常实现为快速排序、堆排序或归并排序的混合体;
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#include <algorithm>
#include <vector>
#include <iostream>

int main() {
    std::vector<int> vec = {5, 2, 3, 1, 4};

    // 使用std::sort对vec进行排序
    std::sort(vec.begin(), vec.end());

    // 输出排序后的向量
    for (int i : vec) {
        std::cout << i << " ";
    }
    std::cout << std::endl;
    return 0;
}

3.2 std::stable_sort

  • std::stable_sort 是一种稳定的排序算法,即相等元素的相对顺序在排序后保持不变;
  • std::stable_sort 用法与 std::sort 类似,但保证排序的稳定性。

4: 修改序列算法

4.1 std::for_each

  • std::for_each 用于对序列中的每个元素执行特定操作;
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#include <algorithm>
#include <vector>
#include <iostream>

void print(int i) {
    std::cout << i << " ";
}

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};

    // 使用std::for_each打印vec中的每个元素
    std::for_each(vec.begin(), vec.end(), print);
    std::cout << std::endl;
    return 0;
}

4.1 std::transform

  • std::transform 用于对序列中的每个元素执行某种转换,并将结果存储到另一个序列中;
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#include <algorithm>
#include <vector>
#include <iostream>
#include <functional> // 为了使用std::plus等函数对象

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};
    std::vector<int> result(vec.size());

    // 使用std::transform将vec中的每个元素加倍并存储到result中
    std::transform(vec.begin(), vec.end(), result.begin(), [](int x) { return x * 2; });

    // 输出转换后的结果向量
    for (int i : result) {
        std::cout << i << " ";
    }
    std::cout << std::endl;
    return 0;
}

5: 其他常见算法

5.1 std::unique_copy

  • std::unique_copy算法用于从一个输入序列中复制不重复的元素到一个输出序列。这个算法假定输入序列是已排序的,因为只有已排序的序列才能保证相邻的重复元素被识别并去除
  • 先排序;
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#include <algorithm>
#include <vector>
#include <iostream>
#include <iterator>

int main() {
    std::vector<int> source = {1, 2, 2, 3, 4, 4, 4, 5};
    std::vector<int> destination;

    // 注意:在这个例子中,std::back_inserter是一个插入迭代器,它将新元素添加到destination容器的末尾
    std::unique_copy(source.begin(), source.end(), std::back_inserter(destination));

    // 输出目标向量,应不包含重复的元素
    for (int val : destination) {
        std::cout << val << " ";
    }
    std::cout << std::endl;

    return 0;
}

5.2 std::merge

  • std::merge 算法用于合并两个已排序的序列,结果也是一个已排序的序列;
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#include <algorithm>
#include <vector>
#include <iostream>
#include <iterator>

int main() {
    std::vector<int> vec1 = {1, 3, 5, 7};
    std::vector<int> vec2 = {2, 4, 6, 8};
    std::vector<int> result(vec1.size() + vec2.size());

    std::merge(vec1.begin(), vec1.end(), vec2.begin(), vec2.end(), result.begin());

    // 输出合并后的结果向量
    for (int val : result) {
        std::cout << val << " ";
    }
    std::cout << std::endl;

    return 0;
}

5.3 集合算法:std::set_difference, std::set_intersection, std::set_union, std::set_symmetric_difference

  • 这些算法用于在两个已排序的序列之间执行集合操作。
  • std::set_difference:计算两个已排序范围的差集。
  • std::set_intersection:计算两个已排序范围的交集。
  • std::set_union:计算两个已排序范围的并集。
  • std::set_symmetric_difference:计算两个已排序范围的对称差集(即属于第一个范围但不属于第二个范围,以及属于第二个范围但不属于第一个范围的所有元素)。
  • 对于其他集合算法,使用方法是类似的,只是调用的函数名不同,以及它们处理集合运算的方式不同。这些算法在处理大量数据时可以显著提高效率,因为它们都利用了输入数据已排序的特性来优化性能

6 其他值得注意的算法

  • 除了之前提到的算法外,C++标准库还提供了许多其他有用的算法,这些算法在处理各种编程任务时都非常实用。

6.1. std::partition 和 std::stable_partition

std::partition 和 std::stable_partition 算法用于根据给定谓词对序列进行划分,使得满足谓词的元素出现在不满足谓词的元素之前。std::stable_partition 还保持了等价元素的相对顺序。

015-pip命令说明

[toc]

Table of Contents

1:pip 命令说明

1.1: 安装 pip

  • python -m pip --version:

1.2: 安装 Python 库

  • pip install requests: 它会自动处理库及其依赖关系

1.3: 升级库

  • pip list --outdated # 查看待升级库
  • pip upgrade <package_name> # 升级指定库

1.4: 卸载库

  • pip uninstall <package_name>

1.5: 搜索库

  • pip search <keyword>: 比如查找与机器学习相关的库,你可以输入 pip search machine learning

1.6: 查看已安装库详细信息

  • pip show <package_name>

1.7: 只下载库而不安装

  • 有时你可能需要离线环境安装包或者备份当前环境的依赖,那么可以使用 download 命令只下载不安装:
  • pip download <package_name>

1.8: 创建 requirements 文件

  • 在项目开发中,为了方便团队成员统一环境,我们可以创建一个包含所有依赖的 requirements 文件:
  • pip freeze > requirements.txt
  • 这会列出当前环境中所有已安装库及其版本,并保存到 requirements.txt 文件中。而要根据这个文件安装所有依赖,只需:
  • pip install -r requirements.txt

1.9: 指定库版本安装

  • 在某些情况下,你可能需要安装特定版本的库,比如安装 requests 库的 2.25.1 版本
  • pip install requests==2.25.1

1.10: 检查是否存在安全漏洞

  • pip 配合 Safety 工具可以检查已安装库的安全性:

040-Linux安装配置gitlab私有仓库

1: 安装 gitlab

1.1 安装

  • https://packages.gitlab.com/gitlab/gitlab-ce/install

  • 安装工具包: apt install policycoreutils-python-utils

  • 安装 gitlab: curl -s https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.deb.sh | sudo bash

  • sudo apt install gitlab-ce

  • 安装成功成功出现如下图所示:

1.2 配置

  • 更新配置 :gitlab-ctl reconfigure。装完成后,更新配置,稍微需要点时间,耐心等待一下,完成后,我们可以看到用户名和密码
  • 以下信息我们可以看到用户名和密码,用户名为:root,密码需要单独查看
  • 上面那个路径就是密码路径,查看密码:cat /etc/gitlab/initial_root_password

1.3 启动 gitlab

  • gitlab-ctl start;

008-Cpp time操作示例

Cpp time 示例

1: time 介绍

  • std::chrono::duration

  • std::chrono::time_point

  • std::chrono::system_clock

  • std::chrono::steady_clock

  • std::chrono::high_resolution_clock

  • std::time_t

  • std::tm

2: time code

 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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <chrono>
#include <iostream>
#include <thread>
#include <ctime>
#include <iomanip>

int main() {
    // std::chrono::duration<Rep ,Period> 表示一段时间
    std::chrono::duration<int> time_out_1(3); // time_out 设置为3S
    std::chrono::duration<int, std::ratio<1>> time_out_2(3); // time_out 设置为3S
    std::chrono::duration<int, std::milli> time_out_3(3000); // time_out 设置为3000 ms

    std::chrono::duration<int,std::ratio<1>> sum_duration =
            std::chrono::duration_cast<std::chrono::duration<int>>(time_out_1) +
            std::chrono::duration_cast<std::chrono::duration<int>>(time_out_2) +
            std::chrono::duration_cast<std::chrono::duration<int>>(time_out_3);

    std::cout << "sum_duration = " << sum_duration.count() << " seconds" << std::endl;

    std::chrono::duration<long long,std::ratio<1,1000>> sum_duration_mill =std::chrono::duration_cast<std::chrono::milliseconds>(sum_duration);
    std::cout << "sum_duration_mill = " << sum_duration_mill.count() << " millseconds" << std::endl;

    // std::chrono::time_point<>; 表示时间点
    std::chrono::system_clock::time_point t1=std::chrono::system_clock::now(); // 获取当前时间点
    std::this_thread::sleep_for(std::chrono::seconds(3)); // sleep 3 s
    std::chrono::system_clock::time_point t2=std::chrono::system_clock::now();
    std::chrono::duration<double> elapsed_time=t2-t1;

    std::cout << "Start time: " << std::chrono::system_clock::to_time_t(t1) << std::endl;
    std::cout << "End time: " << std::chrono::system_clock::to_time_t(t2) << std::endl;
    std::cout << "Time elapsed: " << elapsed_time.count() << " seconds" << std::endl;


    // std::chrono::system_clock 类提供给了从系统实时时钟上获取当前时间功能。
    // 可以调用std::chrono::system_clock::now()来获取当前的时间

    // std::chrono::steady_clock 能访问系统稳定时钟。
    // 可以通过调用std::chrono::steady_clock::now()获取当前的时间。设备上显示的时间,与使用std::chrono::steady_clock::now()获取的时间没有固定的关系。稳定时钟是无法回调的


    // td::chrono::high_resolution_clock类能访问系统高精度时钟。和所有其他时钟一样,通过调用std::chrono::high_resolution_clock::now()来获取当前时间
    // std::chrono::high_resolution_clock可能是std::chrono::system_clock类或std::chrono::steady_clock类的别名,也可能就是独立的一个类
    // 通过std::chrono::high_resolution_clock具有所有标准库支持时钟中最高的精度,这就意味着使用
    // std::chrono::high_resolution_clock::now()要花掉一些时间。所以,当你再调用std::chrono::high_resolution_clock::now()的时候,需要注意函数本身的时间开销。


    // datetime
    // 获取当前时间点
    auto now=std::chrono::system_clock::now();
    // 将时间点转为时间戳 time_t
    std::time_t time_t_now =std::chrono::system_clock::to_time_t(now);
    // 将时间戳转换为 std::tm 结构体
    std::tm* time_info = std::localtime(&time_t_now);
    std::cout << "Current DateTime: " << std::put_time(time_info, "%Y-%m-%d %H:%M:%S") << std::endl;


    return 0;
}

039-Shell设置颜色及一些参数

1: Shell 脚本查错

1.1 set -u

  • 执行脚本时,如果遇到不存在的变量,Bash 默认忽略它;
  • set -u 就用来改变这种行为。脚本在头部加上它,遇到不存在的变量就会报错,并停止执行;
1
2
3
4
5
#!/usr/bin/env bash
set -u

echo $a
echo bar
  • 运行结果如下:
1
2
3
4
$ bash script.sh
bash: script.sh:行4: a: 未绑定的变量
# 可以看到,脚本报错了,并且不再执行后面的语句
#
  • -u 还有另一种写法 -o nounset ,两者是等价的;
  • set -o nounset

1.2 set -x

  • set -x 用来在运行结果之前,先输出执行的那一行命令;
  • -x还有另一种写法-o xtrace;

1.3

1.4 Bash 的错误处理

  • [[ -d $dir_name ]] && cd $dir_name && rm *: 先判断目录存在,再删除;
  • bash 的-x参数可以在执行每一行命令之前,打印该命令;

1.5 set -e

1.6 其他参数

  • set 命令还有一些其他参数。

Linux系统常用命令速查

1: 查看系统信息

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
arch      #显示机器的处理器架构(1)
uname -m  #显示机器的处理器架构(2)
uname -r  #显示正在使用的内核版本
dmidecode -q          #显示硬件系统部件 - (SMBIOS / DMI)
hdparm -i /dev/hda    #罗列一个磁盘的架构特性
hdparm -tT /dev/sda   #在磁盘上执行测试性读取操作
cat /proc/cpuinfo     #显示CPU info的信息
cat /proc/interrupts  #显示中断
cat /proc/meminfo     #校验内存使用
cat /proc/swaps       #显示哪些swap被使用
cat /proc/version     #显示内核的版本
cat /proc/net/dev     #显示网络适配器及统计
cat /proc/mounts      #显示已加载的文件系统
lspci -tv   #罗列PCI设备
lsusb -tv   #显示USB设备

2: date 显示系统日期

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
1: 查看当前时间
date +"%Y-%m-%d %H:%M:%S"
# 输出:"2021-03-25 18:12:38"

2: 查看指定时间,转为时间戳
date +%s
date -d "2021-03-25 18:12:38" +"%Y-%m-%d %H:%M:%S"
date -d "2021-03-25 18:12:38" +%s

3:时间戳转换为date
date -d @1416387827
date -d @1416387827 +"%Y-%m-%d %H:%M:%S"

cal 2007              #显示2007年的日历表
date 041217002007.00   #设置日期和时间 - 月日时分年.秒
clock -w              #将时间修改保存到 BIOS

3: 系统的关机、重启以及登出

1
2
3
4
5
6
7
8
shutdown -h now    #关闭系统(1)
init 0            #关闭系统(2)
telinit 0         #关闭系统(3)
shutdown -h hours:minutes &   #按预定时间关闭系统
shutdown -c       #取消按预定时间关闭系统
shutdown -r now   #重启(1)
reboot   #重启(2)
logout   #注销

4: 文件搜索

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
find / -name file1     #从 '/' 开始进入根文件系统搜索文件和目录
find / -user user1     #搜索属于用户 'user1' 的文件和目录
find /home/user1 -name \*.bin        #在目录 '/ home/user1' 中搜索带有'.bin' 结尾的文件
find /usr/bin -type f -atime +100    #搜索在过去100天内未被使用过的执行文件
find /usr/bin -type f -mtime -10     #搜索在10天内被创建或者修改过的文件
find / -name \*.rpm -exec chmod 755 '{}' \;      #搜索以 '.rpm' 结尾的文件并定义其权限
find / -xdev -name \*.rpm        #搜索以 '.rpm' 结尾的文件,忽略光驱、捷盘等可移动设备
locate \*.ps       #寻找以 '.ps' 结尾的文件 - 先运行 'updatedb' 命令
whereis halt       #显示一个二进制文件、源码或man的位置
which halt         #显示一个二进制文件或可执行文件的完整路径

5: 挂载一个文件系统

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
mount /dev/hda2 /mnt/hda2    #挂载一个叫做hda2的盘 - 确定目录 '/ mnt/hda2' 已经存在
umount /dev/hda2            #卸载一个叫做hda2的盘 - 先从挂载点 '/ mnt/hda2' 退出
fuser -km /mnt/hda2         #当设备繁忙时强制卸载
umount -n /mnt/hda2         #运行卸载操作而不写入 /etc/mtab 文件- 当文件为只读或当磁盘写满时非常有用
mount /dev/fd0 /mnt/floppy        #挂载一个软盘
mount /dev/cdrom /mnt/cdrom       #挂载一个cdrom或dvdrom
mount /dev/hdc /mnt/cdrecorder    #挂载一个cdrw或dvdrom
mount /dev/hdb /mnt/cdrecorder    #挂载一个cdrw或dvdrom
mount -o loop file.iso /mnt/cdrom    #挂载一个文件或ISO镜像文件
mount -t vfat /dev/hda5 /mnt/hda5    #挂载一个Windows FAT32文件系统
mount /dev/sda1 /mnt/usbdisk         #挂载一个usb 捷盘或闪存设备
mount -t smbfs -o username=user,password=pass //WinClient/share /mnt/share #挂载一个windows网络共享

6: 磁盘空间

1
2
3
4
5
6
7
8
df -h           #显示已经挂载的分区列表
ls -lSr |more    #以尺寸大小排列文件和目录
du -sh dir1      #估算目录 'dir1' 已经使用的磁盘空间'
du -sk * | sort -rn     #以容量大小为依据依次显示文件和目录的大小
rpm -q -a --qf '%10{SIZE}t%{NAME}n' | sort -k1,1n
#以大小为依据依次显示已安装的rpm包所使用的空间 (fedora, redhat类系统)
dpkg-query -W -f='${Installed-Size;10}t${Package}n' | sort -k1,1n
#以大小为依据显示已安装的deb包所使用的空间 (ubuntu, debian类系统)

7: 用户和群组

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
groupadd group_name   #创建一个新用户组
groupdel group_name   #删除一个用户组
groupmod -n new_group_name old_group_name   #重命名一个用户组
useradd -c "Name Surname " -g admin -d /home/user1 -s /bin/bash user1     #创建一个属于 "admin" 用户组的用户
useradd user1      #创建一个新用户
userdel -r user1   #删除一个用户 ( '-r' 排除主目录)
usermod -c "User FTP" -g system -d /ftp/user1 -s /bin/nologin user1   #修改用户属性

passwd         #修改口令
passwd user1   #修改一个用户的口令 (只允许root执行)
chage -E 2005-12-31 user1    #设置用户口令的失效期限
pwck     #检查 '/etc/passwd' 的文件格式和语法修正以及存在的用户
grpck    #检查 '/etc/passwd' 的文件格式和语法修正以及存在的群组
newgrp group_name     #登陆进一个新的群组以改变新创建文件的预设群组

8: 打包和压缩文件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
bunzip2 file1.bz2   #解压一个叫做 'file1.bz2'的文件
bzip2 file1         #压缩一个叫做 'file1' 的文件
gunzip file1.gz     #解压一个叫做 'file1.gz'的文件
gzip file1          #压缩一个叫做 'file1'的文件
gzip -9 file1       #最大程度压缩

rar a file1.rar test_file          #创建一个叫做 'file1.rar' 的包
rar a file1.rar file1 file2 dir1   #同时压缩 'file1', 'file2' 以及目录 'dir1'
rar x file1.rar     #解压rar包
unrar x file1.rar   #解压rar包

tar -cvf archive.tar file1   #创建一个非压缩的 tarball
tar -cvf archive.tar file1 file2 dir1  #创建一个包含了 'file1', 'file2' 以及 'dir1'的档案文件
tar -tf archive.tar    #显示一个包中的内容
tar -xvf archive.tar   #释放一个包
tar -xvf archive.tar -C /tmp     #将压缩包释放到 /tmp目录下
tar -cvfj archive.tar.bz2 dir1   #创建一个bzip2格式的压缩包
tar -jxvf archive.tar.bz2        #解压一个bzip2格式的压缩包
tar -cvfz archive.tar.gz dir1    #创建一个gzip格式的压缩包
tar -zxvf archive.tar.gz         #解压一个gzip格式的压缩包

zip file1.zip file1    #创建一个zip格式的压缩包
zip -r file1.zip file1 file2 dir1    #将几个文件和目录同时压缩成一个zip格式的压缩包
unzip file1.zip    #解压一个zip格式压缩包

9: linux 包管理器

9.1 RPM 包 - (Fedora, Redhat 及类似系统)

 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
rpm -ivh package.rpm    #安装一个rpm包
rpm -ivh --nodeeps package.rpm   #安装一个rpm包而忽略依赖关系警告
rpm -U package.rpm        #更新一个rpm包但不改变其配置文件
rpm -F package.rpm        #更新一个确定已经安装的rpm包
rpm -e package_name.rpm   #删除一个rpm包
rpm -qa      #显示系统中所有已经安装的rpm包
rpm -qa | grep httpd    #显示所有名称中包含 "httpd" 字样的rpm包
rpm -qi package_name    #获取一个已安装包的特殊信息
rpm -qg "System Environment/Daemons"     #显示一个组件的rpm包
rpm -ql package_name       #显示一个已经安装的rpm包提供的文件列表
rpm -qc package_name       #显示一个已经安装的rpm包提供的配置文件列表
rpm -q package_name --whatrequires     #显示与一个rpm包存在依赖关系的列表
rpm -q package_name --whatprovides    #显示一个rpm包所占的体积
rpm -q package_name --scripts         #显示在安装/删除期间所执行的脚本l
rpm -q package_name --changelog       #显示一个rpm包的修改历史
rpm -qf /etc/httpd/conf/httpd.conf    #确认所给的文件由哪个rpm包所提供
rpm -qp package.rpm -l    #显示由一个尚未安装的rpm包提供的文件列表
rpm --import /media/cdrom/RPM-GPG-KEY    #导入公钥数字证书
rpm --checksig package.rpm      #确认一个rpm包的完整性
rpm -qa gpg-pubkey      #确认已安装的所有rpm包的完整性
rpm -V package_name     #检查文件尺寸、 许可、类型、所有者、群组、MD5检查以及最后修改时间
rpm -Va                 #检查系统中所有已安装的rpm包- 小心使用
rpm -Vp package.rpm     #确认一个rpm包还未安装
rpm2cpio package.rpm | cpio --extract --make-directories *bin*   #从一个rpm包运行可执行文件
rpm -ivh /usr/src/redhat/RPMS/`arch`/package.rpm    #从一个rpm源码安装一个构建好的包
rpmbuild --rebuild package_name.src.rpm       #从一个rpm源码构建一个 rpm 包

9.2 YUM 软件包升级器 - (Fedora, RedHat 及类似系统)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
yum install package_name             #下载并安装一个rpm包
yum localinstall package_name.rpm    #将安装一个rpm包,使用你自己的软件仓库为你解决所有依赖关系
yum update package_name.rpm    #更新当前系统中所有安装的rpm包
yum update package_name        #更新一个rpm包
yum remove package_name        #删除一个rpm包
yum list                   #列出当前系统中安装的所有包
yum search package_name     #在rpm仓库中搜寻软件包
yum clean packages          #清理rpm缓存删除下载的包
yum clean headers           #删除所有头文件
yum clean all                #删除所有缓存的包和头文件

9.3 DEB 包 (Debian, Ubuntu 以及类似系统)

1
2
3
4
5
6
7
8
dpkg -i package.deb     #安装/更新一个 deb 包
dpkg -r package_name    #从系统删除一个 deb 包
dpkg -l                 #显示系统中所有已经安装的 deb 包
dpkg -l | grep httpd    #显示所有名称中包含 "httpd" 字样的deb包
dpkg -s package_name    #获得已经安装在系统中一个特殊包的信息
dpkg -L package_name    #显示系统中已经安装的一个deb包所提供的文件列表
dpkg --contents package.deb    #显示尚未安装的一个包所提供的文件列表
dpkg -S /bin/ping              #确认所给的文件由哪个deb包提供

9.4 APT 软件工具 (Debian, Ubuntu 以及类似系统)

1
2
3
4
5
6
7
8
apt-get install package_name      #安装/更新一个 deb 包
apt-cdrom install package_name    #从光盘安装/更新一个 deb 包
apt-get update      #升级列表中的软件包
apt-get upgrade     #升级所有已安装的软件
apt-get remove package_name     #从系统删除一个deb包
apt-get check     #确认依赖的软件仓库正确
apt-get clean     #从下载的软件包中清理缓存
apt-cache search searched-package    #返回包含所要搜索字符串的软件包名称

10: 查看文件内容

1
2
3
4
5
6
7
cat file1      #从第一个字节开始正向查看文件的内容
tac file1      #从最后一行开始反向查看一个文件的内容
more file1     #查看一个长文件的内容
less file1     #类似于 'more' 命令,但是它允许在文件中和正向操作一样的反向操作
head -2 file1    #查看一个文件的前两行
tail -2 file1    #查看一个文件的最后两行
tail -f /var/log/messages     #实时查看被添加到一个文件中的内容

11: 文本处理

 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
32
33
34
35
36
37
38
39
40
41
cat file1 file2 ... | command <> file1_in.txt_or_file1_out.txt general syntax for text manipulation using PIPE, STDIN and STDOUT

cat file1 | command( sed, grep, awk, grep, etc...) > result.txt
#合并一个文件的详细说明文本,并将简介写入一个新文件中
cat file1 | command( sed, grep, awk, grep, etc...) >> result.txt
#合并一个文件的详细说明文本,并将简介写入一个已有的文件中

grep Aug /var/log/messages     #在文件 '/var/log/messages'中查找关键词"Aug"
grep ^Aug /var/log/messages    #在文件 '/var/log/messages'中查找以"Aug"开始的词汇
grep [0-9] /var/log/messages   #选择 '/var/log/messages' 文件中所有包含数字的行
grep Aug -R /var/log/*         #在目录 '/var/log' 及随后的目录中搜索字符串"Aug"

sed 's/stringa1/stringa2/g' example.txt
#将example.txt文件中的 "string1" 替换成 "string2"
sed '/^$/d' example.txt           #从example.txt文件中删除所有空白行
sed '/ *#/d; /^$/d' example.txt   #从example.txt文件中删除所有注释和空白行
echo 'esempio' | tr '[:lower:]' '[:upper:]'    #合并上下单元格内容
sed -e '1d' result.txt          #从文件example.txt 中排除第一行
sed -n '/stringa1/p'            #查看只包含词汇 "string1"的行
sed -e 's/ *$//' example.txt    #删除每一行最后的空白字符
sed -e 's/stringa1//g' example.txt
#从文档中只删除词汇 "string1" 并保留剩余全部
sed -n '1,5p;5q' example.txt     #查看从第一行到第5行内容
sed -n '5p;5q' example.txt       #查看第5行
sed -e 's/00*/0/g' example.txt   #用单个零替换多个零

cat -n file1       #标示文件的行数
cat example.txt | awk 'NR%2==1'      #删除example.txt文件中的所有偶数行
echo a b c | awk '{print $1}'        #查看一行第一栏
echo a b c | awk '{print $1,$3}'     #查看一行的第一和第三栏
paste file1 file2           #合并两个文件或两栏的内容
paste -d '+' file1 file2    #合并两个文件或两栏的内容,中间用"+"区分

sort file1 file2              #排序两个文件的内容
sort file1 file2 | uniq       #取出两个文件的并集(重复的行只保留一份)
sort file1 file2 | uniq -u    #删除交集,留下其他的行
sort file1 file2 | uniq -d    #取出两个文件的交集(只留下同时存在于两个文件中的文件)

comm -1 file1 file2    #比较两个文件的内容只删除 'file1' 所包含的内容
comm -2 file1 file2    #比较两个文件的内容只删除 'file2' 所包含的内容
comm -3 file1 file2    #比较两个文件的内容只删除两个文件共有的部分

go将html转为image图片

go将html转为image图片

1: 概述

2: go 代码

  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
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package pkgs

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"time"
)

// 用于从 HTML/CSS 生成高质量图像的 API
// https://docs.htmlcsstoimage.com/
const (
	userID = "c721cbd9-9ddf-4efb-b97c-0616490d98ac"
	apiKey = "aa7c90f4-b2ef-4a6c-85af-e24141c10750"
)

func My_Image() {
	data := map[string]string{
		// "html": `"<div class='ping'>Pong ✅</div>"`,
		"device_scale": "1",
		"html": fmt.Sprintf(`
<div style="height: 455px; width: 1068px;  ">
    <style>
        .line {
            background-color: #f2f2f2;
        }
    </style>
    <table border: 1px solid;>
        <tr class='title' bgcolor='#008888'>
            <th style="width: 100px;">Host</th>
            <th style="width: 150px;">Account</th>
            <th style="width: 50px;">StatusCode</th>
            <th style="width: 100px;">Status</th>
            <th style="width: 666px;">ErrMsg</th>
        </tr>
        <tr class='line' >
            <td>192.168.8.1</td>
            <td>mshw_ms03</td>
            <td>1</td>
            <td>PENDING_CANCEL</td>
            <td>INVALID_BOC_TYPE_BY_CLIENT</td>
        </tr>
        <tr class='line'>
            <td>192.168.8.3</td>
            <td>mshw_baml18</td>
            <td>2</td>
            <td>REJECTED</td>
            <td>99 : 2043 Invalid order price!</td>
        </tr>
        <tr class='line' >
            <td>192.168.8.3</td>
            <td>mshw_baml18</td>
            <td>3</td>
            <td>REJECTED</td>
            <td>99 : 2043 Invalid order price!</td>
        </tr>
        <tr class='line' >
            <td>192.168.8.3</td>
            <td>mshw_baml18</td>
            <td>4</td>
            <td>REJECTED</td>
            <td>99 : 2043 Invalid order price!</td>
        </tr>
        <tr class='line' >
            <td>192.168.8.3</td>
            <td>mshw_baml18</td>
            <td>5</td>
            <td>REJECTED</td>
            <td>99 : 2043 Invalid order price!</td>
        </tr>
        <tr class='line' >
            <td>192.168.8.3</td>
            <td>mshw_baml18</td>
            <td>6</td>
            <td>REJECTED</td>
            <td>99 : 2043 Invalid order price!</td>
        </tr>
        <tr class='line' >
            <td>192.168.8.3</td>
            <td>mshw_baml18</td>
            <td>1</td>
            <td>REJECTED</td>
            <td>99 : 2043 Invalid order price!</td>
        </tr>
        <tr class='line' >
            <td>192.168.8.3</td>
            <td>mshw_baml18</td>
            <td>2</td>
            <td>REJECTED</td>
            <td>99 : 2043 Invalid order price!</td>
        </tr>
    </table>
</div>`),
	}

	reqBody, err := json.Marshal(data)
	if err != nil {
		log.Fatalf("unable to marshal data: %s", err.Error())
	}
	req, err := http.NewRequest("POST", "https://hcti.io/v1/image", bytes.NewReader(reqBody))
	if err != nil {
		log.Fatalf("unable to create new request: %s", err.Error())
	}
	req.SetBasicAuth(userID, apiKey)
	client := &http.Client{Timeout: time.Second * 10}
	resp, err := client.Do(req)
	if err != nil {
		log.Fatalf("request was unsuccessful: %s", err.Error())
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatalf("unable to read response body: %s", err.Error())
	}
	fmt.Println(string(body)) // 在线online图片的连接
}

007-Cpp debug 工具dbg-macro

Cpp debug 工具dbg-macro

1: 介绍

  • https://github.com/sharkdp/dbg-macro
  • 打日志是 C++ 开发中必不可少的一种 debug 方式,dbg-macro 受 Rust 语言中 的 dbg 启发,提供比 printf 和 std::cout 更好的宏函数。主要有如下特点:
    • 美观的彩色输出(当输出不是交互式终端时,颜色将自动禁用)
    • 兼容 C++11,并且是 header-only
    • 支持基础类型和 STL 容器类型的输出
    • 可以输出文件名、行号、函数名和原始表达式

2:install

1
2
git clone https://github.com/sharkdp/dbg-macro
sudo ln -s $(readlink -f dbg-macro/dbg.h) /usr/include/dbg.h

2.1 On Arch Linux

  • yay -S dbg-macro

2.2 With vcpkg

  • vcpkg install dbg-macro

2.3 With cmake

  • CMakeLists.txt
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
cmake_minimum_required(VERSION 3.11) # FetchContent added in cmake 3.11
project(app) # name of executable

set(CMAKE_CXX_STANDARD 17)

# dbg-macro
include(FetchContent)

FetchContent_Declare(dbg_macro GIT_REPOSITORY https://github.com/sharkdp/dbg-macro)
FetchContent_MakeAvailable(dbg_macro)

add_executable(${PROJECT_NAME} main.cpp) # your source files goes here
target_link_libraries(${PROJECT_NAME} PRIVATE dbg_macro) # make dbg.h available
  • main.cpp