最近文章

Go语言高效拼接字符串

strings.BuilderGo 1.10以及以后版本使用strings.Builder,Builder在实现上有以下特点:最大限度地减少内存复制。零值(zero-value)可以直接使用,不需要初始化。示例:package main import ( "strings" "fmt" ) func main() { // 此处是zero value,不需要做初始化就可
标签:

windows批处理操作bat命令

Windows环境下运行bat指令-Windows下 初始化MySQL SQL 文件@echo off start cmd /k "echo initmysql && title init-mysql && cd/d D:softmysql-5.7.26-winx64bin && mysql -h localhost -uroot -
标签:

免费GPU平台colab与aistudio体验对比

查看OS版本!cat /etc/issueUbuntu 18.04.2 LTS n l 查看显卡配置 !nvidia-smi Thu Aug 8 10:10:22 2019 +-----------------------------------------------------------------------------+ | NVID
标签:

Ubuntu安装docker报错:E: Package 'containerd.io' has no installation candidate

Ubuntu版本:19.10按照docker官网的安装方法,在Ubuntu上按装docker时报错:Package containerd.io is not available, but is referred to by another package.This may mean that the package is missing, has been obsoleted, oris only
标签:

Linux查看显卡信息

Linux的lspci命令可以列出目前主机上面的硬件配备,vga则表示显卡。列出显卡信息如下:$ lspci | grep -i vga02:00.0 VGA compatible controller: NVIDIA Corporation GP102 [TITAN Xp] (rev a1)03:00.0 VGA compatible controller: NVIDIA Corporation
标签:

Linux查看GPU使用情况

Nvidia自带的nvidia-smi命令行工具,可以查看GPU的使用情况:nvidia-smi使用watch指令可以周期监控GPU的使用情况:watch -n 10 nvidia-smi-n选项后面指定执行命令的周期,以s为单位。 显示的信息分为两部分:第一部分:各块GPU使用情况,比如温度,显存,GPU利用率第二部分(Processes):使用GPU的进程及占用显存
标签:

Linux查看及修改系统的资源限制命令ulimit

在Linux,查看系统对资源使用的显示可以使用命令ulimit,其中参数-a会列出所有的资源使用限制。[demo@server ~]$ ulimit -acore file size (blocks, -c) 0data seg size (kbytes, -d) unlimitedscheduling priority (-e) 0f
标签:

Shell脚本书写规范

在日常的运维工作中,Shell脚本肯定是必不可少的工作内容。为方便问题排查、脚本执行历史问题追踪、方便大家共同维护,从网上搜罗结合以往的经验教训拟定以下Bash脚本书写规范。欢迎各位同学指正或补充。代码风格规范开头有“蛇棒”所谓shebang其实就是在很多脚本的第一行出现的以”#!”开头的注释,他指明了当我们没有指定解释器的时候默认的解释器,一般可能是下面这样:#!/bin/bash当然,解释器有
标签:

curl发送post请求的有用示例(包括json)

curl用法下面这些是使用curl来发送POST或PUT请求的常见选项:1、请求类型-X POST-X PUT2、Content Type头信息-H "Content-Type: application/x-www-form-urlencoded":发送form表单-H "Content-Type: application/json":发送json数据3、数据传递form表单:-d "param1
标签:

CentOS:yum安装rz和sz上传下载文件

安装$sudo yum install -y lrzsz rz使用rz上传本地文件到服务$rz 执行命令后,在弹出框中选择要上传的文件即可。sz下载服务器的文件到本地$sz filepath 设置默认本地上传下载目录SecureCRT软件 -> Options -> session op
标签:

Nginx配置ssl_client_certificate客户端认证问题

问题1: ssl_client_certificate 配置的CA证书格式错误参考Mini tutorial for configuring client-side SSL certificates和Client Side Certificate Auth in Ngi
标签:

Nginx配置客户端(浏览器)SSL证书认证简明教程(自签名证书)

本文介绍自签名的证书方式,与签名相关的文件包括:cer/crt:证书文件,Linux习惯用crt作为后缀,Windows用cer作为后缀。key:私钥文件csr(Certificate Signing Request):证书签名请求创建CA根证书CA证书用于签署客户端证书。sudo openssl genrsa -des3 -out ca.key&
标签:

Linux统计目录下所有文件的行数

这里提供两种方法来统计目录下所有文件的行数:1、结合使用find和wc:find . -name '*.pl' | xargs wc -l 另外,此命令也可以改为:( find ./ -name '*.pl' -print0 | xargs -0&n
标签:

Linux查看内存占用

在Linux可以使用这两个命令查看内存占用:top,pmaptoptop是linux常用的性能分析工具,可以查看各个进程的资源占用情况。$top top - 21:52:03 up 521 days,  4:59,  2 users,  load average: 0.02, 0
标签:

Windows查看端口占用的进程

Windows netstat在Linux我们可以使用netstat查看网络状态,包括端口占用的进程。在window也是可以使用netstat命令查看端口占用的进程。打开windows的终端:开始->运行-> 输入cmd,回车->进入cmd 执行C:\> netstat -ano -a:显示所有连接和监听的端口-n:以数字的形式显示地
标签:

Shell脚本使用curl命令发送JSON数据

在Linux使用命令行工具curl发送JSON数据需要把content-type设置为“application/json”。-H "Content-Type: application/json 示例curl -H "Content-Type: application/json" -X POST&nb
标签:

CentOS 7更新为阿里云yum源

进入yum源的目录centos 7yum源目录为/etc/yum.repos.d$cd /etc/yum.repos.d 备份yum源在更新centos 7的yum源前先备份。$ sudo cp CentOS-Base.repo backup/ 如果没有bakcup目录先创建。下载阿里云yum源阿里云yum源列表:http://
标签:

CentOS 7安装Docker环境

在CentOS上有两种方式安装Docke:https://get.docker.com/联网脚本安装使用yum安装联网脚本安装1、更新yum源sudo yum update 2、联网下载脚本安装curl -sSL https://get.docker.com/ | sh 使用yum安装1、更新yum源sudo yum 
标签:

Linux使用grep查找文本所在的所有文件

显示所在文件及匹配到的文本grep -rin 'search' /path/  -r/-R:递归遍历目录-i:忽略大小写-n:显示出现在文件的行号仅显示所在文件grep -ril 'search' /path/ -l:显示所在的文件,而不是匹配到的文本包含/排除目录可以使用--exclude, --include, --excl
标签:

Linux Shell脚本里的单引号和双引号的区别

双引号在Shell脚本里,双引号里的字符,除$、\、’、和”这几个字符是特殊字符并保留其特殊功能外,其余字符作为普通字符对待。在双引号内支持内插变量,使用$符号表示。支持内插转义,使用反斜杠\做转,对于在双引号内的"需要使用反斜杠转义。单引号在Shell脚本里,单引号内的字符都为普通字符,不支持内插任何东西,即使是使用反斜杠对单引号做的转义也不行。示例:#!/bin/sh MYVAR=t
标签:

Ubuntu使用apt-get安装软件禁用交互模式

apt-get启动非交互模式:设置DEBIAN_FRONTEND为noninteractive使用apt-get安装软件包添加-y,-q参数export DEBIAN_FRONTEND=noninteractive apt-get -y -q install [packagename] 使用sudo命令sudo DEBIAN_FRONTE
标签:

Linux查找占用指定端口的进程

在Linux有多种方案。lsoflsof -i tcp:80 列出使用tcp连接80端口的进程不指定协议lsof -i :80 netstatsudo netstat -nlp 列出所有打开的网络连接
标签:

Linux:使用visudo设置用户sudo权限

visudo我们可以修改/etc/sudoers文件来设置用户的sudo权限,修改/etc/sudoers一定要使用visudo命令,它可以让我们比较安全的修改此文件。visudo有以下特性:锁定文件避免多个同时编辑检查语法的完整性检查解析错误,以避免用户错误输入使用root的权限直接执行visudo,打开suders文件$visudo 注意:这里不需要输入shduers文件的路径,默认为/etc
标签:

Linux命令useradd添加用户的默认值说明

Linux添加用户的命令useradd会使用选项指定的值在加上默认文件/etc/default/useradd设置的值初始化新增的用户。这里将对useradd的默认值做下说明。查看默认值[root@xxx home]# useradd -D GROUP=100 HOME=/home INACTIVE=-1 EXPIRE= SHELL=/bin/bash SKEL=/e
标签:

CentOS 6/7修改主机名hostname

CentOS 7 RHEL 7新增了hostnamectl命令,基于RHEL 7的CentOS 7相应的可以使用hostnamectl来修改主机名。hostnamectl把主机名分为以下三种:静态主机名:hostnamectl用来在系统启动时初始化内核的主机名。瞬态主机名:由DHCP等一些系统临时分配的主机名,如果系统存在静态主机名且有效,则不会用到瞬态主机
标签:

Linux下查看进程所使用的环境变量

在Linux下直接执行env命令即可获取当前的环境变量[xxxx ~]$$ env HOSTNAME=iZ94lykym6iZ TERM=linux SHELL=/bin/bash HISTSIZE=1000 ... 进程的环境变量可以在/proc/<pid>/environ查看,其中<pid>为进程id获取进程id使用ps获取pid[xxxx 
标签:

ACL(access control lists)配置0.0.0.0/0 和::/0的区别

0.0.0.0/0 和::/0的区别在于前者为ip4地址,后者为ip6地址0.0.0.0/0 :表示所有可能的IP4地址::/0:表示所有可能的IP6地址,包括所有的IP4地址,因为IP4地址可以映射为IP6地址。
标签:

SSH 禁止特定用户使用密码登录

SSH禁止特定用户使用密码登录可以在/etc/ssh/sshd_config添加Match配置过滤指定的用户。按用户过滤Match User user1,user2,user3,user4     PasswordAuthentication no 按组过滤Match Group group1  &
标签:

Go语言高效拼接字符串

发布于 2022.04.25 2分钟阅读 0 评论 5 推荐

    Golang

    作者: 胡学义
  1. Go语言高效拼接字符串 Page 1

strings.Builder

Go 1.10以及以后版本使用strings.Builder,Builder在实现上有以下特点:

  1. 最大限度地减少内存复制。
  2. 零值(zero-value)可以直接使用,不需要初始化。

示例:

package main

import (
    "strings"
    "fmt"
)

func main() {
    // 此处是zero value,不需要做初始化就可以使用。
    var sb strings.Builder

    for i := 0; i < 1000; i++ {
        sb.WriteString("a")
    }

    fmt.Println(sb.String())
}

bytes.Buffer

Go 1.10之前的版本使用bytes.Buffer,使用示例:

package main

import (
    "bytes"
    "fmt"
)

func main() {
    var buffer bytes.Buffer

    for i := 0; i < 1000; i++ {
        buffer.WriteString("a")
    }

    fmt.Println(buffer.String())
}

 

windows批处理操作bat命令

Windows环境下运行bat指令

-Windows下 初始化MySQL SQL 文件


@echo off 
start cmd /k "echo initmysql && title init-mysql && cd/d D:softmysql-5.7.26-winx64bin && mysql -h localhost -uroot -pnrqzdhlscx2 -Dtest < D:softinitmysql.sql"

windows 下,打开多个窗口运行springboot jar包

@echo off 
start cmd /c "echo Starting graph-eureka-server && title graph-eureka-server && java -jar D:softjava-servicegraph-eureka-server.jar "
start cmd /c "echo Starting link-excel && title link-excel && java -Dfile.encoding=UTF-8 -jar D:softjava-servicelink-excel.jar"
start cmd /c "echo Starting link-web && title link-web && java -jar D:softjava-servicelink-web.jar"
start cmd /c "echo Starting link-graph1 && title link-graph1 && java -jar D:softjava-servicelink-graph1.jar"

Windows 下关闭多个Java 虚拟机

taskkill /f /t /fi  "imagename eq java.exe"

备注

1、echo 命令

打开回显或关闭请求回显功能,或显示消息。如果没有任何参数,echo 命令将显示当前回显设置。

语法

echo [{ on|off }] [message]

2、rem 命令,注释,代表此行不会执行

rem 这是一个注释

3、pause 命令

这是一个暂停指令,按任意键继续

4、start 命令

Start语法

start [“title”] [/dPath] [/min] [/max] [{/separate |/shared}] [{/low | /normal | /high | /realtime | /abovenormal | belownormal}][/wait] [/B] [FileName] [parameters]

启动单独的“命令提示符”窗口来运行指定程序或命令。如果在没有参数的情况下使用,start 将打开第二个命令提示符窗口。

start cmd/c 打开新窗口执行指令后关闭窗口

start cmd/k 打开新窗口执行指令后,保持新窗口

title 新窗口的标题名称

5、taskkill 指令,使用该工具按照进程 ID (PID) 或映像名称终止任务。

TASKKILL [/S system [/U username [/P [password]]]]   
{ [/FI filter] [/PID processid | /IM imagename] } [/T] [/F]

1. /S system 指定要连接的远程系统。

2. /U [domain]user 指定应该在哪个用户上下文执行这个命令。

3. /P [password] 为提供的用户上下文指定密码。如果忽略,提示输入。

4. /FI filter 应用筛选器以选择一组任务。允许使用 "*"。例如,映像名称 eq acme*

5. /PID processid 指定要终止的进程的 PID。使用 TaskList 取得 PID。

6. /IM imagename 指定要终止的进程的映像名称。通配符 '*'可用来 指定所有任务或映像名称。

7. /T 终止指定的进程和由它启用的子进程。

8. /F 指定强制终止进程。

9. /? 显示帮助消息

例子,杀死对应进程:

taskkill /pid pid
taskkill /im xxx.exe
taskkill /fi “imagename eq xxx.exe”
taskkill /fi “pid eq pid”

免费GPU平台colab与aistudio体验对比

查看OS版本

!cat /etc/issue
Ubuntu 18.04.2 LTS n l

查看显卡配置

!nvidia-smi
Thu Aug  8 10:10:22 2019       
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 418.67       Driver Version: 410.79       CUDA Version: 10.0     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  Tesla T4            Off  | 00000000:00:04.0 Off |                    0 |
| N/A   67C    P0    30W /  70W |    237MiB / 15079MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
                                                                               
+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
+-----------------------------------------------------------------------------+

查看cuda版本

!nvcc -V

nvcc: NVIDIA (R) Cuda compiler driver

Copyright (c) 2005-2018 NVIDIA Corporation

Built on Sat_Aug_25_21:08:01_CDT_2018

Cuda compilation tools, release 10.0, V10.0.130

查看cudnn版本


!cat /usr/include/cudnn.h | grep CUDNN_MAJOR -A 2

#define CUDNN_MAJOR 7

#define CUDNN_MINOR 6

#define CUDNN_PATCHLEVEL 2

--

#define CUDNN_VERSION (CUDNN_MAJOR * 1000 + CUDNN_MINOR * 100 + CUDNN_PATCHLEVEL)

#include "driver_types.h"

  • tensorflow的使用
import tensorflow as tf
print(tf.test.is_gpu_available())
print(tf.__version__)
True
1.14.0

百度aistudio

查看OS版本

!cat /etc/issue
Ubuntu 16.04.6 LTS n l

查看显卡

!nvidia-smi
Thu Aug  8 20:26:10 2019       
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 396.37                 Driver Version: 396.37                    |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  Tesla V100-SXM2...  Off  | 00000000:00:07.0 Off |                    0 |
| N/A   34C    P0    41W / 300W |      0MiB / 16160MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
                                                                               
+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
|  No running processes found                                                 |
+-----------------------------------------------------------------------------+

查看cuda版本

!nvcc -V
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2018 NVIDIA Corporation
Built on Tue_Jun_12_23:07:04_CDT_2018
Cuda compilation tools, release 9.2, V9.2.148

说明

cuda9.2这个版本对任何gpu版本的tensorflow都无法适配。。 期待百度那边早日升级cuda版本到10.0

查看cudnn版本

!cat /usr/include/cudnn.h | grep CUDNN_MAJOR -A 2
#define CUDNN_MAJOR 7
#define CUDNN_MINOR 3
#define CUDNN_PATCHLEVEL 1
--
#define CUDNN_VERSION (CUDNN_MAJOR * 1000 + CUDNN_MINOR * 100 + CUDNN_PATCHLEVEL)

#include "driver_types.h"

tensorflow的使用(需手动安装)

!pip install tensorflow-gpu 

说明

  • 不指定版本的话,默认下载最新版本。import tensorflow不报错,但无可用的gpu,tensorflow检测不到相应版本的cuda包,自动切换到cpu版本
  • !pip install tensorflow-gpu==1.12.0 后,import tensorflow 报错,提示需要cuda9.0,实际已装cuda9.2,cuda版本不匹配
  • 高版本(1.14.0/1.13.1)的gpu需要cuda10.0,低版本(1.5.0-1.12.0)的gpu需要cuda9.0
import tensorflow as tf
print(tf.test.is_gpu_available())
print(tf.__version__)
False
1.14.0

总结对比

  • colab环境较新,对tensorflow支持的较好。但是不支持数据的存储,断开重连后数据会丢失
  • aistudio支持数据的存储,断开重连后数据还在。但运行环境只对自家的paddle适配的好,不自带tensorflow的包,每次重启需重新下载,且目前cuda的版本无法适配任何一版gpu的tensorflow

参考

Ubuntu安装docker报错:E: Package 'containerd.io' has no installation candidate

Ubuntu版本:19.10

按照docker官网的安装方法,在Ubuntu上按装docker时报错:

Package containerd.io is not available, but is referred to by another package.
This may mean that the package is missing, has been obsoleted, or
is only available from another source
E: Package 'containerd.io' has no installation candidate

原因是执行命令

$ sudo add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable"

其中:$(lsb_release -cs)返回的“eoan”即Ubuntu 19.10。猜测可能是Ubuntu 19.10的问题,替换为表示ubuntu 18.10的“bionic”,如下:

$ sudo add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
bionic \
stable"

为了避免冲突,记得修改“/etc/apt/sources.list”,注释掉

deb-src [arch=amd64] https://download.docker.com/linux/ubuntu eoan stable



Linux查看显卡信息

Linux的lspci命令可以列出目前主机上面的硬件配备,vga则表示显卡。

列出显卡信息如下:

$ lspci | grep -i vga
02:00.0 VGA compatible controller: NVIDIA Corporation GP102 [TITAN Xp] (rev a1)
03:00.0 VGA compatible controller: NVIDIA Corporation GP102 [TITAN Xp] (rev a1)
06:00.0 VGA compatible controller: ASPEED Technology, Inc. ASPEED Graphics Family (rev 30)
83:00.0 VGA compatible controller: NVIDIA Corporation GP102 [TITAN Xp] (rev a1)

其中,每一行开头为每一个硬件设备的序号,如02:00.0,03:00.0等。

通过序号查看显卡的详细信息:

lspci通过-s指定序号,如示例里的02:00.0

$ lspci -v -s 02:00.0
02:00.0 VGA compatible controller: NVIDIA Corporation GP102 [TITAN Xp] (rev a1) (prog-if 00 [VGA controller])
        Subsystem: NVIDIA Corporation Device 11df
        Physical Slot: 2
        Flags: bus master, fast devsel, latency 0, IRQ 104, NUMA node 0
        Memory at cf000000 (32-bit, non-prefetchable) [size=16M]
        Memory at 383fe0000000 (64-bit, prefetchable) [size=256M]
        Memory at 383ff0000000 (64-bit, prefetchable) [size=32M]
        I/O ports at 5000 [size=128]
        [virtual] Expansion ROM at d0000000 [disabled] [size=512K]
        Capabilities: <access denied>
        Kernel driver in use: nvidia
        Kernel modules: nouveau, nvidia_drm, nvidia


Linux查看GPU使用情况

Nvidia自带的nvidia-smi命令行工具,可以查看GPU的使用情况:

nvidia-smi

使用watch指令可以周期监控GPU的使用情况:

watch -n 10 nvidia-smi

-n选项后面指定执行命令的周期,以s为单位。

显示的信息分为两部分:

  • 第一部分:各块GPU使用情况,比如温度,显存,GPU利用率
  • 第二部分(Processes):使用GPU的进程及占用显存大小

第一部分表头说明:

  • Fan:显示风扇转速,数值在0到100%之间,是计算机的期望转速,如果计算机不是通过风扇冷却或者风扇坏了,显示出来就是N/A; 
  • Temp:显卡内部的温度,单位是摄氏度;
  • Perf:表征性能状态,从P0到P12,P0表示最大性能,P12表示状态最小性能;
  • Pwr:能耗表示; 
  • Bus-Id:涉及GPU总线的相关信息; 
  • Disp.A:是Display Active的意思,表示GPU的显示是否初始化; 
  • Memory Usage:显存占用情况; 
  • Volatile GPU-Util:浮动的GPU利用率;
  • Compute M:计算模式; 

Linux查看及修改系统的资源限制命令ulimit

在Linux,查看系统对资源使用的显示可以使用命令ulimit,其中参数-a会列出所有的资源使用限制。

[demo@server ~]$ ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 2055823
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 65535
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 4096
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited

修改系统的资源对用户的使用限制

资源对用户的使用限制在/etc/security/limits.conf文件里配置。如下:

demo@server:~$ cat /etc/security/limits.conf   
# /etc/security/limits.conf
#
#Each line describes a limit for a user in the form:
#
#<domain> <type> <item> <value>
#
#Where:
#<domain> can be:
# - an user name
# - a group name, with @group syntax
# - the wildcard *, for default entry
# - the wildcard %, can be also used with %group syntax,
# for maxlogin limit
#
#<type> can have the two values:
# - "soft" for enforcing the soft limits # 软限制,必须必硬限制的值要小
# - "hard" for enforcing hard limits # 硬限制
#
#<item> can be one of the following:
# - core - limits the core file size (KB)
# - data - max data size (KB)
# - fsize - maximum filesize (KB)
# - memlock - max locked-in-memory address space (KB)
# - nofile - max number of open files # 最大打开的文件数(以文件描叙符,file descripter计数)
# - rss - max resident set size (KB)
# - stack - max stack size (KB)
# - cpu - max CPU time (MIN)
# - nproc - max number of processes
# - as - address space limit
# - maxlogins - max number of logins for this user
# - maxsyslogins - max number of logins on the system
# - priority - the priority to run user process with
# - locks - max number of file locks the user can hold
# - sigpending - max number of pending signals
# - msgqueue - max memory used by POSIX message queues (bytes)
# - nice - max nice priority allowed to raise to
# - rtprio - max realtime priority
#
#<domain> <type> <item> <value>
#
root soft nofile 200000
root hard nofile 200000
admin hard nofile 65536
admin soft nofile 65536
# End of file  

对资源使用限制的配置是针对用户或者用户组,每行格式如下:

用户名/用户组 类型(硬限制hard、软限制soft) 选项 值

其中类型的值可以为hard,soft或者“-”,其中“-”相当于同时配置了hard和soft两行。

注意:退出重新登录后,配置生效

Shell脚本书写规范

在日常的运维工作中,Shell脚本肯定是必不可少的工作内容。为方便问题排查、脚本执行历史问题追踪、方便大家共同维护,从网上搜罗结合以往的经验教训拟定以下Bash脚本书写规范。欢迎各位同学指正或补充。

代码风格规范

开头有“蛇棒”

所谓shebang其实就是在很多脚本的第一行出现的以”#!”开头的注释,他指明了当我们没有指定解释器的时候默认的解释器,一般可能是下面这样:

#!/bin/bash

当然,解释器有很多种,除了bash之外,我们可以用下面的命令查看本机支持的解释器:

[root@thatsit 00:20:11 ~]# cat /etc/shells
/bin/sh
/bin/bash
/sbin/nologin
/bin/dash
/bin/tcsh
/bin/csh
/usr/bin/tmux
[root@thatsit 00:28:32 ~]#

当我们直接使用./a.sh来执行这个脚本的时候,如果没有shebang,那么它就会默认用$SHELL指定的解释器,否则就会用shebang指定的解释器。

不过,上面这种写法可能不太具备适应性,一般我们会用下面的方式来指定:

#!/usr/bin/env bash

代码有注释

注释,显然是一个常识,不过这里还是要再强调一下,这个在shell脚本里尤为重要。因为很多单行的shell命令不是那么浅显易懂,没有注释的话在维护起来会让人尤其的头大。

注释的意义不仅在于解释用途,而在于告诉我们注意事项,就像是一个README。

具体的来说,对于shell脚本,注释一般包括下面几个部分:

  1. shebang
  2. 脚本的参数
  3. 脚本的用途
  4. 脚本的用法及注意事项
  5. 脚本试用平台
  6. 脚本的写作时间,作者,版权等
  7. 各个函数前的说明注释
  8. 一些较复杂的单行命令注释

简单脚本头样例

#!/bin/bash
#########################################################
# Function :Rotate application logs #
# Platform :All Linux Based Platform #
# Version :1.0 #
# Date :2017-07-28 #
# Author :Stephen.Shi #
# Contact :sp@meitu.com #
# Company :MeiTu #
#########################################################

参数要规范

这一点很重要,当我们的脚本需要接受参数的时候,我们一定要先判断参数是否合乎规范,并给出合适的回显,方便使用者了解参数的使用。

最少,最少,我们至少得判断下参数的个数吧:

args judgement 姿势1

if [[ $# != 2 ]];then
echo "Parameter incorrect."
exit 1
fi

args judgement 姿势2

# Uasge
help_msg(){
echo "Usage: $0 <server_group_to_operate>"
}
# arg judge
if [[ $# -ne 1 ]]
then
help_msg
else
xxoo_func
fi

环境变量和魔数

一般情况下我们会将一些重要的环境变量定义在开头,确保这些变量的存在。

source /etc/profile
export PATH="/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin:/apps/bin/"

这种定义方式有一个很常见的用途,最典型的应用就是,当我们本地安装了很多java版本时,我们可能需要指定一个java来用。那么这时我们就会在脚本开头重新定义JAVA_HOME以及PATH变量来进行控制。

同时,一段好的代码通常是不会有很多硬编码在代码里的“魔数”的。如果一定要有,通常是用一个变量的形式定义在开头,然后调用的时候直接调用这个变量,这样方便日后的修改。

变量的定义和引用

变量的定义和引用需要遵循一定的规范:

  1. 名称长的变量尽量使用驼峰写法或者使用小写字母+下划线的方式进行命名
  2. 常量的定义推荐使用大写字母进行命名
  3. 在引用变量时为了避免不必要的麻烦,尽量使用${变量名}的方式进行引用

变量名引用的坑的样例

[root@thatsit scripts]$ cat var_test.sh
#!/bin/bash
xx="heiheihei"
xx_="123"
oo="666"
echo $xx$oo
echo "----"
echo $xx_$oo
echo "----"
echo ${xx}_${oo}
[root@thatsit scripts]$ sh var_test.sh
heiheihei666
----
123666
----
heiheihei_666
[root@thatsit scripts]$

缩进有规矩

对于shell脚本,缩进是个大问题。因为很多需要缩进的地方(比如if,for语句)都不长,所有很多人都懒得去缩进,而且很多人不习惯用函数,导致缩进功能被弱化。

其实正确的缩进是很重要的,尤其是在写函数的时候,否则我们在阅读的时候很容易把函数体跟直接执行的命令搞混。

常见的缩进方法主要有”soft tab”和”hard tab”两种。

  • 所谓soft tab就是使用n个空格进行缩进(n通常是2或4)
  • 所谓hard tab当然就是指真实的”\t”字符,这里不去撕哪种方式最好,只能说各有各的优劣。反正我习惯用四个空格(美剧《硅谷》中的男主执着于用tab,并因此跟习惯使用空格的女友分手,哈哈)。

命名有标准

所谓命名规范,基本包含下面这几点:

  1. 文件名规范,以.sh结尾,方便识别
  2. 通过脚本名称最好能够直接读出脚本的用途,比如常用xx服务的启动脚本可命名为start_xx.sh,oo服务的监控脚本可命名为oo_monit.sh,告警脚本可名称为abc_alert.sh
  3. 变量名字要有含义,不要拼错,尽量使用英文,可能显得更专业(ps:逼格高)一点,哈哈
  4. 统一命名风格,用驼峰或者下划线连接,推荐使用小写字母加下划线的方式

编码要统一

在写脚本的时候尽量使用UTF-8编码,能够支持中文等一些奇奇怪怪的字符。

尽管脚本中可以写中文,但是在写注释以及打log的时候还是尽量英文,毕竟有些机器还是没有直接支持中文的,打出来可能会有乱码。

执行权限记得加

小点,却非常重要;不加执行权限经常会导致无法直接执行,尤其是init脚本等。

日志和回显

日志的重要性不必多说,能够方便我们回头纠错,在大型的项目里是非常重要的。

如果这个脚本是供用户直接在命令行使用的,那么我们最好还要能够在执行时实时回显执行过程,方便用户掌控。

有时候为了提高用户体验,可以回显中添加一些特效,比如颜色啊,闪烁啊之类的,具体可以参考ANSI/VT100 Control sequences这篇文章的介绍。

注意:

  1. 一些debug级别的信息,在脚本调试结束后需要关闭。
  2. 日志输出要带时间、要带时间、带时间,在写定时任务用的脚本时尤为重要。
  3. 日志的输出推荐使用tee -a ${log_file}的方式,可以直接在main函数入口处添加日志输出。

脚本日志输出样例

logfile="/var/log/log_clean.log"
# define functions
function xx(){
echo "xx"
}
function oo(){
echo "oo"
}
# define main function
function main(){
xx
oo
}
# invoke main function
main|tee -a ${logfile}

太长要分行

在调用某些程序的时候,参数可能会很长,这时候为了保证较好的阅读体验,我们可以用反斜杠来分行:

./configure \
–prefix=/usr \
–sbin-path=/usr/sbin/nginx \
–conf-path=/etc/nginx/nginx.conf \

注意在反斜杠前有个空格。

代码有效率

在使用命令的时候要了解命令的具体做法,尤其当数据处理量大的时候,要时刻考虑该命令是否会影响效率。

比如下面的两个sed命令:

sed -n '1p' file
sed -n '1p;1q' file

他们的作用一样,都是获取文件的第一行。但是第一条命令会读取整个文件,而第二条命令只读取第一行。当文件很大的时候,仅仅是这样一条命令不一样就会造成巨大的效率差异。

当然,这里只是为了举一个例子,这个例子真正正确的用法应该是使用head -1 file命令。

勤用双引号

几乎所有的大佬都推荐在使用$来获取变量的时候最好加上双引号。

不加上双引号在很多情况下都会造成很大的麻烦,为什么呢?举一个例子:

#!/bin/sh
#已知当前文件夹有一个a.sh的文件
var="*.sh"
echo $var
echo "$var"

他的运行结果如下:

a.sh
*.sh

为啥会这样呢?其实可以解释为他执行了下面的命令:

echo *.sh
echo "*.sh"

在很多情况下,在将变量作为参数的时候,一定要注意上面这一点,仔细体会其中的差异。上面只是一个非常小的例子,实际应用的时候由于这个细节导致的问题实在是太多了。

巧用main函数

我们知道,像java,C这样的编译型语言都会有一个函数入口,这种结构使得代码可读性很强,我们知道哪些直接执行,那些是函数。但是脚本不一样,脚本属于解释性语言,从第一行直接执行到最后一行,如果在这当中命令与函数糅杂在一起,那就非常难读了。

各位同学应该都写过python,因此大家都知道一个合乎标准的python脚本大体上至少是这样的:

#!/usr/bin/env python
def func1():
pass
def func2():
pass
if __name__=='__main__':
func1()
func2()

他用一个很巧妙的方法实现了我们习惯的main函数,使得代码可读性更强。

在shell中,我们也有类似的小技巧:

#!/usr/bin/bash
func1(){
#do sth
}
func2(){
#do sth
}
main(){
func1
func2
}
main "$@"

我们可以采用这种写法,同样实现类似的main函数,使得脚本的结构化程度更好。

另外在传递参数的时候可能会遇到参数接收位置的变化,记得使用shift函数。

考虑作用域

shell中默认的变量作用域都是全局的,比如下面的脚本:

#!/usr/bin/env bash
var=1
func(){
var=2
}
func
echo $var

他的输出结果就是2而不是1,这样显然不符合我们的编码习惯,很容易造成一些问题。

因此,相比直接使用全局变量,我们最好使用local readonly这类的命令,其次我们可以使用declare来声明变量。这些方式都比使用全局方式定义要好。

巧用heredocs

所谓heredocs,也可以算是一种多行输入的方法,即在”<<”后定一个标识符,接着我们可以输入多行内容,直到再次遇到标识符为止。

使用heredocs,我们可以非常方便的生成一些模板文件:

cat>>/etc/rsyncd.conf << EOF
log file = /usr/local/logs/rsyncd.log
transfer logging = yes
log format = %t %a %m %f %b
syslog facility = local3
EOF

学会查路径

很多情况下,我们会先获取当前脚本的路径,然后一这个路径为基准,去找其他的路径。通常我们是直接用pwd以期获得脚本的路径。

不过其实这样是不严谨的,pwd获得的是当前shell的执行路径,而不是当前脚本的执行路径。

正确的做法应该是下面这两种:

script_dir=$(cd $(dirname $0) && pwd)
script_dir=$(dirname $(readlink -f $0 ))

应当先cd进当前脚本的目录然后再pwd,或者直接读取当前脚本的所在路径;之前在编写nginx配置更新脚本的时候就遇到了这个操作姿势的坑。

代码要简短

这里的简短不单单是指代码长度,而是只用到的命令数。原则上我们应当做到,能一条命令解决的问题绝不用两条命令解决。这不仅牵涉到代码的可读性,而且也关乎代码的执行效率。

最最经典的例子如下:

cat /etc/passwd | grep root
grep root /etc/passwd

cat命令最为人不齿的用法就是这样,用的没有任何意义,明明一条命令可以解决,他非得加根管道;并且在处理大文件的时候第一种方式的效率会比较低。

使用新写法

这里的新写法不是指有多厉害,而是指我们可能更希望使用较新引入的一些语法,更多是偏向代码风格的,比如

  1. 尽量使用func(){}来定义函数,而不是func{}
  2. 尽量使用[[]]来代替[]
  3. 尽量使用$()将命令的结果赋给变量,而不是反引号
  4. 在复杂的场景下尽量使用printf代替echo进行回显

事实上,这些新写法很多功能都比旧的写法要强大,用的时候就知道了。

其他小tip

考虑到还有很多零碎的点,就不一一展开了,这里简单提一提。

  • 路径尽量保持绝对路径,绝多路径不容易出错,如果非要用相对路径,最好用./修饰
  • 优先使用bash的变量替换代替awk sed,这样更加简短
  • 简单的if尽量使用&&和||,写成单行。比如[[ x > 2]] && echo x
  • 当export变量时,尽量加上子脚本的namespace,保证变量不冲突
  • 会使用trap捕获信号,并在接受到终止信号时执行一些收尾工作
  • 使用mktemp生成临时文件或文件夹
  • 利用/dev/null过滤不友好的输出信息
  • 会利用命令的返回值判断命令的执行情况
  • 使用文件前要判断文件是否存在,否则做好异常处理
  • 不要处理ls后的数据(比如ls -l | awk '{ print $8 }'),ls的结果非常不确定,并且平台有关
  • 读取文件时不要使用for loop而要使用while read

转自:https://www.cnblogs.com/thatsit/p/shell-jiao-ben-shu-xie-gui-fan.html


curl发送post请求的有用示例(包括json)

curl用法

下面这些是使用curl来发送POST或PUT请求的常见选项:

1、请求类型

  • -X POST
  • -X PUT

2、Content Type头信息

  • -H "Content-Type: application/x-www-form-urlencoded":发送form表单
  • -H "Content-Type: application/json":发送json数据

3、数据传递

  • form表单:-d "param1=value1&param2=value2" 或者 -d @data.txt
  • json:-d '{"key1":"value1", "key2":"value2"}' 或者 -d @data.json

示例

POST application/x-www-form-urlencoded

默认的content type为application/x-www-form-urlencoded,不需显式设置。

curl -d "param1=value1&param2=value2" -X POST http://localhost:3000/data

使用文件传递数据:

curl -d "@data.txt" -X POST http://localhost:3000/data

POST application/json

发送json需显式设置content type:

curl -d '{"key1":"value1", "key2":"value2"}' -H "Content-Type: application/json" -X POST http://localhost:3000/data

使用文件传递数据:

curl -d "@data.json" -X POST http://localhost:3000/data

此处是不需要显式设置content-type,文件是以.json结尾。

CentOS:yum安装rz和sz上传下载文件

安装

$sudo yum install -y lrzsz

rz

使用rz上传本地文件到服务

$rz

执行命令后,在弹出框中选择要上传的文件即可。

sz

下载服务器的文件到本地

$sz filepath

设置默认本地上传下载目录

SecureCRT软件 -> Options -> session options -> X/Y/Zmodem 设置上传和下载的目录。

Nginx配置ssl_client_certificate客户端认证问题

问题1: ssl_client_certificate 配置的CA证书格式错误

参考Mini tutorial for configuring client-side SSL certificatesClient Side Certificate Auth in Nginx配置客户端的证书认证,配置好后,在浏览器使用证书认证报400错误

400 Bad Request

No required SSL certificate was sent
 

按照教程,生成相关证书都没有问题,在配置nginx的ssl_client_certificate需要把CA证书改用pem格式

转换如下:

sudo openssl x509 -in ca.crt -out ca.pem -outform PEM

nginx配置如下:

server {
  listen 443;
  server_name admin.majing.io;
  ssl on;
  root html;
  index index.html index.htm;
  ssl_certificate server.pem;
  ssl_certificate_key server.key;
  ssl_session_timeout 5m;
  ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
  ssl_prefer_server_ciphers on;

  ssl_client_certificate ca.pem;
  ssl_verify_client on;

  location / {
    root /usr/share/nginx/html;
    index index.html index.htm;
  }
}

参考:ssl_client_certificate

问题2: ssl_client_certificate所配置证书不需要和server证书属于同一个CA根证书

server证书用于ssl服务器端认证,在生产环境一定要使用CA机构颁发的证书。

ssl_client_certificate配置的是客户端认证。

问题3 curl测试

使用curl测试部署,如果客户端证书需要密码,则需要使用冒号在crt文件后添加密码。

curl -v -s -k --key /etc/nginx/certs/client.key --cert /etc/nginx/certs/client.crt:12345 https://example.com

Nginx配置客户端(浏览器)SSL证书认证简明教程(自签名证书)

本文介绍自签名的证书方式,与签名相关的文件包括:

  • cer/crt:证书文件,Linux习惯用crt作为后缀,Windows用cer作为后缀。
  • key:私钥文件
  • csr(Certificate Signing Request):证书签名请求

创建CA根证书

CA证书用于签署客户端证书。

sudo openssl genrsa -des3 -out ca.key 4096
sudo openssl req -new -x509 -days 365 -key ca.key -out ca.crt

创建的内容为:

  • ca.key:CA的密钥文件
  • ca.crt:CA证书文件

创建服务器证书

创建服务器的密钥文件和证书请求文件

sudo openssl genrsa -des3 -out server.key 1024
sudo openssl req -new -key server.key -out server.csr

使用CA签署服务器证书

sudo openssl x509 -req -days 365 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt

创建的文件为:

  • server.key:服务器密钥文件
  • server.csr:服务器证书签名请求,此证书用于向CA请求签署服务器证书。
  • server.crt:有CA根证书签署的服务器证书。

创建客户端证书

创建客户端的密钥文件和证书请求文件

sudo openssl genrsa -des3 -out client.key 1024
sudo openssl req -new -key client.key -out client.csr

使用CA签署客户端证书

sudo openssl x509 -req -days 365 -in client.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out client.crt

转换CA证书为PEM格式

sudo openssl x509 -in ca.crt -out ca.pem -outform PEM

因为在nginx的ssl_client_certificate需要pem格式

转换客户端证书格式

转换为pkcs12格式

pkcs12格式会把客户端的密钥文件(key)和证书文件(crt)打包在一起,后缀为.p12。

sudo openssl pkcs12 -export -clcerts -in client.crt -inkey client.key -out client.p12

pkcs12这种格式被大部分浏览器支持安装。

转换为PEM编码

sudo openssl pkcs12 -in client.p12 -out client.pem -clcerts

Nginx配置

相关配置如下:

server {
    listen        443;
    ssl on;
    server_name example.com;

    ssl_certificate      /etc/nginx/certs/server.crt;
    ssl_certificate_key  /etc/nginx/certs/server.key;
    ssl_client_certificate /etc/nginx/certs/ca.pem;
    ssl_verify_client on;#可以设为on,认证客户端

}

相关问题参考:https://majing.io/posts/10000002871167

Linux统计目录下所有文件的行数

这里提供两种方法来统计目录下所有文件的行数:

1、结合使用find和wc:

find . -name '*.pl' | xargs wc -l

另外,此命令也可以改为:

( find ./ -name '*.pl' -print0 | xargs -0 cat ) | wc -l

使用-print0 是为了避免文件名有换行符等一些特殊字符

需要注意的是,wc是统计换行符,而不是统计行数,所以如果最后一行没有换行符是会被忽略的。

2、使用grep -c

为了避免wc可能会漏统计文件的最后一行,可以使用grep -c来统计,代码如下:

total=0
find /path -type f -name "*.php" | while read FILE; do
     count=$(grep -c ^ < "$FILE")
     echo "$FILE has $count lines"
     let total=total+count
done
echo TOTAL LINES COUNTED:  $total

Linux查看内存占用

在Linux可以使用这两个命令查看内存占用:top,pmap

top

top是linux常用的性能分析工具,可以查看各个进程的资源占用情况。

$top
top - 21:52:03 up 521 days,  4:59,  2 users,  load average: 0.02, 0.04, 0.06
Tasks:  87 total,   1 running,  84 sleeping,   2 stopped,   0 zombie
Cpu(s):  0.7%us,  0.7%sy,  0.0%ni, 98.7%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:   1018600k total,   931668k used,    86932k free,    22444k buffers
Swap:        0k total,        0k used,        0k free,    93136k cached

   PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
   1345 cc         20   0 2296m   326m 2036 S 0.0 32.8 194:05.56 java
   2926 cc         20   0 2335m   320m 4688 S 0.3 32.2  19:08.68 java
   4152 mysql     20   0  698m  41m 3144 S 0.0 4.2 241:43.29 mysqld
   57548 cc         20   0 1034m  15m  476 S 0.0 1.5   0:00.23 node  

前面5行是资源使用的汇总信息。在第四行的Mem为内存使用情况

Mem:   1018600k total,   931668k used,    86932k free,    22444k buffers

汇总的内存信息依次是:total->总的内存,used->已使用的内存,free->可用内存,buffers->buffer占用

进程占用资源情况,输出内容:

  • PID:进程的ID
  • USER:进程所有者
  • PR:进程的优先级别,越小越优先被执行
  • NI:nice值。负值表示高优先级,正值表示低优先级
  • VIRT:进程占用的虚拟内存
  • RES:进程占用的物理内存
  • SHR:进程使用的共享内存
  • S:进程的状态。S表示休眠,R表示正在运行,Z表示僵死状态,N表示该进程优先值为负数
  • %CPU:进程占用CPU的使用率
  • %MEM:进程使用的物理内存和总内存的百分比
  • TIME+:该进程启动后占用的总的CPU时间,即占用CPU使用时间的累加值。
  • COMMAND:进程启动命令名称

%MEM为占用的内存百分比。

快捷键

进入top界面后,可以使用m和M两个快捷键。

  • m:显示/隐藏内存资源汇总,及第四和第五行
  • M:进程占用资源的%MEM列按降序排列

pmap

如果需要查看进程占用内存的详情,可以使用pmap

$ pmap -d pid

pid可以使用ps查到。
输出

$pmap -d 33488
33488:  /usr/bin/java xxx
Address      Kbytes Mode Offset      Device  Mapping
0000000000400000    4 r-x-- 0000000000000000 0ca:00001 java
0000000000600000    8 rw--- 0000000000000000 0ca:00001 java
00000000015cf000   928 rw--- 0000000000000000 000:00000  [ anon ]

pmap会列出进程id对应的命令,以及内存地址的映射情况。

Windows查看端口占用的进程

Windows netstat

在Linux我们可以使用netstat查看网络状态,包括端口占用的进程。在window也是可以使用netstat命令查看端口占用的进程。

打开windows的终端:

开始->运行-> 输入cmd,回车->进入cmd

执行

C:\> netstat -ano
  • -a:显示所有连接和监听的端口
  • -n:以数字的形式显示地址和端口,如果没有-n,地址可能会是域名。
  • -o:显示连接关联的pid

资源监视器GUI

有两种方法进入资源监视器GUI:

  • 命令:开始-> 运行 -> resmon.exe
  • 菜单:打开任务管理器 -> 切换到性能标签-> 点击界面下方的“打开资源监视器”

资源监视器GUI如图:

Shell脚本使用curl命令发送JSON数据

在Linux使用命令行工具curl发送JSON数据需要把content-type设置为“application/json”。

-H "Content-Type: application/json

示例

curl -H "Content-Type: application/json" -X POST -d '{"username":"jack","age":10}' http://example.com/api/user

-H,--header:设置头信息Content-Type为application/json。
-d,--data:添加发送的数据。
-X:指定http请求的方法。如果使用了-d,默认是使用POST,可以省略-X参数。

此外也可以把json数据放在一个文件里。

curl -H "Content-Type: application/json" -X POST -d @user.json http://example.com/api/user

注意:文件前的@不能去掉

Windows

对于windows,-d参数的数据,需要使用双引号,json里的双引号使用反斜杠转义才可以:

curl -H "Content-Type: application/json" -X POST -d "{\"username\":\"jack\",\"age\":10}" http://example.com/api/user

CentOS 7更新为阿里云yum源

进入yum源的目录

centos 7yum源目录为/etc/yum.repos.d

$cd /etc/yum.repos.d

备份yum源

在更新centos 7的yum源前先备份。

$ sudo cp CentOS-Base.repo backup/

如果没有bakcup目录先创建。

下载阿里云yum源

阿里云yum源列表:http://mirrors.aliyun.com/repo/,centos 7yum源文件为Centos-7.repo。

$sudo wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo

重建yum缓存

更新yum源后需要重建yum的缓存。

清除旧的缓存

$sudo yum clean all

重建新的缓存

$ sudo yum makecache

CentOS 7安装Docker环境

在CentOS上有两种方式安装Docke:

  1. https://get.docker.com/联网脚本安装
  2. 使用yum安装

联网脚本安装

1、更新yum源

sudo yum update

2、联网下载脚本安装

curl -sSL https://get.docker.com/ | sh

使用yum安装

1、更新yum源

sudo yum update

2、添加docker的yum仓库

sudo vim /etc/yum.repos.d/docker.repo

添加内容如下:

[dockerrepo]
name=Docker Repository
baseurl=https://yum.dockerproject.org/repo/main/centos/$releasever/
enabled=1
gpgcheck=1
gpgkey=https://yum.dockerproject.org/gpg

3、安装docker-engine

sudo yum install docker-engine

启动和验证

上面两种方式都可以安装,接着是启动和验证docker。

启动docker服务

sudo service docker start

验证

sudo docker run hello-world

设置随系统启动

sudo chkconfig docker on`

Linux使用grep查找文本所在的所有文件

显示所在文件及匹配到的文本

grep -rin 'search' /path/

 -r/-R:递归遍历目录
-i:忽略大小写
-n:显示出现在文件的行号

仅显示所在文件

grep -ril 'search' /path/

-l:显示所在的文件,而不是匹配到的文本

包含/排除目录

可以使用--exclude, --include, --exclude-dir 或--include-dir,包含制定的目录或者排除指定的目录

包含指定文件

grep --include=*.txt "search" -rin /path/

排除指定的文件

grep --exclude=*.jar "search" -rin /path/

排除多个目录

grep --exclude-dir={dir1,dir2} "search" -rin /path/

排除匹配目录

grep --exclude-dir=*dir "search" -rin /path/

Linux Shell脚本里的单引号和双引号的区别

双引号

在Shell脚本里,双引号里的字符,除$、\、’、和”这几个字符是特殊字符并保留其特殊功能外,其余字符作为普通字符对待。

在双引号内支持内插变量,使用$符号表示。支持内插转义,使用反斜杠\做转,对于在双引号内的"需要使用反斜杠转义。

单引号

在Shell脚本里,单引号内的字符都为普通字符,不支持内插任何东西,即使是使用反斜杠对单引号做的转义也不行。

示例:

#!/bin/sh
MYVAR=test
echo "双引号输出:$MYVAR"
echo '单引号输出:$MYVAR'

输出结果为:

双引号输出:test
单引号输出:$MYVAR

Ubuntu使用apt-get安装软件禁用交互模式

apt-get启动非交互模式:

  1. 设置DEBIAN_FRONTEND为noninteractive
  2. 使用apt-get安装软件包添加-y,-q参数
export DEBIAN_FRONTEND=noninteractive
apt-get -y -q install [packagename]

使用sudo命令

sudo DEBIAN_FRONTEND=noninteractive apt-get -y -q install [packagename]

Linux查找占用指定端口的进程

在Linux有多种方案。

lsof

lsof -i tcp:80

列出使用tcp连接80端口的进程

不指定协议

lsof -i :80

netstat

sudo netstat -nlp

列出所有打开的网络连接

Linux:使用visudo设置用户sudo权限

visudo

我们可以修改/etc/sudoers文件来设置用户的sudo权限,修改/etc/sudoers一定要使用visudo命令,它可以让我们比较安全的修改此文件。

visudo有以下特性:

  1. 锁定文件避免多个同时编辑
  2. 检查语法的完整性
  3. 检查解析错误,以避免用户错误输入

使用root的权限直接执行visudo,打开suders文件

$visudo

注意:这里不需要输入shduers文件的路径,默认为/etc/sudoers。可以使用-f指定sudoers文件。

设置sudo权限

语法格式

用户  主机=(用户身份) 命令列表

用户:用户可以是直接用户名(如:root),也可以是以%开头表示的用户组(如:%wheel)。
主机:使用Host_Alias定义主机的别名
命令列表:使用Cmnd_Alias定义命令别名,多个命令使用逗号隔开

用法

找到下面这一行

root  ALL=(ALL)   ALL

1、允许用户在所有主机上执行所有命令的权限

test   ALL=(ALL) ALL

2、运行用户在指定主机上执行特定命令的权限

Host_Alias HOST1 = 192.168.1.1
Cmnd_Alias MY_CMD = /bin/mycmd
test HOST1=(ALL) MY_CMD

意思是:允许test在HOST1表示的主机上执行MY_CMD表示的命令

3、设置组执行所有命令的权限

%mygroup  ALL= (ALL)  ALL

4、设置组无需密码执行所有命令的权限

%mygroup ALL=(ALL)   NOPASSWD: ALL

wheel

在Linux有一个特殊的组wheel,它允许此组的用户执行所有命令的权限。

使用visudo打开sudoers文件,找到

%wheel ALL=(ALL)   ALL

如果此行被注释掉,把#去掉,然后把用户添加到此组即可。

usermod -aG wheel myuser

Linux命令useradd添加用户的默认值说明

Linux添加用户的命令useradd会使用选项指定的值在加上默认文件/etc/default/useradd设置的值初始化新增的用户。

这里将对useradd的默认值做下说明。

查看默认值

[root@xxx home]# useradd -D
GROUP=100
HOME=/home
INACTIVE=-1
EXPIRE=
SHELL=/bin/bash
SKEL=/etc/skel
CREATE_MAIL_SPOOL=yes

GROUP

主用户组,默认为100。创建用户时不会马上使用主用户组作为用户的组。它需要满足两个条件才会用到此默认值。

  1. 添加用户时没有指定用户所属的组,即没有使用-g/--gid或-G, --groups选项
  2. 文件/etc/login.defs的USERGROUPS_ENAB设置为no,或者使用了-N/--no-user-group禁止创建以用户名为组名的用户组。

添加用户到GROUP设定的主用户组命令类似:

sudo useradd -N primary_group_username

查看组信息

cat /etc/group

其他值

HOME:创建用户目录的根目录。
INACTIVE:密码过期后,开始永久禁用账号的天数。0表示马上禁用账号,-1表示不使用此功能,即不会永久禁用账号。
EXPIRE:禁用账号的日期,格式YYYY-MM-DD
SHELL:用户登录的shell脚本
SKEL

这些默认值存放在默认值文件/etc/default/useradd里,所有也可以使用cat查看useradd的默认值。

设置默认值

使用useradd -D 再加上所要修改的默认值选项即可修改useradd的默认值。

-g/--gid GROUP:设置主用户组GROUP的默认值。

sudo useradd -D -gid 100

-b/--base-dir BASE_DIR:设置HOME的默认值。用户主目录由base目录加上用户名组成。

sudo useradd -D -b myhome

-f/--inactive INACTIVE:设置INACTIVE的默认值。

sudo useradd -D -f 0

-e/--expiredate EXPIRE_DATE:设置EXPIRE默认值。

sudo useradd -D -e 2017-10-27

-s/--shell SHELL:设置SHELL默认值。

sudo useradd -D -s /bin/sh

CentOS 6/7修改主机名hostname

CentOS 7

 RHEL 7新增了hostnamectl命令,基于RHEL 7的CentOS 7相应的可以使用hostnamectl来修改主机名。

hostnamectl把主机名分为以下三种:

静态主机名:hostnamectl用来在系统启动时初始化内核的主机名。
瞬态主机名:由DHCP等一些系统临时分配的主机名,如果系统存在静态主机名且有效,则不会用到瞬态主机名。
pretty主机名:静态和瞬态主机名都是要符合域名的字符串,而pretty主机名则可以包含其他一些特殊字符。

查看主机名

使用hostnamectl或hostnamectl status查看主机信息

[root@myhostname ~]# hostnamectl
  Static hostname: myhostname
Transient hostname: transientName
     Icon name: computer-vm
      Chassis: vm
    Machine ID: xxxxxxxx
      Boot ID: xxxxxxxx
  Virtualization: kvm
 Operating System: CentOS Linux 7 (Core)
    CPE OS Name: cpe:/o:centos:centos:7
      Kernel: Linux 3.10.0-693.2.2.el7.x86_64
   Architecture: x86-64

设置主机名

使用hostnamectl的set-hostname命令设置主机名。

[root@myhostname ~]# hostnamectl set-hostname test
[root@myhostname ~]# hostnamectl
  Static hostname: test
     Icon name: computer-vm
      Chassis: vm
    Machine ID: xxxxxxxx
      Boot ID: xxxxxxxx
  Virtualization: kvm
 Operating System: CentOS Linux 7 (Core)
    CPE OS Name: cpe:/o:centos:centos:7
      Kernel: Linux 3.10.0-693.2.2.el7.x86_64
   Architecture: x86-64

对比两次的hostname,使用hostnamectl set-hostname test后,Transient hostname已被删除。

注意到hostname设置为test后,终端提示还是root@myhostname,退出重新登录即会显示新的hostname。

设置瞬态主机名

hostnamectl set-hostname --transient transientName

设置静态主机

hostnamectl set-hostname --static  staticName

单独设置静态主机名,设置静态主机名为永久修改主机名,重启机器不会影响。

设置静态主机名实际是会修改/etc/hostname文件的主机名,系统重启时会读取/etc/hostname来初始化内核主机名。

设置pretty主机名

hostnamectl set-hostname --pretty prettyName

CentOS 6

永久修改主机名

CentOS 6永久修改主机名需要修改两个文件/etc/sysconfig/network和/etc/hosts。

/etc/sysconfig/network修改HOSTNAME的值

HOSTNAME=myNewHostName

为了避免出现一些其他问题,修改/etc/hosts里的hostname。

修改后重启服务器reboot。

运行时修改主机名

使用hostname命令可以在不重启主机的情况下修改主机名。

hostname newhostname

重启机器后,主机名会重新变为原来的主机名。

Linux下查看进程所使用的环境变量

在Linux下直接执行env命令即可获取当前的环境变量

[xxxx ~]$$ env
HOSTNAME=iZ94lykym6iZ
TERM=linux
SHELL=/bin/bash
HISTSIZE=1000
...

进程的环境变量可以在/proc/<pid>/environ查看,其中<pid>为进程id

获取进程id

使用ps获取pid

[xxxx ~]$ ps -ef | grep java
500   3345  1 0 Sep06 ?    00:48:57 /usr/bin/java -Djava.util.logging.config.file=/home/xxx/tomcat/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.endorsed.dirs=/home/xxx/tomcat/endorsed -classpath /home/xxx/tomcat/bin/bootstrap.jar:/home/xxx/tomcat/bin/tomcat-juli.jar -Dcatalina.base=/home/xxx/tomcat -Dcatalina.home=/home/xxx/tomcat -Djava.io.tmpdir=/home/xxx/tomcat/temp org.apache.catalina.startup.Bootstrap start

其中3345就是pid。

使用pidof获取pid

pidof命令需要知道进程的可执行的命令。

[xxxx ~]$ pidof java
24299 3345

它会列出所有执行此命令的进程id。

列出进程的环境变量

直接查看

cat /proc/<pid>/environ

美化输出查看

xargs --null --max-args=1 < /proc/<pid>/environ

ACL(access control lists)配置0.0.0.0/0 和::/0的区别

发布于 2017.10.06 6分钟阅读 1 评论 5 推荐

    运维

    作者: 胡学义
  1. SSH 禁止特定用户使用密码登录 Page 1
  2. ACL(access control lists)配置0.0.0.0/0 和::/0的区别 Page 2

0.0.0.0/0 和::/0的区别在于前者为ip4地址,后者为ip6地址

  • 0.0.0.0/0 :表示所有可能的IP4地址
  • ::/0:表示所有可能的IP6地址,包括所有的IP4地址,因为IP4地址可以映射为IP6地址。

SSH 禁止特定用户使用密码登录

发布于 2017.10.06 22分钟阅读 0 评论 5 推荐

    运维

    作者: 胡学义
  1. SSH 禁止特定用户使用密码登录 Page 1
  2. ACL(access control lists)配置0.0.0.0/0 和::/0的区别 Page 2

SSH禁止特定用户使用密码登录可以在/etc/ssh/sshd_config添加Match配置过滤指定的用户。

按用户过滤

Match User user1,user2,user3,user4
    PasswordAuthentication no

按组过滤

Match Group group1
    PasswordAuthentication no

使用叹号(!)取非过滤

Match User !root
    PasswordAuthentication no

注意:Match是引入了一个条件块,如果满足Match行指定的条件,那么随后的指令将会覆盖全局配置的指令。Match条件块的结束标识为下一个Match指令或者是文件结束。