Shell笔记

Linux系统介绍:内核、shell及软件包管理

Linux系统主要包括3层, 硬件(RAM、CPU、I/O设备等)、 Linux 内核和 用户进程。 Linux 内核最初由芬兰黑客 Linus Torvalds 开发,Linux内核是Linux操作系统的重要组成部分,是操作系统的核心,是系统硬件和进程之间的接口。内核提供内存管理、进程管理、设备驱动和各种系统调用。 _images/linux-architecture.png

Linux内核版本

Linux各个内核版本可以在https://www.kernel.org/ 上下载,一些社区组织或厂商将Linux内核与各种软件和文档包装起来,并提供系统安装界面和系统配置、设定与管理工具,就构成了 Linux 的发行版本。Linux有多个发行版本,常见的Linux系统有Centos和Ubuntu。 _images/linux-kernel.jpg

查看系统版本

cat /proc/version
uname -a
[root@iZ8vb54310gt89j8qct198Z ~]# cat /proc/version
Linux version 4.18.0-147.5.1.el8_1.x86_64 (mockbuild@kbuilder.bsys.centos.org) (gcc version 8.3.1 20190507 (Red Hat 8.3.1-4) (GCC)) #1 SMP Wed Feb 5 02:00:39 UTC 2020
[root@iZ8vb54310gt89j8qct198Z ~]# uname -a
Linux iZ8vb54310gt89j8qct198Z 4.18.0-147.5.1.el8_1.x86_64 #1 SMP Wed Feb 5 02:00:39 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

4.18.0-147.5.1.el8_1.x86_64 :

  • 4:内核主版本号

  • 18:内核次版本号,偶数代表稳定版;奇数代表开发版

  • 0:内核修订版本号,添加安全补丁,bug修复,新功能或驱动程序等

  • 147.5.1:发行版本的补丁版本

  • el8_1:使用的内核是 RedHat / CentOS 系列发行版专用内核

  • x86_64:x86平台64位CPU

查看centos发行版本:

[root@iZ8vb54310gt89j8qct198Z ~]# cat /etc/redhat-release 
CentOS Linux release 8.1.1911 (Core) 

shell

常见 shell

Shell 是一种脚本编程语言,连接内核和用户。常见的 Shell 有 sh、bash、ksh、csh等。

  • Bourne Shell (/usr/bin/sh或/bin/sh)

  • Bourne Again Shell (/bin/bash):兼容 sh

  • C Shell (/usr/bin/csh)

  • K Shell (/usr/bin/ksh)

  • Shell for Root (/sbin/sh)

cat /etc/shells 命令查看系统可用shell:

[root@client ~]# cat /etc/shells
/bin/sh
/bin/bash
/usr/bin/sh
/usr/bin/bash
[root@client ~]# 

运行 shell

  1. 使脚本具有执行权限

chmod +x ./test.sh 
chmod 777 ./test.sh 
  1. 执行脚本

./test.sh # 执行脚本
/bin/sh test.sh

查看Linux系统信息

查看系统位数

  1. getconf LONG_BIT

  2. file /bin/ls

[root@iZ8vb54310gt89j8qct198Z ~]# getconf LONG_BIT
64
[root@iZ8vb54310gt89j8qct198Z ~]# file /bin/ls
/bin/ls: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=937708964f0f7e3673465d7749d6cf6a2601dea2, stripped, too many notes (256)
[root@iZ8vb54310gt89j8qct198Z ~]# 

查看内存信息

Linux 查看内存支持的最大内存容量

$ dmidecode|grep -P 'Maximum\s+Capacity'
        Maximum Capacity: 8 GB

查看槽位上内存的速率,没插就是unknown。

dmidecode|grep -A16 "Memory Device"|grep 'Speed'

_images/Linux-Memory-Device.png 查看内存条厂家

dmidecode -t memory | grep Manufacturer

_images/Linux-Memory-Manufacturer.png

查看内存信息(显示插槽个数和每个插槽里内存条的大小)

$ dmidecode -t memory | grep Size
        Size: 8192 MB

查看内存使用情况:

$free -h
              total        used        free      shared  buff/cache   available
Mem:           1.8G        1.4G        173M        764K        251M        268M
Swap:          2.0G        1.0G        1.0G

查看CPU信息

# CPU型号
$ cat /proc/cpuinfo | grep name | sort | uniq
model name      : Intel Xeon Processor (Skylake, IBRS)

# 物理CPU个数
$ cat /proc/cpuinfo | grep "physical id" 
physical id     : 0
physical id     : 1
physical id     : 2
physical id     : 3
physical id     : 4
physical id     : 5
physical id     : 6
physical id     : 7

# 每个物理CPU核数
$ cat /proc/cpuinfo| grep "cpu cores"| uniq
cpu cores       : 1

# 逻辑CPU个数
$ cat /proc/cpuinfo| grep "processor"| wc -l
8

Linux软件包管理

Linux软件安装可以直接通过源码编译安装,一般源码包都打包成tar.gz压缩格式。源码包安装比较麻烦,容易出错,也可以使用包管理来软件包的管理,包管理工具是对软件工具的安装、卸载及其他管理, 常见的两类软件包管理工具是RPM 和 DPKG,RPM是Red Hat软件包管理器,DPKG的是Debian的Linux系列基本的包管理系统。

源码编译安装

源码编译安装步骤:

  1. 下载安装文件

  2. 解压

tar -xvzf xxx.tar.gz
  1. 检查编译 进入解压文件内

./configure

检查通过后,将生成用于编译的MakeFile文件。 4. 编译

make
  1. 安装

make install

安装完毕,应清除编译过程中产生的临时文件和配置过程中产生的文件。

make clean
make distclean

如果要卸载,则执行

make uninstall

RPM

RPM 全称为 Redhat Package Manager,最早由 Red Hat 公司制定实施,rpm包文件通常以.rpm结尾。

RPM包安装

下载rpm包后安装: 安装 RPM 包

rpm -ivh package.rpm

升级 RPM 包

rpm -Uvh package.rpm

卸载 RPM 包

rpm -ev package
rpm命令其它用法

查看是否安装了某个软件:

[root@Client ~]# rpm -qa | grep wireshark
wireshark-1.10.14-25.el7.x86_64

查询某个命令属于哪个软件:

[root@Client ~]# which scp
/usr/bin/scp
[root@Client ~]# rpm -qf /usr/bin/scp
openssh-clients-7.4p1-21.el7.x86_64
yum

rpm无法解决软件包与软件包之间的依赖问题,可以使用yum工具进行在线安装,yum(Yellowdog update Modifier)是RPM前端工具,操作对象为rpm包。由于网络问题,可以设置yum国内镜像源,也可以配置本地源。下面介绍yum安装方法: 搜索可用软件包:

yum search all 软件关键字

搜索已安装的软件:

yum list installed | grep 软件关键字

安装

yum install package-name
yum -y install package-name #接受所有互动问答

卸载

yum remove package-name
yum -y remove package-name

DPKG

DPKG全称为 Debian Package,功能与 RPM 相似,包文件通常以 .deb 扩展名结尾。Ubuntu系统使用此包管理工具。

DPKG 命令安装

安装 DEB 包

dpkg -i package.deb

升级 DEB 包

dpkg -i package.deb ( 和安装命令相同)

卸载 DEB 包

dpkg -r package.deb # 不卸载配置文件
dpkg -P package.deb # 卸载配置文件
apt

apt 全称 Advanced Packaging Tools,DPKG 前端工具, apt 的主要包管理工具为apt-get,实现功能和yum类似。

搜索可用软件包

apt-cache search 软件关键字

安装

apt-get install package-name

下载指定软件的源文件

apt-get source package-name

更新

apt-get upgrade # 更新软件
apt-get update # 更新软件列表
apt-get dist-upgrade # 更新所有软件

卸载

apt-get remove package-name

查看历史命令history

在Linux命令窗口可以查看执行过的历史命令,可以通过上/下方向键(或者Ctrl+ p / Ctrl+ n)显示相对于当前命令的上一条或下一条历史记录。或者通过Ctrl+ r 来搜索历史命令。

还有一种更为直观的方法是使用history命令,可以显示多个记录,默认情况下,历史命令存放在 ~/.bash_history 文件里面,也可以在/etc/bashrc中设置历史命令存放路径,添加:export HISTFILE=存放路径

history命令格式如下:

history [-c] [-d offset] [n]
  • -c:清空历史命令

  • -d offset:删除历史命令中第offset个命令

  • n:显示最近的n条历史命令

显示最近的5个命令:

[root@server ~]# history 5
  996  cat /etc/bashrc
  997  vim /etc/bashrc
  998  history --help
  999  echo $HISTSIZE
 1000  history 5
[root@server ~]# 

Linux 文件句柄

由于UNIX/Linux系统中的资源都是以文件的形式存在的,可以限制用户进程可使用的系统资源数量,比如一个进程可以打开的文件数,用户可以创建多大的文件,以及进程可以使用多少内存。如果Linux在进行大量并发操作的时候,可能会报 "Too many open files" 错误,这是因为并发操作的文件数超过了限制,可以使用ulimit命令查看:

$ 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) 7144
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
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) 7144
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

open files 的最大限制为1024,可以使用ulimit命令进行修改:

ulimit –n 10000

这个命令不能保证永久生效,系统重启后会恢复原来的默认值。为了让ulimit在重启过程中持续存在,需要修改配置文件/etc/security/limits.conf

#<domain>      <type>  <item>         <value>
#

#*               soft    core            0
#*               hard    rss             10000
#@student        hard    nproc           20
#@faculty        soft    nproc           20
#@faculty        hard    nproc           50
#ftp             hard    nproc           0
#@student        -       maxlogins       4

type可以设置为soft和hard:

  • soft:软件限制,用于警告

  • hard:硬件限制,设置实际的默认值

item选项包括:

  • core :core文件大小 (KB)

  • data :最大的数据大小 (KB)

  • fsize :最大文件大小 (KB)

  • memlock :最大锁定内存空间 (KB)

  • nofile :打开文件的最大数量

  • rss :最大Resident Set大小 (KB)

  • stack :堆栈大小 (KB)

  • cpu :最大CPU time (MIN)

  • nproc :最大进程数

  • as :最大地址空间 (KB)

  • maxlogins :此用户的最大登录数

  • maxsyslogins :系统的最大登录数

  • priority :运行用户进程的优先级

  • locks :用户最大文件锁定数

  • sigpending :最大被挂起/阻塞 (pending) 的信号数

  • msgqueue :POSIX消息队列使用的最大内存 (bytes)

  • nice :最大允许的 nice 优先级: [-20, 19]

  • rtprio :最大realtime优先级

打开文件的最大数量设置方法如下:

编辑配置文件 /etc/security/limits.conf 加入如下配置:

* soft nofile 10000
* hard nofile 10000

或者:

* - nofile 2000

保存退出。

Linux Bash编程

在《Linux系统介绍》中,介绍了shell的多个版本,现在的Linux发行版基本都默认使用bash(Bourne Again shell),兼容Bourne shell (sh),本文将简要介绍Bash编程语法。

变量

命名规则

  • 只能使用英文字母,数字和下划线,首个字符不能以数字开头

  • 中间不能有空格,可以使用下划线(_)

  • 不能使用标点符号

  • 不能使用bash里的关键字(可用help命令查看保留关键字) img

定义与使用变量

定义变量

your_name="abc"
echo $your_name

拼接字符串

your_name="world"
your_name2="hello,$your_name!"
echo $your_name2

数组

array_name=(value0 value1 value2 value3)
valuen=${array_name[n]} # 数组取值
array_name[0]=value0 # 赋值
length=${#array_name[@]} # 获取数组长度

数组实例:

my_array=(A B "C" D)
echo "第一个元素为: ${my_array[0]}"
my_array[1]=b
echo "数组的元素为:${my_array[*]}" # 打印所有元素
echo "数组的元素为:${my_array[@]}"

输出:

第一个元素为: A
数组的元素为:A b C D
数组的元素为:A b C D

只读变量

a="123"
readonly a

删除变量

unset variable_name #不能删除只读变量

不能删除只读变量

# b=10
# readonly b
# echo $b
10
# unset b
-bash: unset: b: cannot unset: readonly variable
#

环境变量

显示所有环境变量

env
# 或者
printenv

显示环境变量值

printenv LANG
# 或者
echo $LANG

控制语句

条件分支:if

if定义

if condition
then
    command1
    command2
    ...
    commandN
fi

if和then写在同一行时,用分号分隔。

if [ 2==2 ]; then
	echo "true"; 
else 
	echo "false"; 
fi
判断条件写法
# 写法一
test expression
# 写法二
[ expression ]
# 写法三
[[ expression ]]
if test 2==2; then	echo "true"; fi
if [ 2>1 ]; then echo "true"; fi

if [[ 2>1 ]]; then	echo "true"; fi
实例

比较两个变量的大小

a=10
b=20
if [ $a -eq $b ]; then 
	echo"equal"; 
elif [ $a -lt $b ]; then 
	echo "small"; 
elif [ $a -gt $b ]; then 
	echo "big"; 
fi

循环:for

for定义
for var in item1 item2 ... itemN
do
    command1
    command2
    ...
    commandN
done
实例

for和do写在同一行时,用分号分隔。

for Ioop in 1 2 3 4 5
do
    echo "hello"
done

for Ioop in 1 2 3 4 5;do
    echo "hello"
done

循环读取文件内容并输出

for i in $(cat test.txt); do echo $i; done

循环遍历列表

list=(value1 value2 value3)
for i in ${list[*]}; do echo $i; done
# 或者
for i in ${list[@]}; do echo $i; done

循环: while

while定义
while condition
do
    command
done
实例
int=1
while(( $int<=5))
do
    echo $int
    let "int++"
done

循环读取文件内容并输出

while read line; do echo $line; done<test.txt

输出:

test1
test222
test3
test4
test5

read命令

  • read命令是用于从终端或者文件中读取输入的内部命令

  • 读取整行输入

  • 每行末尾的换行符不被读入

read命令使用

从标准输入读取输入并赋值给变量

read var

从标准输入读取多个内容

read varl var2 var3

不指定变量(默认赋值给 REPLY)

read

实例

# read a
123
# echo $a
123
# read a b c
1 2 3
# echo $a   
1
# echo $b
2
# echo $c
3
#

默认变量

# read
456
# echo $REPLY
456
#

注释

# 注释
# 多行注释
:<<EOF
内容
.......
EOF

脚本参数传递

  • $0 脚本名称

  • $1~$n 获取第n个参数:

  • $# 传递到脚本的参数个数

  • $$ 脚本运行的当前进程ID号

  • $* 以一个单字符串显示所有向脚本传递的参数

  • $? 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误

vim param.sh:

#!/bin/bash
echo "脚本名称:$0"
echo "脚本运行的当前进程ID号:$$"
echo "参数个数:$#"
echo "所有参数:$*"
echo "第1个参数:$1"
echo "第10个参数:${10}"
echo "return "$?

执行:

# chmod +x param.sh
# ./param.sh 1 2 3 4 5 6 7 8 9 10 1        
脚本名称:./param2.sh
脚本运行的当前进程ID号:21097
参数个数:11
所有参数:1 2 3 4 5 6 7 8 9 10 1
第1个参数:1
第10个参数:10
return 0
# 

基本运算

bash会把反引号里面当作一条命令来执行 In:

# echo `date +%y/%m/%d` 
20/12/27
# echo `expr 2 + 2`  
4
# a=10
# b=20
# echo expr $a + $b  
30
# echo $(($a+$b))
30
# echo expr $a - $b
-10
# echo expr $a \* $b
200
# echo expr $b / $a
2
# 
  • % 取余

  • = 赋值 a=$b 将把变量b的值赋给a

  • == 相等 相同则返回true

  • != 不相等 不相同则返回true

# a=10
# b=20
# echo `expr $b % $a`
0
# echo $[$a == $b] 
0
# echo $[$a != $b]  
1
#
  • -eq 检测相等

  • -ne 检测不相等

  • -gt 检测左边是否大于右边

  • -lt 检测左边是否小于右边

  • -ge 检测左边是否大于等于右边

  • -le 检测左边是否小于等于右边

# vim test.sh  
# cat test.sh
#!/bin/bash
a=10
b=20
if [ $a -lt $b ]
then
        echo "equal"
fi
# chmod +x test.sh
# ./test.sh
equal
#

其它实例

内存统计

#!/bin/bash
# 内存使用百分比
free | sed -n '2p' | gawk 'x = int(( $3 / $2 ) * 100) {print x}' | sed 's/$/%/'

# 统计内存
for i in `ps aux | awk '{print $6}' | grep -v 'RSS'`; do
    count=$[$count+$i]
done
echo "$count/kb"
# ./test.sh  
16%
474608/kb

求阶乘

vim test.sh

read -p "Enter a number:"
factorial=1
for (( count=1; count<=$REPLY; count++))
do
	factorial=$[ $factorial * $count ]
done
echo "The factorial of $REPLY is $factorial"
# chmod +x test.sh
# ./test.sh 
Enter a number:6
The factorial of 6 is 720

Linux Bash编程二:shell语法及实用技巧

Linux Bash编程中,介绍了Bash编程基本语法,本文记录一下Bash编程中使用到的相关shell 语法技巧。

字符串处理

在字符串中传递变量

$ num=8
# 方法1:双引号
$ text="There are $num ducks swimming in a pond"
$ echo $text
There are 8 ducks swimming in a pond
$ 
$ text="There are "$num" ducks swimming in a pond"
$ echo $text
There are 8 ducks swimming in a pond

# 方法2:单引号
$ text='There are $num ducks swimming in a pond'
$ echo $text
There are $num ducks swimming in a pond
$ 
$ text='There are '$num' ducks swimming in a pond'
$ echo $text
There are 8 ducks swimming in a pond
$ text="There are '$num' ducks swimming in a pond"
$ echo $text
There are '8' ducks swimming in a pond

tr命令

tr (translate) 命令用于删除或者转换字符,比如大小写转换,删除字符等。命令格式如下:

$ tr [OPTION] SET1 [SET2]

OPTION参数说明:

  • -c | --complement:删除或者替换SET1以外的字符

  • -d | --delete:删除SET1以外的字符

  • -s, --squeeze-repeats:压缩连续重复的字符为单个字符

  • -t, --truncate-set1:截取 SET1 使之与 SET2 长度相等

1. 大小写转换
$ echo HELLO WORLD | tr "A-Z" "a-z"
hello world
$ echo HELLO WORLD | tr "[:upper:]" "[:lower:]"
hello world
$ 
$ echo hello world | tr "a-z" "A-Z"
HELLO WORLD
$ echo hello world | tr "[:lower:]" "[:upper:]"
HELLO WORLD
2. 替换
$ echo "(hello world)" | tr "()" "{}"
{hello world}
3. 压缩重复字符串

比如可以将多个连续空格压缩为一个空格

$ echo "hello        world    !" | tr -s [:space:] ' '
hello world !
4. 删除指定字符
$ echo "10MB" | tr -d MB
10

提取数字还可以这样:

$ echo "10MB" | tr -cd "[0-9]"
10
$ echo "10MB" | tr -cd [:digit:]
10

删除数字:

$ echo "10MB" | tr -d "[0-9]"
MB
$ echo "10MB" | tr -d [:digit:]
MB

字母字符用[:alpha:]表示

判断字符串是否包含某个子串

使用通配符*

SIZE=10M

if [[ $SIZE == *M* ]]
then
   echo "$SIZE include M"
fi

或者使用操作符~

if [[ $SIZE =~ M ]]
then
   echo "$SIZE include M"
fi

数组操作

冒泡排序

#!/bin/bash

BubbleSort()
{
    # 冒泡排序
    # Performing Bubble sort
    num_length=${#arry[*]}
    
    for (( i = 0; i<$num_length; i++ ))
    do
        for (( j = 0; j<$num_length-i-1; j++ ))
        do
            if [[ ${arry[j]} -gt ${arry[$(( j+1 ))]} ]]
            then
                # swap
                temp=${arry[j]}
                arry[$j]=${arry[$((j+1))]}
                arry[$(( j+1 ))]=$temp
            fi
        done
    done
    
    echo "Array in sorted order :"
    echo -e "\E[1;31m${arry[*]} \033[0m"
}

arry=(9 8 5 6 2 4 7 1)
BubbleSort

执行结果:

$ sh BubbleSort.sh 
Array in sorted order :
1 2 4 5 6 7 8 9 

字体颜色

常用颜色格式:

normal='\033[0m' # 默认颜色
style='\033[1m' # 高亮
style='\033[4m' # 添加下划线
style='\033[7m' # 反显 
color='\033[32m' # 绿色字体
color='\033[30m' # 黑色
color='\033[31m' # 红色
color='\033[33m' # 黄色
color='\033[34m' # 蓝色
color='\033[35m' # 紫色
color='\033[36m' # 深绿
color='\033[37m' # 白色

使用方法:

echo -e "\033[1m" "There are 8 ducks swimming in a pond"
echo -e "\033[0m" "There are 8 ducks swimming in a pond"
echo -e "\033[4m" "There are 8 ducks swimming in a pond"
echo -e "\033[7m" "There are 8 ducks swimming in a pond"
echo -e "\033[32m" "There are 8 ducks swimming in a pond"

_images/echo-e.png

文本处理

文件操作

sed -i '/^$/d' test.txt # 删除空行
sed -i 's/ *//g' test.txt # 删除空格
IFS=$'\n'  # linux分隔符,默认是空格
for lines in `cat test.txt`; do # 循环读取每一行
	pic=`echo $lines | grep '\!\[\]('` # 处理读取的内容:使用Linux三剑客进行文本处理
	if [ "$pic" != "" ]
	then
    	echo $pic >> new_file.txt
    fi
	# do something
done	

清空文件内容

用于每次写文件时清空文件内容,下面介绍5种方法,前面4种方法中,如果文件不存在会创建文件。

$ cat /dev/null > test.txt
$ : > test.txt
$ > test.txt
$ true > test.txt
$ sed -i '1,$d' test.txt # 如果文件test.txt不存在会报错

使用SCP或Rsync实现Linux主机之间文件、目录的复制

我们知道Linux本机的文件拷贝可以使用cp命令,它不能在Linux主机之间拷贝数据。本文介绍SCP和Rsync这两种实现Linux主机间的数据拷贝工具。

SCP 和 Rsync区别

SCP(secure copy) 是基于ssh协议的安全拷贝,用于将文件/目录安全地从本地主机传输到远程主机。

Rsync (remote synchronize)也可以实现同步本地主机和远程主机的文件/目录,和SCP不同之处在于,首次复制时,Rsync会复制整个目录,在后面的复制中,不会复制相同的内容,只对差异文件做更新,scp是把所有文件都复制过去。Rsync广泛用于备份和镜像。

下面介绍它们的简单使用方法。

SCP

一般情况下Linux服务器都有scp命令,如果没有,可通过如下方式安装:

yum -y install openssh-clients # centos
apt-get install openssh-client # Ubuntu

复制文件/目录到远程主机

scp source_file_name user@destination_host:destination_folder # 复制文件
scp -r source_directory user@destination_host:destination_folder # 复制目录

案例1:复制文件到远程主机

[root@Client ~]# scp text.txt root@192.168.20.40:/root
The authenticity of host '192.168.20.40 (192.168.20.40)' can't be established.
ECDSA key fingerprint is SHA256:tS6tueeKp9vBLDvxgsxIgCCaGMQWs9+5E167qz2ZB9c.
ECDSA key fingerprint is MD5:82:04:10:14:57:52:0a:05:d9:9b:ae:6e:3f:3f:68:98.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.20.40' (ECDSA) to the list of known hosts.
root@192.168.20.40's password: 
test.txt                                                                                                                     100%   12     6.0KB/s   00:00    
[root@Client ~]# 

从远程主机复制文件/目录

scp user@source_host:source_file_name local_destination_folder # 复制文件
scp -r user@source_host:source_file_name local_destination_folder # 复制目录

案例2:从远程主机复制文件

[root@Client ~]# scp root@192.168.20.40:/root/test40.txt /root
root@192.168.20.40's password: 
test40.txt                                                                                                                   100%   12     4.2KB/s   00:00    
[root@Client ~]# ll | grep test40.txt
-rw-r--r--   1 root    root          12 7月   6 09:41 test40.txt
[root@Client ~]# 

-r参数用于递归的复制整个目录,SCP更多的参数使用方法可参考:https://manned.org/scp.1

本地文件/目录复制

如果不指定远程主机地址,可以实现和cp目录一样的功能:

scp source_file destination_folder # 复制文件
scp -r source_directory destination_folder # 复制目录

案例3:本地文件复制

[root@Client ~]# mkdir test
[root@Client ~]# scp test40.txt /root/test
[root@Client ~]# ll /root/test/
总用量 4
-rw-r--r-- 1 root root 12 7月   6 09:49 test40.txt
[root@Client ~]# 

Rsync

安装方法:

yum install rsync      # centos
apt-get install rsync  # Ubuntu

选项参数

Rsync可用的选项参数很多,下面介绍几个常用参数,更多参数使用方法可参考https://manned.org/rsync.1 ,或者使用rsync -hman rsync命令查看文档说明。

选项 功能
-t 将源文件的修改时间(modify time)同步到目标机器
-I --ignore-times,不跳过时间和大小都匹配的文件,也就是不检查是否有改动,直接复制
-r 递归,用于目录复制
-a 递归同步,还可以同步元信息(比如修改时间、权限等)
-v 打印复制过程
-l 拷贝符号连接
--delete 删除目标目录中多余的文件,也就是保持两个目录相同,使得目标目录成为源目录的镜像副本

复制文件/目录到远程主机

如果复制的目标目录不存在,会自动创建,语法格式和SCP一样:

rsync source_file_name/ user@destination_host:destination_folder # 复制文件
rsync -r source_file_name/ user@destination_host:destination_folder # 复制目录

案例1:复制文件、目录到远程主机

[root@Client ~]# rsync test.txt root@192.168.20.40:/root
root@192.168.20.40's password: 
[root@Client ~]# 
[root@Client ~]# rsync -rvl test/ root@192.168.20.40:/root/test222
root@192.168.20.40's password: 
sending incremental file list
created directory /root/test222
./
test2.txt
test40.txt

sent 187 bytes  received 93 bytes  62.22 bytes/sec
total size is 12  speedup is 0.04

从远程主机复制文件/目录

rsync user@source_host:source_file_name local_destination_folder # 复制文件
rsync -r user@source_host:source_file_name local_destination_folder # 复制目录

案例1:复制远程主机文件到本机

[root@Client ~]# rsync root@192.168.20.40:/root/test40.txt /root
root@192.168.20.30's password: 
[root@Client ~]# ll test40.txt
-rw-r--r-- 1 root root 12 7月   8 11:11 test40.txt
[root@Client ~]# 

其它用法

复制指定类型的文件

仅复制py文件:

rsync *.py user@destination_host:destination_folder
复制多个文件
[root@Client ~]# rsync test1.txt test2.txt test{5,6,7}.txt root@192.168.20.40:/root
root@192.168.20.40's password: 
[root@Client ~]# 

远程主机上查看是否复制成功

[root@Server ~]# ls | grep -E "test[0-9]{1}.txt"
test1.txt
test2.txt
test5.txt
test6.txt
test7.txt
[root@Server ~]# 

从远程主机复制多个文件(先删除本地文件):

[root@Client ~]# rsync root@192.168.20.40:/root/test1.txt :test2.txt root@192.168.20.40:test{5,6,7}.txt /root
root@192.168.20.40's password: 
[root@Client ~]# ls | grep -E "test[0-9]{1}.txt"
test1.txt
test2.txt
test5.txt
test6.txt
test7.txt

本地文件/目录复制

和scp命令一样,rsync也可以用于在本机进行文件复制。

rsync source_file destination_folder # 复制文件
rsync -r source_directory destination_folder # 复制目录

小结

rsync工具只对差异文件做更新的特性,在多个服务器之间同步文件非常有用,通常跳过写一个自动化脚本来实现批量同步,但是,你也许已经发现了,在执行同步命令时,需要输入目标主机的密码,在主机很多的情况下就不方便了。

一种解决方案是可以使用expect实现自动化交互,另一种方法是配置服务器之间ssh免密登录,因为scp和rsync默认使用ssh协议。ssh免密登录配置方法可参考配置多台服务器之间ssh免密登录

Linux三剑客grep、awk和sed介绍

grep,sed 和 awk是Linux/Unix 系统中常用的三个文本处理的命令行工具,称为文本处理三剑客。本文将简要介绍这三个命令的基本用法以及它们在Windows系统中的使用方法。

管道

在介绍这两个命令之前,有必要介绍一下Unix/Linux中管道(pipe)的概念。管道将一个命令/程序/进程的输出发送到另一个命令/程序/进程,以进行进一步处理。是一种进程间通信机制,使用管道符"|”将两个命令隔开,管道符左边命令的输出就会作为管道符右边命令的输入。 _images/pipe.png 管道实现了数据在多个命令之间传递,不需要创建临时文件来传递,它是单向的,数据通过管道从左向右流动。

实例1: cat test.txt | grep test1

$ cat test.txt | grep test1
test1
test111
test3 test1
test111
$ cat test.txt | grep test1 | grep test3
test3 test1
$

实例2:

$ cat test.txt | head -3
test1
test2
test3
$ cat test.txt | tail -5
test
test

test
rrrr
$ 

grep

定义

grep(Global Regular Expression Print) 命令用于搜索文件的特定模式,它不能增加、修改、删除文本内容,通常用于搜索过滤文本,显示被模式匹配到的行。使用正则表达式进行文本匹配(正则表达式参考文章《Python正则表达式》),它的使用权限是所有用户。

命令形式: grep [OPTIONS] PATTERN [FILE...]

  • 扩展正则表达式(egrep)添加 -E 参数:grep -E [OPTIONS] PATTERN [FILE...]

  • -P参数可以让grep使用perl的正则表达式语法

选项参数

  • -v 或 --invert-match : 显示不被 pattern匹配到的行

  • -n 或 --line-number : 显示匹配的行号

  • -o 或 --only-matching :仅显示匹配到的字符串

  • -c 或 --count : 统计匹配的行数

  • -i 或 --ignore-case :忽略字符大小写

  • -m或--max-count:-m 1 : 匹配到1行后停止匹配

  • -A<显示行数> 或 --after-context=<显示行数> : 除了显示符合范本样式的那一列之外,并显示该行之后的内容。

  • -B<显示行数> 或 --before-context=<显示行数> : 除了显示符合样式的那一行之外,并显示该行之前的内容。

  • -C<显示行数> 或 --context=<显示行数> : 除了显示符合样式的那一行之外,并显示该行之前和之后的内容。

or操作:

  • grep 'pattern1\|pattern2'

  • grep -E 'pattern1|pattern2'

  • egrep 'pattern1|pattern2'

实例1:查找文件内容,显示行号

查找文件内容包含'test1'的行,显示行数

$ grep -n test1 test.txt 
1:test1
7:test111
9:test3 test1
11:test111
$ grep -o test1 test.txt  
test1
test1
test1
test1
$ grep -no test1 test.txt
1:test1
7:test1
9:test1
11:test1

实例2:查找文件内容,不包含test1的行

$ grep -nv test1 test.txt
2:test2
3:test3
4:test4
5:test5
6:test6
8:test2
10:test

实例3:grep 正则表达式

查找test1开头的行

$ grep -n ^test1 test.txt
1:test1
7:test111
11:test111

查找以1结尾的行

$ grep -n 1$ test.txt    
1:test1
7:test111
9:test3 test1
11:test111

实例4:判断或者提取数字

提取文本中的数字

$ cat test.txt
test123
456test
66
$ grep -Eo '[0-9]{1,}' test.txt
123
456
66
$ grep -o '[[:digit:]]*' <<< cat test.txt
123
456
66
$ cat test.txt | grep -o '[[:digit:]]*'
123
456
66

打印全为数字的行:

$ grep -Eo '^[0-9]{1,}*$' test.txt
66
$ grep -o '^[[:digit:]]*$' <<< cat test.txt
66
$ cat test.txt | grep -o '^[[:digit:]]*$'
66

判断某个变量是否为数字:

$ num='123'
$ grep '^[[:digit:]]*$' <<< $num
123

查看进程

$ ps -aux | grep chrome
root       5425  0.4  1.8 869280 34200 pts/0    Sl   Dec22  11:31 /opt/google/chrome/chrome --no-sandbox
root       5439  0.0  0.0 563592  1132 pts/0    S    Dec22   0:00 /opt/google/chrome/chrome --type=zygote --no-zygote-sandbox --no-sandbox
root       5440  0.0  0.1 563592  2836 pts/0    S    Dec22   0:06 /opt/google/chrome/chrome --type=zygote --no-sandbox
root       5441  0.0  0.0  26452   208 pts/0    S    Dec22   0:00 /opt/google/chrome/nacl_helper --no-sandbox
root       5442  0.0  0.0  26452   144 pts/0    S    Dec22   0:00 /opt/google/chrome/nacl_helper --no-sandbox

sed

定义

sed(Stream Editor)是一种流编辑器,一次处理一行内容,将行存储在模式空间(临时缓冲区),然后用sed命令处理模式空间中的内容,处理完成后将内容送入屏幕,然后清除模式空间,继续读入下一行,执行下一个循环,直到文件末尾。这个过程中不会改变文件内容(除了 -i 选项)。

命令形式: sed [选项] [sed命令] [-f <script FILE>] [FILE] 查看帮助文档:

man sed
sed -h

选项

  • -h: 显示帮助信息

  • -n: 仅显示 script处理后的结果,常与sed命令p连用:sed -n 'p' test.txt 打印test.txt文件内容

  • -e:直接在指令列模式上进行 sed 的动作编辑,不修改原文件,输出到终端

  • -i:修改文件内容,而不输出到终端

  • -f filename : sed 动作写在filename 内,执行 filename 内的sed 动作

  • -r∶扩展正规表达式

常用命令

  • a:append,新增: sed -e '4 a newline' test.txt

  • c:change,取代: sed -e '2,5c No 2-5 number' test.txt

  • d:delete,删除: sed -e '2,5d' test.txt

    • sed -e '/^$/d' test.txt:删除test.txt文件空行

  • i:insert,插入: sed -e '2i newline' test.txt

  • p:print,打印:sed -n 'p' test.txt

  • s:substitute,替换:sed -e 's/old/new/g' test.txt

    • sed -e 's/$/%/' test.txt:在每行末尾添加%

    • sed -e 's/ *//g' test.txt: 删除test.txt文件空格

    • sed -e "4s;old;new;g" test.txt 或者 sed -e '4s/old/new/g' test.txt:替换第4行

  • N:将下一行添加到pattern space中,将当前读入行和用N命令添加的下一行看成“一行”

注意:

  1. 在替换操作中,替换时用的分割符 '/' 可以使用其它符号代替,特别是替换的内容中有 '/' 时,可以使用@、#、%等符号代替。

  2. grep和sed命令的正则表达式中不支持 \d ,可使用如下方式匹配数字:

    • sed -re 's/[0-9]+//g' test.txt

    • egrep '[0-9]+' test.txtgrep -E '[0-9]+' test.txt

实例1:打印并输出数据

打印并输出第5行数据

$ sed -n '5p' test.txt
test5
$ cat -n test.txt | sed -n '5p' 
     5	test5
$ 

打印并输出第3-5行数据

$ sed -n '3,5p' test.txt
test3
test4
test5

取反,不选择第3到5行数据

$ sed -n '3,5!p' test.txt
test1
test2

隔行输出

$ sed -n '1~2p' test.txt
test1
test3
test5
$ sed -n '1~3p' test.txt
test1
test4
$ 

实例2:将匹配的行数据输出到指定文件

$ 累加
sed -n '1~2p' test.txt >> a.log
$ 覆盖
sed -n '1~3p' test.txt > a.log 
$ sed -n '1~2p' test.txt>> a.log
$ cat a.log
test1
test3
test5
$ sed -n '1~3p' test.txt > a.log 
$ cat a.log
test1
test4
$ 

实例3:新增、插入字符串

在第2行后加上 newLine

$ sed '2 a newline' test.txt
test1
test2
newline
test3
test4
test5
$ 

在第2行前加上 newline

$ sed '2 i newline' test.txt
test1
newline
test2
test3
test4
test5

实例4:删除匹配到的行或者匹配行后的n行

介绍两种方法来删除某一行的内容,一种是使用替代(substitute)的方法: 删除匹配到test3的那一行

$ sed -e 's/test3.*//g' test.txt
test1
test2

test4
test5

删除匹配行及后一行

$ sed -e 'N;s/test3.*//g' test.txt
test1
test2

test5

这种方法会留一个空行,可以进一步使用命令sed -e '/^$/d' test.txt命令删除空行。

第二种方法是使用删除(delete)命令:

$ sed -e '/test3.*/d' test.txt
test1
test2
test4
test5

也可以删除匹配到的行及匹配行后的n行

$ sed -e '/test2.*/,+2d' test.txt
test1
test5

实例5:全局替换

将所有的test2替换为test222

$ sed -e 's/test2/test222/g' test.txt
test1
test222
test3
test4
test5
$ sed -e 's/test2/test222/' test.txt
test1
test222
test3
test4
test5

替换某一行:替换test1开头的所在行 test2.txt内容:

$ cat test2.txt
hello world !
test1 test2 test2
test1
test2
test3 
# 方法1:c参数,替换某一行
$ sed "2c hello" test2.txt
hello world !
hello
test1
test2
test3 
$ sed "3c hello" test2.txt
hello world !
test1 test2 test2
hello
test2
test3 
# 方法2:s参数替换
$ sed 's/^test1.*$/hello/' test2.txt
hello world !
hello
hello
test2
test3 

实例6:修改文件

前面的新增、替换操作都没有改变文件内容,如果要使文件修改生效,需要使用 -i 选项。

$ sed -i 's/test2/test222/' test.txt
$ cat test.txt 
test1
test222
test3
test4
test5
$ 

实例7:横向连接

将匹配到的对象横向连接

比如我们需要杀掉某个服务有多个进程:

[root@Server ~]# ps -ef | grep named | grep -v grep
root       7136      1  0 1月22 ?       00:00:54 /var/bin/named -c /var/named/named.conf
root       7690      1  0 1月21 ?       00:01:02 /var/bin/named -c /var/named/named.conf

使用命令 kill -9 7136 7690来杀掉这两个进程,使用如下命令实现连接这两个进程的ID:

kill -9 $(ps -ef | grep named | grep -v grep | awk '{print $2}') | sed ':1;N;s/\n/ /g;t1'

关键命令为 sed ':1;N;s/\n/ /g;t1',将换行替换为空格。

awk

定义

awk是一种文本模式扫描和处理的编程语言,由 Aho, Weinberger 和 Kernighan开发。awk功能强大,可用于数据提取和统计,常用在shell脚本中。awk逐行读入文件,以空格为默认分隔符将每行切片,切开的部分再进行后续处理。

命令形式: awk [options] 'pattern action' [FILE(s)]

  • pattern:正则表达式

  • action:对匹配到的内容执行的命令(默认为输出每行内容)

常用参数

  • $0: 整条记录(当前行)

  • $1 - $​n: 表示当前行的第n个域

  • FILENAME: awk浏览的文件名

  • BEGIN: 处理文本之前要执行的操作

  • END: 处理文本之后要执行的操作

  • FS: 设置输入域分隔符,等价于命令行 -F 选项,默认为空格“ ”

    • awk -F: '{print $1}' test.txt

    • 或者 awk 'BEGIN {FS = ":"} {print $1}' test.txt

  • NF: 浏览记录的域的个数/列数

  • NR: 已读的记录数/行数

  • FNR: 当前输入文件的记录数

  • OFS: 输出域分隔符,默认为空格“ ”

  • ORS: 输出记录分隔符,默认为“\n”

  • RS: 控制记录分隔符

  • exit:匹配到第一行内容后退出:awk -F: '{print $2;exit}' test.txt ,grep使用 -m 参数

实例1:查找、打印

搜索/etc/passwd有root关键字的所有行

$ awk -F : '/root/ {print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
$
$ awk -F : '/root/ {print $7}' /etc/passwd
/bin/bash
/sbin/nologin

打印etc/passwd/的第二行信息

$ awk -F : 'NR==2 {print $0}' /etc/passwd
bin:x:1:1:bin:/bin:/sbin/nologin
$

实例2:BEGIN、END制表

使用 begin加入标题

$ awk -F : 'BEGIN {print "No", "User", "Auth"} {print NR "|" $1 "|" $2} END {print FILENAME}' /etc/passwd
No User Auth
1|root|x
2|bin|x
3|daemon|x
4|adm|x
5|lp|x
6|sync|x
7|shutdown|x
8|halt|x
9|mail|x
.................
28|nscd|x
29|exim|x
/etc/passwd

实例3:自定义分割符

$ echo "123|456|789"
123|456|789
$ echo "123|456|789" | awk 'BEGIN{RS="|"}{print $0}'
123
456
789

综合实例

找出log中的404 500的报错有多少条

$ grep -E ' 404 | 500 ' nginx.log | wc -l
267
$ grep -P ' 404 | 500 ' nginx.log | wc -l
267
$ grep -Pc ' 404 | 500 ' nginx.log  
267

$ awk '$9~/404|500/' nginx.log | wc -l    # {print}省略
267
$ awk '$9~/404|500/{print}' nginx.log | wc -l
267
  • $9表示查找第9列

  • 波浪号~表示用来匹配后面的正则表达式,告诉awk后面开始是正则语法。

  • wc -l :和-c参数一样,统计匹配到的行数

访问量最高的ip

使用awk命令查找
$ awk '{print$1}' nginx.log | sort | uniq -c | sort -nr | head -3
    282 216.244.66.241
    130 136.243.151.90
    110 127.0.0.1

$ awk '{print$1}' nginx.log | sort | uniq -c | sort -nr | head -3 | awk '{print $2}'
216.244.66.241
136.243.151.90
127.0.0.1

sort命令用于排序:

  • -r:sort默认为升序,-r参数表示降序

  • -n:以数值来排序,如果不使用这个参数就会出现10比2小的情况,因为把10当做字符来进行比较了。

uniq 命令用于检查及删除文本文件中重复出现的行列,一般与 sort 命令结合使用

  • -c:在每列旁边显示该行重复出现的次数

head命令用于查看文件的开头部分的内容

使用grep查找
$ grep '^[0-9]*.[0-9]*.[0-9]*.[0-9]*' nginx.log    #其中的点“.”为正则语法,表示匹配任意字符
123.127.112.18 - - [05/Dec/2018:00:09:18 +0000] "GET /cable HTTP/1.1" 101 1017 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36" 70.577 70.577 .
139.180.132.174 - - [05/Dec/2018:00:09:20 +0000] "GET /bbs.zip HTTP/1.1" 404 1264 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36" 0.011 0.011 .
139.180.132.174 - - [05/Dec/2018:00:09:12 +0000] "GET /__zep__/js.zip HTTP/1.1" 500 2183 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36" 0.018 0.018 .

$ grep -o '^[0-9]*.[0-9]*.[0-9]*.[0-9]*' nginx.log
216.244.66.241
223.71.41.98
113.87.161.17
216.244.66.241
216.244.66.241
144.76.81.72
............
$ grep -o '^[0-9]*.[0-9]*.[0-9]*.[0-9]*' nginx.log | wc -l
2000
$ grep -o '^[0-9]*.[0-9]*.[0-9]*.[0-9]*' nginx.log | sort | uniq -c | sort -nr |head -3   
    282 216.244.66.241
    130 136.243.151.90
    110 127.0.0.1
  ......................
$ 

将 topics 后面的数字替换成numer

$ grep 'topics' nginx.log | sed 's#topics/[0-9]*#topics/number#g' 

将ip地址横向打印

[root@centos7 tmp]# awk '{print $1}' nginx.log | sed ':1;N;s/\n/|/g;t1'  
216.244.66.241|216.244.66.241|216.244.66.241|216.244.66.241|216.244.66.241|216.244.66.241|216.244.66.241|223.71.41.98|113.87.161.17|216.244.66.241|216.244.66.241|144.76.81.72
  • # :1 :标记  t1

  • ;:把不同的命令分开

在Windows中使用grep、awk和sed

在Windows系统中也可以使用这3个命令,然而,windows cmd不支持这3个命令,因此需要下载对应的Win32版本文件,下面提供几种下载方法:

  1. 开源软件平台SourceForge:https://sourceforge.net/projects/gnuwin32/files/

  2. 安装Git Bash:安装方法可参考Git简易教程-安装及简单使用,Git Bash的安装目录~\Git\usr\bin\下有很多GNU工具。

  3. 我把这三个工具放到了Github上:hiyongz/ShellNotes,可以在上面下载,注意对应的dll文件也需要下载。

安装使用:

  1. 在SourceForge上下载对应的setup文件安装,并添加到环境变量

  2. 或者直接下载对应的二进制文件,解压并添加到环境变量

测试文件test.log的内容:

log
log2
test
666 log

使用awk和grep命令查询log出现的行:

$ awk -F ' ' "/^log/ {print $0}" test.log
log
log2

$ grep -n "^log" test.log
1:log
2:log2

注意:正则表达式要用双引号。

使用bat脚本进行文本处理:

@echo off

set grep="D:/ProgramWorkspace/ShellNotes/grep/grep.exe"
set wc="D:/ProgramWorkspace/ShellNotes/wc/wc.exe"
set awk="D:/ProgramWorkspace/ShellNotes/awk/awk.exe"
set sed="D:/ProgramWorkspace/ShellNotes/sed/sed.exe"

%grep% -n "^log" test.log | %wc% -l > esult.log
%awk% -F ' ' "/^log/ {print $0}" test.log  >> result.log
%sed% -n '1,3p' test.log  >> result.log

pause

参考资料:

  1. 正则表达式30分钟入门教程:https://deerchao.cn/tutorials/regex/regex.htm

  2. Python正则表达式

Linux常用命令:文件操作命令

Linux系统命令主要包括文件操作、网络命令和性能命令,本文介绍常用文件操作命令。

文件属性

_images/linux-shell-file.png文件类型:

  • 普通文件:-

  • 目录文件:d

  • 块设备文件:b,硬盘

  • 字符设备: c,串行端口的接口设备,例如键盘、鼠标

  • 链接文件:l

  • 套接字文件:s

  • 管道文件:p

r 读权限read 4 w 写权限 write 2 x 操作权限 execute 1

常用命令:

  • chmod 777 test,修改test文件属性为可读,可写,可执行(4+2+1=7)

  • ls -l 查看文件属性(或者使用ll

  • ls -ld 查看当前目录的属性

  • ls -l 长模式,属性信息

  • ls -1 把文件一行一个的显示出来

  • ls -a 显示所有文件

  • ls -s 显示文件及文件大小

  • ls -l -a -s  --> ls -las

  • ls -sh (h-human,显示文件大小单位)

基本终端操作命令

ls: 列出目录文件 pwd: 显示目前的目录 cd: 切换目录

  • cd - :切换到上次目录

  • cd .. :切换到上级目录

  • cd / :切换到根目录

  • cd ~ :切换到当前用户的home目录

  • cd start*end :目录名较长时可使用通配符"*",比如进入system目录,可以使用 cd s*m

man命令:可以通过 man + 命令 查看帮助文档:

  • j:下翻

  • k:上翻

  • 空格键:翻页

  • q:退出

  • /-e:查找“-e”

    • n 下一个“-e”

    • N(shift+n) 上一个“-e”

[root@client ~]# ls
desktop.ini  jenkins  test.log  test.txt  t.txt
[root@client ~]# cd j*s
[root@client jenkins]# pwd  
/root/jenkins
[root@client jenkins]# cd -
/root
[root@client ~]# pwd
/root
[root@client ~]# cd jenkins/
[root@client jenkins]# pwd
/root/jenkins
[root@client jenkins]# cd ..
[root@client ~]# pwd
/root
[root@client ~]# 
/root
[root@client ~]# cd /
[root@client /]# pwd
/
[root@client /]# cd ~
[root@client ~]# pwd
/root
[root@client ~]# 

文件、目录操作

touch:新建文件,或者使用vim命令创建文件:vim test.txt,保存 mkdir: 创建一个新的目录 rmdir: 删除一个空的目录 cp: 复制文件或目录 rm: 移除文件或目录 mv: 移动文件与目录,或修改文件与目录的名称

# 将目录A复制到目录B下
cp -r /etc/A /etc/B
# 将目录A的内容复制到目录B下
cp -r /etc/A/* /etc/B
cp -r /etc/A/. /etc/B
# 删除目录A及其下面的所有文件
rm -r /etc/A
rm -rf /etc/A #强制删除
# 移动目录A到目录B下
mv /etc/A /etc/B
# 移动目录A下的所有文件到目录B下
mv /etc/A/* /etc/B

文件内容显示

cat:显示文件内容,还可以将多个文件连接起来显示,适用于内容少的文件 more:以一页一页的显示内容,空格键下一页 less:支持向前翻,向后翻页 head:打印前面n行内容:head -2 test.txt tail:打印后面n行内容:tail -2 test.txt

向文件添加内容

将内容"TEST"添加到test.txt文件中

方法一:vi编辑法

  • 打开终端,输入vi test.txt 回车,按a或i进入编辑模式 输入 TEST,然后按esc键退出编辑模式,输入 :wq 保存并退出。

方法二:echo命令法

# 追加
echo ‘TEST’ >> ./test.txt
# 覆盖
echo ‘TEST’ > ./test.txt

方法三:cat命令法

cat >> ./test.txt <<TEST

结尾的TEST要顶格。

方法四:cat编辑法

# 追加
cat >> ./test.txt

# 覆盖
cat > ./test.txt
  • 回车后开始编辑输入内容:TEST,然后回车

  • ctrl+d 或者 ctrl+c组合键结束编辑。

清空文件内容

下面介绍几种清空文件内容的方式

> test.txt
: > test.txt
cat /dev/null > test.txt
echo -n "" > test.txt

也可以使用 ddtruncate命令来清空内容:

dd of=test.txt count=0
dd if=/dev/null of=test.txt
truncate -s 0 test.txt

这两个命令可以用来生成指定大小的文件,具体使用方法可参考文章Linux和Windows创建指定大小文件方法

还可以使用 sed 命令:

sed -i d test.txt
sed -i '/^$/d' test.txt # 删除空行
sed -i 's/ *//g' test.txt # 删除空格

find命令

用于查找文件,基本用法:find path -name‘xxx' find / -name jenkins:查找所有目录下的jenkins文件

[root@client ~]# find / -name jenkins
/root/jenkins
/var/lib/docker/overlay2/6cc1d9dcc70fed5dcc455ca4147a13f650724c2e8004a9c101b4e2130276241c/diff/usr/share/jenkins
/var/lib/docker/overlay2/9b98446d8cf91c4c8da9d8eab5cd6366ef2cec266615c1fe6ad4f4faa84f25a1/diff/usr/share/jenkins
/var/lib/docker/overlay2/f1f4123687b215d1eff46d989df6c9568be89c231a83ab6105dc22c136ccf24b/diff/usr/share/jenkins
[root@iZ8vb54310gt89j8qct198Z ~]# 

限制搜索深度

  • -maxdepth

  • -mindefth

限制文件类型:文件类型有:普通文件f,目录d,符号链接 l,字符设备c,块设备b,套接字s,FIFO-p

  • -type f:搜索普通文件和目录 还有其他限制条件,可以通过命令 man find 查看

文件解压

tar -xvzf xxx.tar.gz
  • -x, --extract:解压文件

  • -v, --verbose:显示解压日志

  • -z, --gzip:通过gzip支持压缩或解压缩

  • -f, --file:指定解压文件

du 命令:显示目录或文件的大小

du(disk usage)命令主要用于显示目录或文件的大小:

$ du
du
18760   ./node_exporter-1.1.2.linux-amd64
27792   .

下面介绍几个选项参数:

  • -a, --all:显示目录下所有文件大小

  • -b, --bytes:以byte为单位

  • -h, --human-readable:文件大小以K,M,G为单位显示

  • -H, --si:文件大小以KB,MB,GB为单位(幂底数为1000)

  • -k, --kilobytes:以1024 bytes为单位

  • -m, --megabytes:以MB为单位

  • -s, --summarize:显示文件总大小

实例:

$du -hs
28M     .

$ du -ah
8.9M    ./node_exporter-1.1.2.linux-amd64.tar.gz
12K     ./node_exporter-1.1.2.linux-amd64/LICENSE
4.0K    ./node_exporter-1.1.2.linux-amd64/NOTICE
19M     ./node_exporter-1.1.2.linux-amd64/node_exporter
12K     ./node_exporter-1.1.2.linux-amd64/nohup.out
19M     ./node_exporter-1.1.2.linux-amd64
28M     .

Linux常用命令:网络命令

本文简要介绍Linux网络配置命令,包括 ip 地址、路由查看、配置等

ping

ping: 测试网络连接情况

  • -c:回应的次数

  • -i:每次ping的时间间隔

  • -I:网卡名

  • -t:ttl 数值

  • -s:数据包的大小

# ping ipv6地址
ping -6 -I eth1 2001:db8::10
# ping ipv4地址
ping -I eth1 192.168.0.1 

网络信息查询

netstat

netstat: 打印 Linux网络系统的状态信息

  • -t 列出所有tcp

  • -u 列出所有udp

  • -l 只显示监听端口

  • -n 以数字形式显示地址和端口号

  • -p 显示进程的pid和名字

netstat -t
netstat -ntlp
# 列出所有网络端口信息
netstat -a                      
# 列出所有tcp连接信息
netstat -at   
# 列出所有udp连接信息
netstat -au 
# 所有端口数据包统计信息 
netstat -s
# 显示核心路由信息 
netstat -r
# 或
route -n
route print # windows
# 显示网络接口列表
netstat -i
# 显示网络接口详细信息
netstat -ie
# 或
ifconfig

列出所有网卡信息

# 查看所有网卡信息
ifconfig  -a
ip link
netstat -i

# 查看某一个网卡
ifconfig 网卡名字 

路由配置

ipv4

route add/del -net 192.168.0.0/24 netmask 255.255.255.0 gw 192.168.0.1 dev eth1
route add/del -host 192.168.1.1 dev eth1
route add -net 23.23.23.0 netmask 255.255.255.0 reject # 屏蔽一条路由
route add/del default gw 192.168.0.1 #增加/删除默认网关

添加永久静态路由(centos7):

$ vim /etc/sysconfig/network-scripts/route-eth1
ADDRESS0=192.168.0.0/2
NETMASK0=255.255.255.0
GATEWAY0=192.168.0.1

0表示第一条静态路由。配置完成后重启网络:systemctl restart network

ipv6

ip -6 route add default via fe80::290:4cff:fe88:8888 dev eth1 # 配置默认网关
ip -6 route add 2001:db8:3333::/64 via fe80::ca3a:35ff:fe09:efa1 dev eth1 # 添加目的网络为2001:db8:3333::/64,下一跳网关为fe80::ca3a:35ff:fe09:efa1的静态路由

查看路由表

route -n
route -4 -n
route -6 -n
ip -6 route show default # 查看默认路由网关

禁用启用网卡

ifconfig eth1 up
ifconfig eth1 down

释放、更新地址

# ipv4
dhclient -r eth1
dhclient -v eth1
# ipv6
dhclient -6 -r eth1 //释放ipv6地址 
dhclient -6 //重新获取ipv6地址

重启网络:

systemctl restart network

添加、删除IP地址

# 添加IPv4地址
ifconfig eth1 192.168.1.200 netmask 255.255.255.0
ip addr add 192.168.1.200/24 dev eth1
# 添加IPv6地址
ip -6 addr add 2001:db8:1111::20 dev eth1
# 删除IPv6地址
ip -6 addr del 2001:db8:1111::20 dev eth1
ip addr del 192.168.1.200/24 dev eth1

# 激活/禁用设备
ifconfig eth0 up
ifconfig eth0 down

修改MAC地址

ifconfig eth1 hw ether MAC地址 up

设置MTU值

ifconfig eth1 mtu 1500 up

配置arp信息

# arp缓存
arp -a

# 删除arp
arp -d IP

# 添加arp
arp -s IP MAC       

设置无线网络

# 安装
sudo apt install wireless-tools
# 开启无线网卡wlan0
ifconfig wlan0 up
# 设置密码
iwconfig wlan0 key 12345678
# 设置SSID
iwconfig wlan0 essid "test"
# 加入无线网
iwconfig wlan0 ap auto
# 查看网卡信息
iwconfig wlan0
# 为无线网卡指定IP地址
ifconfig wlan0 192.168.1.30 netmask 255.255.255.0  
# 用dhclient或dhcpcd获取ip
dhclient wlan0
# 或
dhcpcd wlan0

iwconfig 的弊端是只支持WEP认证方式,要想支持WPA,需要wpa_supplicant工具,wpa_supplicant支持4种认证方式:OPEN,WEP,WPA,WPA2

Linux常用命令:性能命令

本文介绍Linux常用性能统计分析命令,监控进程或者系统性能。主要包括CPU(top、mpstat)、内存(vmstat、free)、I/O(iostat)、网络性能(sar)、系统日志信息(demsg)、查看进程状态(pidstat)。下面简要介绍这些命令的使用方法。

mpstat、iostat、pidstat和sr命令需要安装sysstat软件包,sysstat包含了系统性能监测工具,安装方法如下:

yum install sysstat # CentOS
sudo apt-get install sysstat # Ubuntu

负载

CPU负载(cpu load)指的是某个时间点进程对系统产生的压力。表示特定时间间隔内运行队列中的平均进程数,如果一个进程满足以下条件则其就会位于运行队列中:

  • 它没有在等待IO操作的结果

  • 它没有主动进入等待状态(也就是没有调用'wait')

  • 没有被停止(例如:等待终止)

单CPU满负荷运行时cpu_load为1,当多个CPU或多核时,相当于大桥有多个车道,满负荷运行时cpu_load值为CPU数或多核数;CPU负载的计算(以单CPU为例),假设一分钟内执行10个任务代表满负荷,当一分钟给出30个任务时,CPU只能处理10个,剩余20个不能处理,cpu_load=3; _images/cpu-load.png 单核CPU

  • cpu load = 1,满负载运行

  • cpu load = 0.5,半负载运行

  • cpu load = 1.7,超负载运行

一般来说,每个CPU内核当前活动进程数不大于3,则系统运行表现良好!

  • 如果多核cpu,需要累加

    • 4核cpu<12

uptime

uptime命令显示的平均负载包括了正在或准备运行在CPU上的进程和阻塞在不可中断睡眠状态(uninterruptible) I/O(通常是磁盘I/O)上的进程。

[root@server ~]# uptime
 16:54:53 up 29 days,  2:02,  1 user,  load average: 0.03, 0.03, 0.00
[root@server ~]# cat /proc/loadavg
0.03 0.03 0.00 3/166 16903
  • 显示最近1分钟、5分钟、15分钟系统负载的移动平均值,它们共同展现了负载随时间变动的情况。

  • 3:正在运行的进程数,166:总的进程数,16903:最近运行进程的ID。

ps和top命令

ps命令

ps命令是Process Status的缩写,用于查看系统进程信息

  • -e,-A:显示所有进程,包括其他用户的进程

  • -f:显示完整格式

  • -l:显示长列表

  • -a:所有进程,加上-x参数会显示没有控制终端的进程

  • -u:username,显示指定用户的进程,例如ps -u root

  • -x:显示当前用户在所有终端下的进程

  • -aux:显示所有进程,包括所有用户,分组情况

ps常用用法,通常与grep组合使用

  1. 显示dhcpd进程

ps ax | grep dhcpd | grep -v grep 
  1. ps -ef 显示所有进程

  2. ps -aux 显示所有进程

ps -aux

按照CPU或者内存用量来筛选进程:

ps -aux --sort -pcpu
# 或
ps -aux --sort -pmem

终止进程

# 强制中断正在执行的命令,如,命令长时间没有响应的情况下
Ctrl+C组合键

# kill命令
kill -9 进程ID
# killall命令:终止指定名称的所有进程
killall -9 dhclient

top命令

ps命令列出的是当前进程的快照,top可用于持续监视系统性能, 动态显示进程信息。

  • -n 获取多次cpu的执行情况,top -n 4:只更新4次

  • -d 间隔时间,top -d 4:每隔4秒更新一次

  • -p 获取指定端口进程的数据,top -p 22

每隔1秒检测指定进程的cpu,检测20次

top -d 1 -n 20

示例

打印指定pid进程的cpu信息,间隔时间为1s,打印20次 _images/top-p.png

  1. 查看进程的pid:

ps -ef | grep systemd

_images/ps-ef.png 2. 循环打印

# 打印一次
top -p 1 -n 1 | grep systemd | awk '{print $10}'
# 循环打印20次
for i in {1..20};do top -p 1 -n 1 | grep systemd | awk '{print $10}';sleep 1s;done

for((i=0;i<20;i++));do top -p 1 -n 1 | grep systemd | awk '{print $10}';sleep 1s;done

dmesg | tail

默认显示最新的10个系统信息,可以查看导致性能问题的错误信息。

1. 显示最新的20个系统信息

[root@centos7 ~]# dmesg | tail -20
[   15.356358] RPC: Registered named UNIX socket transport module.
[   15.356360] RPC: Registered udp transport module.
[   15.356361] RPC: Registered tcp transport module.
[   15.356362] RPC: Registered tcp NFSv4.1 backchannel transport module.
[   15.551529] type=1305 audit(1584428235.986:4): audit_pid=1054 old=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:auditd_t:s0 res=1
[   19.223990] NET: Registered protocol family 40
[   23.857606] ip6_tables: (C) 2000-2006 Netfilter Core Team
[   24.130255] Ebtables v2.0 registered
[   24.366128] Netfilter messages via NETLINK v0.30.
[   24.418582] ip_set: protocol 7
[   24.517273] IPv6: ADDRCONF(NETDEV_UP): ens33: link is not ready
[   24.521156] e1000: ens33 NIC Link is Up 1000 Mbps Full Duplex, Flow Control: None
[   24.524658] IPv6: ADDRCONF(NETDEV_UP): ens33: link is not ready
[   24.524669] IPv6: ADDRCONF(NETDEV_CHANGE): ens33: link becomes ready
[   24.528687] IPv6: ADDRCONF(NETDEV_UP): ens34: link is not ready
[   24.532350] e1000: ens34 NIC Link is Up 1000 Mbps Full Duplex, Flow Control: None
[   24.535760] IPv6: ADDRCONF(NETDEV_UP): ens34: link is not ready
[   24.574912] IPv6: ADDRCONF(NETDEV_UP): ens34: link is not ready
[   25.391535] nf_conntrack version 0.5.0 (16384 buckets, 65536 max)
[   25.525351] IPv6: ADDRCONF(NETDEV_CHANGE): ens34: link becomes ready
[root@centos7 ~]#

2. 显示开始的20个系统信息

[root@centos7 ~]# dmesg | head -20
[    0.000000] Initializing cgroup subsys cpuset
[    0.000000] Initializing cgroup subsys cpu
[    0.000000] Initializing cgroup subsys cpuacct
[    0.000000] Linux version 3.10.0-1062.el7.x86_64 (mockbuild@kbuilder.bsys.centos.org) (gcc version 4.8.5 20150623 (Red Hat 4.8.5-36) (GCC) ) #1 SMP Wed Aug 7 18:08:02 UTC 2019
[    0.000000] Command line: BOOT_IMAGE=/vmlinuz-3.10.0-1062.el7.x86_64 root=UUID=d7dc0c9e-a27d-4239-aba4-7c2e51d9fc93 ro crashkernel=auto spectre_v2=retpoline rhgb quiet LANG=en_US.UTF-8
[    0.000000] Disabled fast string operations
[    0.000000] e820: BIOS-provided physical RAM map:
[    0.000000] BIOS-e820: [mem 0x0000000000000000-0x000000000009ebff] usable
[    0.000000] BIOS-e820: [mem 0x000000000009ec00-0x000000000009ffff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000000dc000-0x00000000000fffff] reserved
[    0.000000] BIOS-e820: [mem 0x0000000000100000-0x000000007fedffff] usable
[    0.000000] BIOS-e820: [mem 0x000000007fee0000-0x000000007fefefff] ACPI data
[    0.000000] BIOS-e820: [mem 0x000000007feff000-0x000000007fefffff] ACPI NVS
[    0.000000] BIOS-e820: [mem 0x000000007ff00000-0x000000007fffffff] usable
[    0.000000] BIOS-e820: [mem 0x00000000f0000000-0x00000000f7ffffff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000fec00000-0x00000000fec0ffff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000fee00000-0x00000000fee00fff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000fffe0000-0x00000000ffffffff] reserved
[    0.000000] NX (Execute Disable) protection: active
[    0.000000] SMBIOS 2.7 present.
[root@centos7 ~]#

vmstat 1

全称 virtual memory stat,逐行输出虚拟内存状态统计信息

[root@centos7 ~]# vmstat
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
1  0      0 1424832   2084 195100    0    0    47     4   45   55  0  0 99  1  0

vmstat 1 :每隔一秒打印一次

[root@centos7 ~]#
[root@centos7 ~]# vmstat 1   #1s打印一个
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
1  0      0 1424472   2084 195120    0    0    28     2   30   37  0  0 99  1  0
0  0      0 1424456   2084 195120    0    0     0     0   38   53  0  0 100  0  0
0  0      0 1424456   2084 

参数解释:

  • r: 运行队列中进程数量

  • b: 等待IO的进程数量

  • swpd:使用的虚拟内存

  • free:可用内存

  • buff:用作缓冲的内存大小

  • cache:用作缓存的内存大小

  • us:用户进程执行时间(user time)

  • sy:系统进程执行时间(system time

  • id:空闲时间(包括IO等待时间),中央处理器的空闲时间

  • wa:等待IO时间

free -m

查看linux内存使用情况

[root@centos7 ~]# free -m
              total        used        free      shared  buff/cache   available
Mem:           1819         199        1471           9         148        1470
Swap:          4095           0        4095
  • Mem:物理内存

  • totel:总的物理内存 单位为:M

  • used:用掉的内存

  • free:空闲的物理内存

  • shared:共享内存

  • buff/cache:缓存内存

mpstat -P ALL 1

mpstat是Multiprocessor Statistics的缩写,实时监控CPU性能。 mpstat -P ALL 1 2:间隔1s打印报告,共打印2个

  • -P ALL:监控所有CPU

  • 1:间隔时间1s

  • 2:打印次数2次

[root@centos7 ~]# mpstat
Linux 3.10.0-1062.el7.x86_64 (centos7)  03/18/2020      _x86_64_        (4 CPU)

04:41:47 AM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
04:41:47 AM  all    0.66    0.00    1.39    2.65    0.00    0.01    0.00    0.00    0.00   95.28
[root@centos7 ~]#
[root@centos7 ~]# mpstat -P ALL 1
Linux 3.10.0-1062.el7.x86_64 (centos7)  03/18/2020      _x86_64_        (4 CPU)

04:44:11 AM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
04:44:11 AM  all    0.39    0.00    0.82    1.54    0.00    0.01    0.00    0.00    0.00   97.24
04:44:11 
[root@centos7 ~]#
  • %usr:间隔时间段内,用户态的CPU时间(%),不包含 nice值为负进程

  • %nice:nice值为负进程的CPU时间(%)

  • %sys:核心时间(%)

  • %iowait:硬盘IO等待时间(%)

  • %irq:硬中断时间(%)

  • %soft:软中断时间(%)

  • %steal:虚拟机管理器在服务另一个虚拟处理器时虚拟CPU处在非自愿等待下花费时间的百分比

  • %guest:运行虚拟处理器时CPU花费时间的百分比

  • %idle:CPU的空闲时间(%)

pidstat 1

pidstat用于监控全部或指定进程的资源占用情况,和top命令类似,但不覆盖输出,有利于观察数据随时间的变动情况,top会覆盖之前的输出

  • pidstat -p 1 1:-p 指定进程号,间隔1s打印pid为1的进程

[root@centos7 ~]# pidstat
Linux 3.10.0-1062.el7.x86_64 (centos7)  03/18/2020      _x86_64_        (4 CPU)


04:52:29 AM   UID       PID    %usr %system  %guest    %CPU   CPU  Command
04:52:29 AM     0         1    0.05    0.19    0.00    0.24     0  systemd
04:52:29 AM     0         2    0.00    0.00    0.00    0.00     3  kthreadd
04:52:29 AM     0         6    0.00    0.00    0.00    0.00     0  ksoftirqd/0
04:52:29 
  • PID:进程ID

  • %usr:进程在用户空间占用cpu的百分比

  • %system:进程在内核空间占用cpu的百分比

  • %guest:进程在虚拟机占用cpu的百分比

  • %CPU:进程占用cpu的百分比,各个CPU上的使用量的总和

  • CPU:处理进程的cpu编号

  • Command:当前进程对应的命令

iostat 1

iostat用于显示CPU和块设备(磁盘I/O)相关的统计信息

[root@centos7 ~]# iostat 1
Linux 3.10.0-1062.el7.x86_64 (centos7)  03/18/2020      _x86_64_        (4 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           0.15    0.00    0.34    0.60    0.00   98.92


Device:            tps    kB_read/s    kB_wrtn/s    kB_read    kB_wrtn
sda               9.46       158.59        15.05     142895      13561
scd0              0.02         1.14         0.00       1028          0

avg-cpu:总体cpu使用情况统计信息 linux各种设备文件在/dev目录下可以看到

  • tps:每秒进程向磁盘设备下发的IO读、写请求数量

  • kB_read/s:每秒从驱动器读入的数据量

  • kB_wrtn/s:每秒从驱动器写入的数据量

  • kB read:读入数据总量

  • kB wrtn:写入数据总量

sar命令

sar(System ActivityReporter):系统活动情况报告, 是Linux系统性能分析工具。可以用来分析磁盘I/O、CPU效率、内存使用等,下面介绍它的分析网络性能用法。

sar -n DEV 1

检查网络流量的工作负载,可用来检查网络流量是否已经达到限额。

[root@centos7 dev]# sar -n DEV 1
Linux 4.18.0-147.5.1.el8_1.x86_64 (iZ8vb54310gt89j8qct198Z)     12/19/2020      _x86_64_        (1 CPU)

08:08:37 PM     IFACE   rxpck/s   txpck/s    rxkB/s    txkB/s   rxcmp/s   txcmp/s  rxmcst/s   %ifutil
08:08:38 PM      eth0      4.00      2.00      0.23      0.27      0.00      0.00      0.00      0.00
08:08:38 PM        lo      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00
08:08:38 PM   docker0      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00

sar -n TCP 1

显示TCP连接情况,可用来描述系统负载

[root@centos7 dev]# sar -n TCP,ETCP 1
Linux 4.18.0-147.5.1.el8_1.x86_64 (iZ8vb54310gt89j8qct198Z)     12/19/2020      _x86_64_        (1 CPU)

08:15:48 PM  active/s passive/s    iseg/s    oseg/s
08:15:49 PM      0.00      0.00      1.00      1.00

08:15:48 PM  atmptf/s  estres/s retrans/s isegerr/s   orsts/s
08:15:49 PM      0.00      0.00      0.00      0.00      0.00
  • active/s:主动连接数,本地每秒创建的TCP连接数

  • passive/s:被动连接数,远程每秒创建的TCP连接数

  • retrans/s:每秒TCP重传次数

Linux和Windows创建指定大小文件方法

在测试中有时需要创建不同大小的测试文件,用于测试上传下载性能以及以及其它文件传输功能,本文介绍几种Liunx和Windows系统下创建指定大小文件的方法。

Linux系统创建指定大小文件

下面介绍的dd 、fallocate和truncate命令包含于GNU coreutils软件包中,不需要单独安装。

dd命令

dd (device driver) 命令常用来复制备份文件,与cp命令具有以下区别:

  • dd是对块进行操作,操作磁盘的扇区字节,

  • cp操作文件或目录,对于不能以文件或目录格式呈现的数据cp无法复制。

  • dd是对磁盘连续的读取,也就是完全的数据搬移,cp复制的数据排列不是按顺序的。

也可以使用这个命令来创建特定大小的文件。

root@Server ~]# dd if=/dev/urandom of=testfile10MB_dd bs=10MB count=1
记录了1+0 的读入
记录了1+0 的写出
10000000字节(10 MB)已复制,0.124436 秒,80.4 MB/秒
root@Server ~]# ll testfile10MB_dd
-rw-r--r--   1 root    root    10000000 7月   7 11:56 testfile10MB_dd
[root@Server ~]# du testfile10MB_dd
9768    testfile10MB_dd

/dev/urandom用于生成随机数据,也可以使用/dev/zero来生成全0的文件:

[root@Server ~]# dd if=/dev/zero of=testfile10MB_dd0 bs=10MB count=1
记录了1+0 的读入
记录了1+0 的写出
10000000字节(10 MB)已复制,0.00799675 秒,1.3 GB/秒
[root@Server ~]# ll testfile10MB_dd0
-rw-r--r--   1 root    root    10000000 7月   7 13:57 testfile10MB_dd0
[root@Server ~]# od -c testfile10MB_dd0
0000000  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
*
46113200
[root@Server ~]# 

/dev/urandom、/dev/random以及/dev/zero、/dev/null介绍

  • /dev/urandom和/dev/random都可以产生随机的ASCII码字符流,其中/dev/random依赖系统中断,当系统中断不足时,/dev/random设备会“挂起”。/dev/urandom不依赖系统中断,所以在生成特定大小文件时一般使用/dev/urandom,不使用/dev/urandom。

  • /dev/zero “零”设备可以无限的提供空字符,产生二进制的零流

  • /dev/null “空”设备,像”黑洞“一样,所有写入它的内容都会永远丢失,也不会读取到任何内容。常用于禁止标准输出和标准错误的输出,比如抓包命令:tcpdump -i eth1 -w /tmp/packet.pcap >/dev/null &

根据/dev/urandom的特性,也可以结合head命令来创建指定大小的文件:

head -c 10MB /dev/urandom > testfile10MB
# 或者
head -c 10MB /dev/zero > testfile10MB

bs参数和truncate命令的size参数类似,默认单位为bytes,也支持以下单位:

  • c =1 bytes, w =2 bytes, b =512 bytes

  • K, M, G, T, P, E, Z, Y(幂底数为1024 bytes,如5M=5×1024×1024)

  • KB, MB, GB ...(幂底数为1000 bytes,如5MB=5×1000×1000)

fallocate命令

fallocate用于创建大文件(大于2G):

[root@Server ~]# fallocate -l 2G testfile2G_fal
[root@Server ~]# ll testfile2G_fal
-rw-r--r--   1 root    root    2147483648 7月   7 14:01 testfile2G_fal

-l参数指定文件大小,默认单位为bytes,也可以指定单位:K, M, G, T, P, E, Z, Y以及KB, MB, GB等

truncate命令

truncate命令也可以用来创建指定大小的文件,下面创建一个10 MB大小的文件

[root@Server ~]# truncate -s 10M testfile10M
[root@Server ~]# ll testfile10M
-rw-r--r--   1 root    root    10485760 7月   7 10:45 testfile10M
[root@Server ~]# 
[root@Server ~]# truncate -s 10MB testfile10Mb
[root@Server ~]# ll testfile10Mb
-rw-r--r--   1 root    root    10000000 7月   7 10:49 testfile10Mb

-s | --size参数 用于指定要生成的文件大小,单位可以是:

  • K, M, G, T, P, E, Z, Y(幂底数为1024 bytes,如5M=5×1024×1024)

  • KB, MB, GB ...(幂底数为1000 bytes,如5MB=5×1000×1000)

dd 、fallocate和truncate的区别

truncate命令生成的是空洞文件,并不占用实际的磁盘空间,文件中间是用“\0”填充的,实际占用的空间为0。使用du命令查看truncate生成文件占用的磁盘空间:

[root@Server ~]# ll testfile10Mb
-rw-r--r-- 1 root root 10000000 7月   7 14:30 testfile10Mb
[root@Server ~]# du -sh testfile10Mb
0       testfile10Mb
[root@Server ~]# od -c testfile10Mb
0000000  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
*
46113200
[root@Server ~]# 

fallocate命令为文件预分配物理空间,分配的空间在磁盘的扇区上是连续的,生成的不是空洞文件,不是空洞文件那样“假装”占有那么多空间:

[root@Server ~]# ll testfile2G_fal
-rw-r--r-- 1 root root 2147483648 7月   7 14:01 testfile2G_fal
[root@Server ~]# du -sh testfile2G_fal
2.0G    testfile2G_fal

可以看到,和truncate不一样,用fallocate生成的文件在磁盘上确实占用了2.0G的空间。

dd命令生成的文件也不是空洞文件,使用它来生成大文件时速度较慢,而且使用dd以及提到的head命令生成文件时会进行大量IO操作,所以在Linux中生成文件时,建议使用fallocate命令。

Windows系统创建指定大小文件

fsutil工具

Windows中可以使用fsutil工具生成文件,命令语法格式如下:

fsutil file createNew test.txt 1024 # 文件大小单位为bytes

以管理员身份打开cmd,创建一个5M bytes的文件:5×1024×1024=5242880 bytes

C:\Users\DELL> fsutil file createNew test.txt 5242880
File C:\Users\DELL\test.txt is created
C:\Users\DELL> dir test.txt | findstr test.txt
2021/07/07  15:26         5,242,880 test.txt

Centos 虚拟机配置

克隆虚拟机后设置静态IP

克隆虚拟机后设置静态IP无效的解决方法

1. 获取虚拟机网卡的MAC地址

通过下面的其中一个命令获取要设置的网卡MAC地址

ip link show
ifconfig -a
ip address show

_images/ip_link.png

2. 修改70-persistent-ipoib.rules 文件

将eth0的MAC地址改为第一步获取到的地址

vim /etc/udev/rules.d/70-persistent-ipoib.rules

_images/persistent.png

3. 修改网卡配置文件

将对于网卡配置文件的MAC地址也改为第一步获取到的地址

vim /etc/sysconfig/network-scripts/ifcfg-eth0

_images/ifcfg-eth0.png

4. 重启

重启网络服务

systemctl restart network

systemctl restart network失败

systemctl restart network 重启网络失败

[root@haiyong rules.d]# systemctl restart network
Job for network.service failed because the control process exited with error code. See "systemctl status network.service" and "journalctl -xe" for details.
[root@haiyong rules.d]# journalctl -xe
-- 
-- The start-up result is done.
Jun 19 12:10:01 haiyong CROND[5949]: (root) CMD (/usr/lib64/sa/sa1 1 1)
Jun 19 12:10:10 haiyong polkitd[754]: Registered Authentication Agent for unix-process:
Jun 19 12:10:10 haiyong systemd[1]: Starting LSB: Bring up/down networking...
-- Subject: Unit network.service has begun start-up
-- Defined-By: systemd
-- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-- 
-- Unit network.service has begun starting up.
Jun 19 12:10:10 haiyong NetworkManager[939]: <warn>  [1624075810.7721] ifcfg-rh:     mi
Jun 19 12:10:10 haiyong network[5992]: Bringing up loopback interface:  [  OK  ]
Jun 19 12:10:10 haiyong NetworkManager[939]: <warn>  [1624075810.8999] ifcfg-rh:     mi
Jun 19 12:10:10 haiyong NetworkManager[939]: <info>  [1624075810.9472] agent-manager: r
Jun 19 12:10:10 haiyong NetworkManager[939]: <info>  [1624075810.9481] audit: op="conne
Jun 19 12:10:10 haiyong network[5992]: Bringing up interface ens33:  Error: Connection 
Jun 19 12:10:10 haiyong network[5992]: [FAILED]
Jun 19 12:10:11 haiyong NetworkManager[939]: <info>  [1624075811.0139] agent-manager: r
Jun 19 12:10:11 haiyong NetworkManager[939]: <info>  [1624075811.0152] audit: op="conne
Jun 19 12:10:11 haiyong network[5992]: Bringing up interface ens37:  Error: Connection 
Jun 19 12:10:11 haiyong network[5992]: [FAILED]
Jun 19 12:10:11 haiyong network[5992]: RTNETLINK answers: File exists
Jun 19 12:10:11 haiyong network[5992]: RTNETLINK answers: File exists
Jun 19 12:10:11 haiyong network[5992]: RTNETLINK answers: File exists
Jun 19 12:10:11 haiyong network[5992]: RTNETLINK answers: File exists
Jun 19 12:10:11 haiyong network[5992]: RTNETLINK answers: File exists
Jun 19 12:10:11 haiyong network[5992]: RTNETLINK answers: File exists
Jun 19 12:10:11 haiyong network[5992]: RTNETLINK answers: File exists
Jun 19 12:10:11 haiyong network[5992]: RTNETLINK answers: File exists
Jun 19 12:10:11 haiyong network[5992]: RTNETLINK answers: File exists
Jun 19 12:10:11 haiyong systemd[1]: network.service: control process exited, code=exite
Jun 19 12:10:11 haiyong systemd[1]: Failed to start LSB: Bring up/down networking.
-- Subject: Unit network.service has failed
-- Defined-By: systemd
-- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-- 
-- Unit network.service has failed.
-- 
-- The result is failed.
Jun 19 12:10:11 haiyong systemd[1]: Unit network.service entered failed state.
Jun 19 12:10:11 haiyong systemd[1]: network.service failed.
Jun 19 12:10:11 haiyong polkitd[754]: Unregistered Authentication Agent for unix-proces

解决方法:

[root@haiyong rules.d]# systemctl stop NetworkManager
[root@haiyong rules.d]# systemctl disable NetworkManager
Removed symlink /etc/systemd/system/multi-user.target.wants/NetworkManager.service.
Removed symlink /etc/systemd/system/dbus-org.freedesktop.nm-dispatcher.service.
Removed symlink /etc/systemd/system/network-online.target.wants/NetworkManager-wait-online.service.
[root@haiyong rules.d]# systemctl restart network

关闭防火墙

查看防⽕火墙状态

systemctl status firewalld
systemctl status firewalld.service

停⽌止firewall

systemctl stop firewalld.service

禁止firewall开机启动

systemctl disable firewalld.service 

关闭selinux

vi /etc/selinux/config

注释SELINUX=enforcing,添加SELINUX=disabled

# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
#     enforcing - SELinux security policy is enforced.
#     permissive - SELinux prints warnings instead of enforcing.
#     disabled - No SELinux policy is loaded.
# SELINUX=enforcing
SELINUX=disabled
# SELINUXTYPE= can take one of three values:
#     targeted - Targeted processes are protected,
#     minimum - Modification of targeted policy. Only selected processes are protected.
#     mls - Multi Level Security protection.
SELINUXTYPE=targeted

时钟同步

ntpdate是一个linux时间同步服务软件,一般默认情况下是未安装。

1. 配置时间服务器

使用root⽤户

[root@linux .ssh]# ntpdate
-bash: ntpdate: command not found

安装ntpdate:

yum -y install ntpdate
yum -y install ntp
[root@linux ~]# systemctl status ntpd.service
● ntpd.service - Network Time Service
   Loaded: loaded (/usr/lib/systemd/system/ntpd.service; disabled; vendor preset: disabled)
   Active: inactive (dead)
[root@linux ~]# rpm -qa | grep ntp
ntpdate-4.2.6p5-29.el7.centos.2.x86_64
ntp-4.2.6p5-29.el7.centos.2.x86_64

编辑/etc/ntp.conf

vim /etc/ntp.conf

restrict 127.0.0.1
restrict ::1

# Hosts on local network are less restricted.
restrict 192.168.183.0 mask 255.255.255.0 nomodify notrap

# Use public servers from the pool.ntp.org project.
# Please consider joining the pool (http://www.pool.ntp.org/join.html).
# server 0.centos.pool.ntp.org iburst
# server 1.centos.pool.ntp.org iburst
# server 2.centos.pool.ntp.org iburst
# server 3.centos.pool.ntp.org iburst

server 127.127.1.0 # local clock
fudge 127.127.1.0 stratum 10

_images/ntp.png 保证BIOS与系统时间同步

vim /etc/sysconfig/ntpd ,添加:

# Command line options for ntpd
OPTIONS="-g"
SYNC_HWLOCK=yes

启动ntpd服务

systemctl start ntpd.service

设置ntpd的服务开机启动

chkconfig ntpd on
systemctl enable ntpd.service

设置时间同步:

# 通过⽹络连接外⽹进⾏时钟同步
ntpdate us.pool.ntp.org;
# 阿⾥云时钟同步服务器
ntpdate ntp4.aliyun.com

2. 其他机器配置

使用root⽤户

安装ntpdate:

yum -y install ntpdate

在其他机器配置10分钟与时间服务器同步⼀次 编写脚本

crontab -e

输入如下内容:

*/10 * * * * /usr/sbin/ntpdate 192.168.183.121

修改任意机器时间

date -s "2020-06-20 11:11:11"

查看crontab任务

crontab -l

查看crontab的执行日志

tail -n 30 -f /var/log/cron

安装jdk

查看系统⾃带的openjdk,如果有,卸载系统⾃带的openjdk

[root@linux ~]# rpm -qa | grep java
[root@linux ~]# 

使用rz命令上传jdk-8u231-linux-x64.tar.gz文件,注意不要勾选Upload files as ASCII

解压jdk

tar -zxvf jdk-8u231-linux-x64.tar.gz -C ../servers/

配置环境变量

vi /etc/profile

export JAVA_HOME=/opt/bigdata/servers/jdk1.8.0_231
export PATH=:$JAVA_HOME/bin:$PATH

使配置文件生效

source /etc/profile
[root@linux software]# java -version
java version "1.8.0_231"
Java(TM) SE Runtime Environment (build 1.8.0_231-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.231-b11, mixed mode)

配置Linux主机名

为了方便区分局域网中的多个Linux主机,可以为每台机器设置主机名,本文介绍hostname配置方法。

1. 配置Linux hostname

下面配置两台centos7 虚拟机,主机名分别配置为client和server,它们主机IP 地址分别为192.168.30.8和192.168.30.9。

配置client主机

[root@client ~]# vi /etc/sysconfig/network

添加如下内容,保存:

# Created by anaconda
NETWORKING=yes
hostname=client

重启网络:

[root@client ~]# systemctl restart network
[root@client ~]# hostname
client
[root@client ~]# 

如果不生效可以使用如下命令:

[root@client ~]# hostnamectl set-hostname client

配置server主机

[root@server ~]# hostnamectl set-hostname server

重启网络:

[root@server ~]# systemctl restart network
[root@server ~]# hostname
server
[root@server ~]# uname -n
server

2. 配置hostname与IP映射

配置client和server的hosts文件

vi /etc/hosts

添加如下内容:

192.168.30.8 client
192.168.30.9 server

3. 测试

通过ping hostname来测试是否配置成功:

client ping server:

[root@client ~]# ping server -c 3
PING server (192.168.30.9) 56(84) bytes of data.
64 bytes from server (192.168.30.9): icmp_seq=1 ttl=64 time=0.616 ms
64 bytes from server (192.168.30.9): icmp_seq=2 ttl=64 time=0.384 ms
64 bytes from server (192.168.30.9): icmp_seq=3 ttl=64 time=0.566 ms

--- server ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2001ms
rtt min/avg/max/mdev = 0.384/0.522/0.616/0.099 ms
[root@client ~]# 

server ping client:

[root@Server ~]# ping client -c 3
PING client (192.168.30.8) 56(84) bytes of data.
64 bytes from client (192.168.30.8): icmp_seq=1 ttl=64 time=0.502 ms
64 bytes from client (192.168.30.8): icmp_seq=2 ttl=64 time=0.678 ms
64 bytes from client (192.168.30.8): icmp_seq=3 ttl=64 time=0.323 ms

--- client ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 0.323/0.501/0.678/0.144 ms
[root@Server ~]# 

配置hostname与IP映射后,可以直接ping主机名而不用ping IP地址了。

4. 配置windows hosts

配置windows hosts,以便在windows下面能通过主机名进行访问。

编辑 C:\Windows\System32\drivers\etc\hosts文件,添加如下内容:

192.168.30.8 client
192.168.30.9 server

保存

5. windows测试

C:\Users\10287>ping client -n 3

正在 Ping client [192.168.30.8] 具有 32 字节的数据:
来自 192.168.30.8 的回复: 字节=32 时间<1ms TTL=64
来自 192.168.30.8 的回复: 字节=32 时间<1ms TTL=64
来自 192.168.30.8 的回复: 字节=32 时间<1ms TTL=64

192.168.30.8 的 Ping 统计信息:
    数据包: 已发送 = 3,已接收 = 3,丢失 = 0 (0% 丢失),
往返行程的估计时间(以毫秒为单位):
    最短 = 0ms,最长 = 0ms,平均 = 0ms

配置多台服务器之间ssh免密登录

使用scp 或者 rsync命令在多台Linux服务器之间同步文件时需要输入密码,除了使用expect实现自动化交互以外,还有一种方法就是配置服务器之间ssh免密登录,本文记录一下具体配置过程。

1. 创建.ssh目录

假定有3台Linux主机,分别为A,B,C

在所有主机上创建ssh目录并赋予权限

mkdir /root/.ssh 
chmod 700 /root/.ssh

2. 生成公钥与私钥

所有主机生成公钥与私钥,执行以下命令:

$ cd ~  # 进⼊入用户目录
$ ssh-keygen -t rsa -P ""  # 生成ssh密码,-t 参数表示生成算法,可以选择rsa和dsa;-P表示使用的密码,""表示无密码。

3. 将公钥追加authorized_keys文件中

将第一台主机A上生成公钥追加到authorized_keys文件中

$ cd ~/.ssh  # 进入.ssh目录
$ cat id_rsa.pub >> authorized_keys   # 将id_rsa.pub的内容追加到authorized_keys文件中

然后可以删除A上的id_rsa.pub文件,因为已经写进了authorized_keys文件中

$ rm -rf id_rsa.pub 
或者
$ mv id_rsa.pub id_rsa.pub.copy

接下来将B和C的id_rsa.pub写入到A的authorized_keys文件中,使用scp 或者 rsync命令分别将B和C两台机器的id_rsa.pub复制到主机A 。(scp 或者 rsync命令的使用方法可参考文章使用SCP或Rsync实现Linux主机之间文件、目录的复制

在主机B上操作 :

$ scp id_rsa.pub hostA:~/.ssh/ # hostA为A的主机名或者A的IP地址

也可以直接在主机A上操作,执行如下命令:

$ scp hostB:~/.ssh/id_rsa.pub ~/.ssh/

在主机A上执行如下命令,将主机B的id_rsa.pub文件内容添加到authorized_keys文件中:

$ cat id_rsa.pub >> authorized_keys
$ mv id_rsa.pub id_rsa.pub.copy2

主机C类似,将C的id_rsa.pub文件内容添加到authorized_keys文件中。

这样authorized_keys文件里面保存了主机A,B,C的公钥,然后将authorized_keys文件拷贝到其它两台主机上就可以了:

$ scp authorized_keys hostB:/root/.ssh/
$ scp authorized_keys hostC:/root/.ssh/

4. 测试

ssh root@要进行链接的机器ip地址

主机A -> B:

[root@hostA ~]# ssh root@192.168.20.20
Last login: Sat Jul 10 10:17:34 2021 from hostA
[root@hostB ~]# 

主机B -> A:

[root@hostB ~]# ssh root@192.168.20.10
Last login: Sun Jul 11 19:54:08 2021 from hostB
[root@hostA ~]# 

使用samba实现linux和windows文件共享

Samba是用于Linux/Unix系统与Windows之间共享文件的软件,本文记录一下Samba的安装及使用方法。

samba简介

samba的功能都是通过一个CIFS(Common Internet File System)协议套件来管理的,这个名字是由微软引入的。

Samba是一个开源的CIFS实现,官网地址为 https://www.samba.org/samba/

SMB (Server Message Block Protocol)协议是一种客户端/服务器通信协议,它主要包括smbd 和 nmbd,提供四种基本服务:

  1. 文件、打印服务:由SMB守护进程smbd提供

  2. 验证和授权:“共享模式”和“用户模式”

  3. 域解析:模拟Windows NT域系统,主要包括广播和点对点两种形式,还有一种是使用NBNS (NetBIOS Name Service)服务器,微软称为WINS服务(Windows Internet Name Service)

  4. 服务声明(浏览):声明网络上计算机提供的可浏览服务(文件和打印共享)列表。

前两个服务由smbd实现,后两个由nmbd来实现。

samba安装

centos7:

sudo yum install -y samba
sudo yum install -y samba-client

ubuntu:

sudo apt update
sudo apt install samba
sudo apt install samba-client

smbclient是一个smb服务器的客户端管理程序。

查看安装状态

$ whereis samba
samba: /usr/lib64/samba /etc/samba /usr/libexec/samba /usr/share/man/man7/samba.7.gz
$ rpm -qa | grep samba
samba-common-4.10.16-15.el7_9.noarch
samba-client-4.10.16-15.el7_9.x86_64
samba-client-libs-4.10.16-15.el7_9.x86_64
samba-common-libs-4.10.16-15.el7_9.x86_64
samba-libs-4.10.16-15.el7_9.x86_64
samba-common-tools-4.10.16-15.el7_9.x86_64
samba-4.10.16-15.el7_9.x86_64
$ smbd --version
Version 4.10.16

samba配置

1. 查看windows工作组

通过cmd命令 net config workstation 查看工作组:

C:\Users\10287>net config workstation
计算机名                     \\DESKTOP-EHODIV3
计算机全名                   DESKTOP-EHODIV3
用户名                       Administrator

工作站正运行于
        NetBT_Tcpip_{E484BACB-E20F-47EB-8727-EF799C2C041E} (0A0027000016)

软件版本                     Windows 10 Home China

工作站域                     WORKGROUP
登录域                       DESKTOP-EHODIV3

COM 打开超时 ()            0
COM 发送计数 (字节)          16
COM 发送超时 (毫秒)          250
命令成功完成。

或者查看系统属性:此电脑 -> 属性 -> 高级系统设置 -> 计算机名 查看工作组 _images/windows-workgroup.jpg

2. 关闭防火墙

配置之前先关闭linux防火墙

查看防⽕火墙状态

systemctl status firewalld
systemctl status firewalld.service

停⽌止firewall

systemctl stop firewalld.service

禁止firewall开机启动

systemctl disable firewalld.service 
[root@Server apTest]# systemctl start smb.service
[root@Server apTest]# 
[root@Server apTest]# 
[root@Server apTest]# netstat -antpu| grep smb
tcp        0      0 0.0.0.0:139             0.0.0.0:*               LISTEN      5164/smbd           
tcp        0      0 0.0.0.0:445             0.0.0.0:*               LISTEN      5164/smbd           
tcp6       0      0 :::139                  :::*                    LISTEN      5164/smbd           
tcp6       0      0 :::445                  :::*                    LISTEN      5164/smbd           
[root@Server apTest]# 

关闭selinux

vi /etc/selinux/config

注释SELINUX=enforcing,添加SELINUX=disabled

# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
#     enforcing - SELinux security policy is enforced.
#     permissive - SELinux prints warnings instead of enforcing.
#     disabled - No SELinux policy is loaded.
# SELINUX=enforcing
SELINUX=disabled
# SELINUXTYPE= can take one of three values:
#     targeted - Targeted processes are protected,
#     minimum - Modification of targeted policy. Only selected processes are protected.
#     mls - Multi Level Security protection.
SELINUXTYPE=targeted

3. 修改配置文件

先创建一个共享目录或者使用已有的目录。

$ mkdir -p /var/samba/share
$ touch /var/samba/share/test.txt

配置读写权限

chmod -R 777 /var/samba

配置smb.conf文件:vi /etc/samba/smb.conf

添加的共享名为myshare,这个名称是windows访问时会显示的名称,可以随意设置。

[global]
        workgroup = WORKGROUP
        security = user

        passdb backend = tdbsam

        printing = cups
        printcap name = cups
        load printers = yes
        cups options = raw

[homes]
        comment = Home Directories
        valid users = %S, %D%w%S
        browseable = No
        read only = No
        inherit acls = Yes

[printers]
        comment = All Printers
        path = /var/tmp
        printable = Yes
        create mask = 0600
        browseable = No

[print$]
        comment = Printer Drivers
        path = /var/lib/samba/drivers
        write list = @printadmin root
        force group = @printadmin
        create mask = 0664
        directory mask = 0775

[myshare]
		comment = my server share dir
		path = /var/samba/share
		public = yes
		writable = yes
		browseable = yes
		guest ok = yes
		guest only = yes
		read only = no
        
        

4. 配置samba登录用户密码

可以使用groupadduseradd命令添加用户组,下面我直接使用root用户:

$ smbpasswd -a root
New SMB password:
Retype new SMB password:
Added user root.

新输的密码就是远程登录密码。

5. 启动服务

配置文件设置完成后启动samba服务,并设置开机启动

启动 smb.servicenmb.service两个服务

systemctl start smb.service
systemctl start nmb.service

重启smb服务命令:systemctl restart smb.service

设置开机启动

systemctl enable smb.service
systemctl enable nmb.service

6. windows访问共享文件

win + r 输入samba服务器地址,访问samba共享文件

_images/win-r-samba.jpg 也可以在文件浏览器中输入地址 \\192.168.30.9 访问共享文件。

输入用户名密码后就可以访问Linux共享文件了!

_images/windows-samba-file.jpg 可以对myshare中的文件进行读写操作以及文件创建。

smbclient使用

samba-client是linux中的客户端管理程序,如果要在linux/unix中访问samba文件可以使用smbclient工具。

登录samba服务器

$ smbclient //192.168.30.9/myshare
Enter SAMBA\root's password: 
Try "help" to get a list of possible commands.
smb: \> 

或者

$ smbclient //192.168.30.9/myshare/ -U root%12345678
Try "help" to get a list of possible commands.
smb: \> 

登录成功后就可以对共享文件进行访问了:

smb: \> ls
  .                                   D        0  Sun Aug 22 10:17:09 2021
  ..                                  D        0  Sun Aug 22 09:03:44 2021
  test.txt                            N        0  Sun Aug 22 09:30:59 2021

                60273916 blocks of size 1024. 52785976 blocks available
smb: \> 

下载

下载文件:

smb: \> get test.txt /root/samba/test.txt
getting file \test.txt of size 0 as /root/samba/test.txt (0.0 KiloBytes/sec) (average 0.0 KiloBytes/sec)
smb: \> 
$ ll /root/samba/
total 0
-rw-r--r--. 1 root root 0 Aug 22 10:39 test.txt

指定日志存放目录

get test.txt /root/samba/test.txt -l /tmp/smb/smbalog

下载目录:

$ smbclient //192.168.30.9/myshare/ -U root%12345678 -c 'prompt OFF; recurse ON; cd /sambafolder/; lcd /tmp/smb/localfolder/; mget *' -l /tmp/smb/smbalog

上传

上传文件

smb: \> put /root/samba/test.txt test.txt

上传目录

$ smbclient //192.168.30.9/myshare/ -U root%12345678 -c 'prompt OFF; recurse ON; cd /sambafolder/; lcd /tmp/smb/localfolder/; mput *' -l /tmp/smb/smbalog

更多smbclient使用方法参考:https://www.samba.org/samba/docs/current/man-html/smbclient.1.html

参考文档:

  1. https://www.liquidweb.com/kb/how-to-install-samba-on-linux-windows/

  2. https://www.samba.org/samba/docs/SambaIntro.html

Linux Bash编程:Fisher–Yates shuffle 洗牌算法

本文介绍使用shell语法来实现Fisher–Yates shuffle 洗牌算法。

Fisher-Yates shuffle 算法简介

Fisher–Yates shuffle 洗牌算法可以用于对数组进行随机排列,它的时间复杂度为O(n),伪代码如下:

To shuffle an array a of n elements (indices 0..n-1):
for i from n - 1 downto 1 do
	j = random integer with 0 <= j <= i
	exchange a[j] and a[i]

假定有一个数组a=[1, 2, 3, 4, 5, 6, 7, 8, 9],数组长度为n,打乱a中元素的具体迭代步骤如下:

  1. 生成一个[0, n-1]区间的随机数k;

  2. 将第k个元素和第n-1个元素进行交换;

  3. 进行下一轮迭代,生成一个[0, n-2]区间的随机数k,将第k个元素和第n-2个元素进行交换, 迭代次数为n-1次:从n-1取到1;

  4. 最终得到一个打乱的数组。

下表是一个数组的具体打乱过程,打乱后的数组是(9 4 8 1 2 3 5 6 7)

随机数 原数组 新数组
0-8:6 a = (1 2 3 4 5 6 7 8 9) 交换a[8]和a[6] :(1 2 3 4 5 6 9 8 7)
0-7:5 a = (1 2 3 4 5 6 9 8 7) 交换a[7]和a[5] :(1 2 3 4 5 8 9 6 7)
0-6:4 a = (1 2 3 4 5 8 9 6 7) 交换a[6]和a[4] :(1 2 3 4 9 8 5 6 7)
0-5:2 a = (1 2 3 4 9 8 5 6 7) 交换a[5]和a[2] :(1 2 8 4 9 3 5 6 7)
0-4:1 a = (1 2 8 4 9 3 5 6 7) 交换a[4]和a[1] :(1 9 8 4 2 3 5 6 7)
0-3:0 a = (1 9 8 4 2 3 5 6 7) 交换a[3]和a[0] :(4 9 8 1 2 3 5 6 7)
0-2:2 a = (4 9 8 1 2 3 5 6 7) 交换a[2]和a[2] :(4 9 8 1 2 3 5 6 7)
0-1:0 a = (4 9 8 1 2 3 5 6 7) 交换a[1]和a[0] :(9 4 8 1 2 3 5 6 7)

shell实现

shuffle.sh :

#!/bin/bash

shuffle() {
   local i tmp size max rand
   # 打乱顺序
   # Knuth-Fisher-Yates shuffle algorithm
   size=${#my_array[*]}
   max=$(( 32767 / size * size ))
   # echo "max: $max"
   for ((i=size-1; i>0; i--)); do
      while (( (rand=$RANDOM) >= max )); do :; done
      rand=$(( rand % (i+1) ))    
      # 交换
      tmp=${my_array[i]} 
      my_array[i]=${my_array[rand]} 
      my_array[rand]=$tmp
      echo ${my_array[*]}
   done
}

my_array=(1 2 3 4 5 6 7 8 9)
shuffle
echo ${my_array[*]}

执行效果:

$ sh shuffle.sh 
1 2 3 4 9 6 7 8 5
1 8 3 4 9 6 7 2 5
7 8 3 4 9 6 1 2 5
7 8 6 4 9 3 1 2 5
7 8 6 9 4 3 1 2 5
7 9 6 8 4 3 1 2 5
7 6 9 8 4 3 1 2 5
7 6 9 8 4 3 1 2 5

参考:

  1. https://www.geeksforgeeks.org/shuffle-a-given-array-using-fisher-yates-shuffle-algorithm/

  2. https://gaohaoyang.github.io/2016/10/16/shuffle-algorithm/#top

  3. https://stackoverflow.com/questions/5533569/simple-method-to-shuffle-the-elements-of-an-array-in-bash-shell

随机数生成、对浮点数进行四舍五入运算

本文介绍使用shell实现随机数生成以及对浮点数进行四舍五入运算

随机数生成

生成0-1之间的随机数

生成0-1的随机数:

#!/bin/bash
random_number=`echo "scale=4 ; ${RANDOM}/32767" | bc -l` # 生成0-1的随机数
# random_number=`bc -l <<< "scale=4 ; ${RANDOM}/32767"`
echo $random_number

exit 0

执行:

$ sh random.sh 
.8696
$ sh random.sh 
.4517
$ sh random.sh 
.5126
  • ${RANDOM}函数产生0 - 32767之间的伪随机整数。其中32767(2^15 - 1)是有符号16位整数的上限。

  • scale=4:保留4位小数

生成0-n之间的随机数

生成0-10之间的随机数:

#!/bin/bash
size=10
max=$(( 32767 / size * size ))
while (( (rand=$RANDOM) >= max )); do :; done
rand=$(( rand % (size+1) )) 
echo $rand

生成1-10之间的随机数:

#!/bin/bash
size=10
max=$(( 32767 / size * size ))
while (( (rand=$RANDOM) >= max )); do :; done
rand=$(( rand % (size) + 1 )) 
echo $rand

max=$(( 32767 / size * size ))语句比较关键,这么处理的原因是${RANDOM}产生的最大数是32767,如果生成1-10之间的随机数,需要去掉32761-32767之间的数,否则会导致出现9和10的概率和其它数不一样。

对浮点数进行四舍五入运算

可以使用 printf "%.*f\n" [精度] [浮点数] 命令对浮点数进行四舍五入运算。

$ printf "%.*f\n" 0 6.666
7
$ printf "%.*f\n" 1 6.666
6.7
$ printf "%.*f\n" 2 6.666
6.67

bash脚本示例:

#!/bin/bash

random_number=`echo "scale=4 ; ${RANDOM}/32767" | bc -l` # 生成0-1的随机数
number=`echo "$random_number*100" | bc`
echo $number
number_round1=`echo $number | xargs printf "%.*f\n" 0`
echo $number_round1

number_round2=`echo $number | xargs printf "%.*f\n" 1`
echo $number_round2

exit 0

执行结果如下:

97.8900
98
97.9

参考:

  1. https://unix.stackexchange.com/questions/167058/how-to-round-floating-point-numbers-in-shell

Linux Bash编程:将整数分解为n个随机数

本文介绍使用shell实现将一个整数m随机分解为n个数。

要求:

  1. 将一个整数m分解为n个随机数,n个随机数之和要等于m

  2. 指定随机数的最小值

分析:

这与leetcode上的两道题类似:

  1. 343. 整数拆分

  2. 剑指 Offer 14- I. 剪绳子

下面来介绍一种思路:

  1. 随机抽取 n-1 个区间为(0, m)的数,得到数组a

  2. 0m加入数组a

  3. 对数组a进行升序排序

  4. 按顺序计算数组a中相邻元素的差值:后一个元素减去前一个元素。差值组成的数组就是我们要的结果。

shell脚本SplitInteger.sh:

#!/bin/bash

SplitInteger()
{    
    let SIZE_BYTES=$SIZE_BYTES-$NUMBER*$minNum
    declare -a num_list
    num_list[0]=0
    num_list[1]=$SIZE_BYTES
    let num=$NUMBER
    for i in $(seq 2 $num); do
        random_rate=`echo "scale=4 ; ${RANDOM}/32767" | bc -l` # 生成0-1的随机数 
        # let random_bytes=$(( SIZE_BYTES*random_rate ))
        random_bytes=`echo "$SIZE_BYTES*$random_rate" | bc` # 字符类型转换为数字类型进行运算
        # echo "$random_bytes"
        num_list[$i]=`echo $random_bytes | xargs printf "%.*f\n" 0` # 对结果进行四舍五入计算
    done

    # echo "Array in unsorted order :"
    # echo ${num_list[*]}

    num_length=${#num_list[*]}
    BubbleSort   # 排序

    # 计算差值

    let rand_len=$num_length-2
    for i in $(seq 0 $rand_len); do
        new_list[$i]=`echo "${num_list[$(( i+1 ))]}-${num_list[$i]}+$minNum" | bc`
    done

    # echo "Diff Array:"
    echo "${new_list[*]}"

    sum=0
    for (( i=0;i<${#new_list[*]};i++ ))
    do
        let sum=sum+${new_list[$i]}
    done

    echo $sum

}

let SIZE_BYTES=100
let NUMBER=10
let minNum=5
SplitInteger
exit 0

执行:

$ sh SplitInteger.sh 
8 12 6 16 9 12 11 9 5 12
100

BubbleSort为冒泡排序方法,具体实现参考Linux Bash编程:字符串处理

Linux Bash之getopt命令行参数解析

Unix shell 中内置了命令行参数解析函数getopts,但它仅支持简单的参数解析,不支持长参数,getopt是getopts的增强版,支持长参数。在Python笔记:命令行参数解析中介绍了Python中的命令行参数解析方法getopt(),本文介绍shell中如何使用getopt进行命令行参数解析。

先看下面脚本(test_getopt.sh):

#!/bin/bash

FIELD=unset
DF=unset
COUNT=unset
green='\033[32m'

help()
{
  Usage="Usage: sh test_getopt.sh [OPTION]  \n\
  Options:\n\
        [ -f | --field FIELD]  \t\t-- 字段 \n \
        [ -Y | --display-filter DF] \t-- 条件 \n \
        [ -c | --count COUNT ]  \t-- 计数 \n \
        [ -h | --help ]  \t\t-- 帮助信息  \n \
        "
  echo -e ${green} $Usage
  exit 2
}

ARGS=$(getopt -a -n test_getopt.sh -o f:Y:ch --long field:,display-filter:,count,help -- "$@")
VALID_ARGS=$?
if [ "$VALID_ARGS" != "0" ]; then
  help  
fi

eval set -- "$ARGS"
while :
do
  case "$1" in
    -f | --field)            FIELD="$2"   ; shift 2  ;;
    -Y | --display-filter)   DF="$2"      ; shift 2  ;;
    -c | --count)            COUNT=2      ; shift    ;;
    -h | --help)             help; exit 0 ; shift    ;;    
    --) shift; break ;;
  esac
done

echo "FIELD   : $FIELD"
echo "DF   : $DF "
echo "COUNT : $COUNT"
echo "其余参数: $@"

exit 0

下面对脚本进行简要解释:

  1. 在开头可以定义脚本的全局变量,green用于设置字体颜色。

  2. help()函数用于显示帮助信息,说明脚本的使用方法。

  3. ARGS=$(getopt -a -n test_getopt.sh -o f:Y:ch --long field:,display-filter:,count,help -- "$@")

    • 短参数一般在前面加单破折号(-),长参数使用双破折号(--),-a选项可以使长参数支持单破折号(-)

    • 如果参数必须赋值,在后面加冒号(:),

    • -n test_getopt.sh:指定程序名为test_getopt.sh,如果不设置,默认使用getopt

    • -o | --options:短选项

    • -l | --longoptions:长选项

  4. getopt接收所有输入后会返回一个状态码,0表示成功,其他值表示失败,状态码会传递给变量$?,对变量$?做一个判断,如果不为0则打印帮助信息。

  5. eval set -- "$ARGS"

    • eval 命令把字符串当做命令来执行,这里用于处理参数中的转义字符。

    • set 命令将命令行参数替换成getopt格式化后的命令行参数,也就是将getopt格式化的参数分配至位置参数($1,$2,...)

  6. 接下来就是对参数($1,$2,...)进行遍历处理

    • 通过shift来移动获取参数,用它来实现移动一个或者多个位置(也就是弹栈)

    • 每次循环,检查$1参数,对于必须赋值的参数,需要移动两位,因为它后面跟了一个参数值,需要移动两位才能到下一个参数。取值为$2,因为第一个参数为选项名称,第二个参数才是参数值。

    • 移位到--后,表示所有参数解析完成,退出循环。

运行:

$ sh test_getopt.sh --help
 Usage: sh test_getopt.sh [OPTION]
 Options:
 [ -f | --field FIELD]          -- 字段
 [ -Y | --display-filter DF]    -- 条件
 [ -c | --count COUNT ]         -- 计数
 [ -h | --help ]                -- 帮助信息
$ 
$ sh test_getopt.sh -c -f test -Y hello test2
FIELD   : test
DF   : hello
COUNT : 2
其余参数: test2

Python正则表达式

正则表达式(Regular expression)是组成搜索模式的一组字符序列,是记录文本规则的代码,用来检查文本中是否包含指定模式的字符串,通过定义一个规则来匹配字符串。正则表达式广泛应用于在字符串查找和处理中,大多文本编辑器基本都支持正则表达式查找。本文将简要介绍正则表达式语法,然后介绍Python语言中正则表达式使用方法。

正则表达式

Unix之父Ken Tompson将正则表达式引入Unix,后面发展成了grep(Global Regular Expression Print)命令,由于grep不支持+|? ,且分组比较麻烦,AT&T的Alfred Aho开发了egrep命令。随着Unix的版本不断演化,Unix中的程序(比如Linux三剑客中的awk、sed)所支持的正则表达式有差异,比较混乱。在1986年制定了POSIX(Portable Operating System Interface)标准,其中统一了正则表达式的语法。

POSIX标准把正则表达式分为两种:BRE(Basic Regular Expressions)和ERE(Extended Regular Expressions )。BRE就是unix系统使用的grep命令,ERE对应egrep命令,是BRE的扩展。而linux系统使用的是GNU标准,linux发行版集成了GNU(Gnu’s Not Unix)套件,GNU在实现了POXIS标准的同时,做了一定的扩展。也包括GNU Basic Regular Expressions 和GNU Extends Regular Expressions。

正则表达式除了POSIX标准之外还有一个Perl分支,Perl与sed和awk兼容,后来演化成为PCRE(Perl Compatible Regular Expressions),是一个用C语言编写的正则表达式函数库,功能很强大,性能比POSIX正则表达式好。PCRE被引入了其他语言中,比如PHP, Tcl, Python, Ruby, C++, Java, R语言等等。

普通正则

代码 说明
. 匹配除换行符以外的任意字符
\w 匹配字母或数字或下划线或汉字
\s 匹配任意的空白符
\d 匹配数字
\b 匹配单词的开始或结束
^ 匹配字符串的开始
$ 匹配字符串的结束
* 重复零次或更多次

扩展正则

扩展正则:grep加 -E 参数

  • grep -E ' 404 | 500' nginx.log

代码/语法 说明
+ 重复一次或更多次
重复零次或一次
{n} 重复n次
{n,} 重复n次或更多次
{n,m} 重复n到m次
| 表示或

零宽断言

语法 说明
(?=exp) 匹配exp前面的位置
(?<=exp) 匹配exp后面的位置
(?!exp) 匹配后面不是exp的位置
(?<!exp) 匹配前面不是exp的位置

正则表达式实例

正则表达式在线测试工具:

  1. https://regex101.com/

  2. http://c.runoob.com/front-end/854

  3. https://tool.oschina.net/regex

测试文本test.txt

$ cat test.txt
abc
bac
123456
bc
test123
12345678901234
023-12345678
123
GET 1
GET123
GET
test123test
1. 匹配以字母a开头的单词
$ grep '\ba\w*\b' test.txt
abc
2. 匹配刚好6个字符的单词
$ grep -E '\b\w{6}\b' test.txt
123456
GET123
3. 匹配1个或更多连续的数字
$ grep -Po '\d+' test.txt
123456
123
12345678901234
023
12345678
123
1
123
123
4. 5位到12位QQ号
$ grep -P '\d{5,12}' test.txt
123456
12345678901234
023-12345678

$ grep -P '^\d{5,12}$' test.txt
123456
5. 匹配电话号码
$ grep -P '0\d{2}-\d{8}' test.txt
023-12345678
6. 只匹配3位数字
$ grep -P '^\d{3}$' test.txt
123
7. 查找单词‘GET’
$ grep '\bGET\b' test.txt
GET 1
GET
$ grep '^GET$' test.txt
GET
8. 匹配两个字符之间的内容
$ grep -Eo "test(.+?)test" test.txt
test123test
$ grep -Po "(?<=test).*?(?=test)" test.txt
123
9. .*.+的使用方法
$ text1="fn()"
$ text2="fn(6)"
$ echo $text1 | grep "fn\(.*\)"
fn()
$ echo $text2 | grep "fn\(.*\)"
fn(6)
$ echo $text1 | grep -E "fn\(.+\)"

$ echo $text2 | grep -E "fn\(.+\)"
fn(6)

Python正则表达式

Python有一个内置正则表达式模块 re ,可以使用它来进行字符串操作:

import re

re模块提供了以下4种方法:

  • findall:返回所有匹配项

  • search:如果匹配到目标字符,返回一个匹配对象,用于判断是否存在目标字符串

  • split:分割

  • sub:替换

匹配数字、字母

text = '1&\nbsp;hour(s) 2&\nbsp;min 25&\nbsp;s'
re.findall(r'\d+',text) # 匹配时间(数字)
re.findall(r'\d+|(?<=;)\w+',text) # 匹配时间和单位

output:

['1', '2', '25']
['1', 'hour', '2', 'min', '25', 's']
re.findall(r'\d{2}+',text) # 匹配2位数字

查找替换两个字符串之间内容

替换字符target_text

xpath_path = '//*[contains(text(),"target_text")]/../td[5]/span' # xpath路径
repl = "需要替换成的字符串"
re.sub(r"(?<=\").*?(?=\")", repl, xpath_path) # 替换要查找的文本

output:

'//*[contains(text(),"需要替换成的字符串")]/../td[5]/span'

添加千位分割符

number = '12345678' 
re.sub(r"\B(?=(?:\d{3})+(?!\d))", ",",number) # 替换要查找的文本
re.sub(r"\B(?:(?:\d{3})+(?!\d))", ",",number) 

output:

'12,345,678'
'12,'

(?:\d{3})+(?!\d):

  • 查找3n(数字) + 非数字 组合

(?:exp) :

  • 匹配exp,不捕获匹配的文本(非获取匹配),也不给此分组分配组号,当执行了第一次匹配时,匹配到了行尾,直接将345678替换成了“,”。

参考文档

  1. 正则表达式30分钟入门教程:https://deerchao.cn/tutorials/regex/regex.htm

  2. github项目learn-regex:https://github.com/ziishaned/learn-regex

  3. https://www.w3schools.com/python/python_regex.asp

Linux cron定时介绍

定时任务的使用场景非常广泛,比如定时发送邮件,定时清理日志等等,在持续集成中,可以定时的触发测试任务,比如希望在每天晚上下班时间执行自动化用例。本文通过介绍Linux cron定时来了解​cron定时相关概念。

Linux Crontab 定时任务

cron来源于希腊语chronos,意思是时间。在类Unix的操作系统中,可以使用cron 服务器来实现定时执行任务。crontab文件存放cron指令,执行周期命令的守护进程crond负责激活这些任务,定期检查是否有任务执行。

crond 服务

crond 服务是用来执行周期任务或等待处理某些事件的一个守护进程,crontab 命令需要 crond 服务支持。centos7中一般是默认安装的,可以使用 rpm 命令查看是否安装:

$ rpm -qa | grep crontab
crontabs-1.11-6.20121102git.el7.noarch

查看crond 服务状态:

# centos7
systemctl status crond.service 

# centos6
service crond status

启动crond 服务:

# centos7
systemctl start  crond.service

# centos6
service crond start

停止crond 服务:

# centos7
systemctl stop  crond.service

# centos6
service crond stop

重启crond 服务:

# centos7
systemctl restart  crond.service

# centos6
service crond restart

重载crond 服务:

# centos7
systemctl reload  crond.service

# centos6
service crond reload

crontab相关文件

cron 服务主要包括以下文件目录:

  • /var/spool/cron:用户定义的crontab文件存放目录

  • /etc/cron.d:存放要执行的crontab文件或脚本

  • /etc/crontab:系统任务调度的配置文件

  • /etc/anacrontab:anacron配置文件

  • /etc/cron.deny:列出不允许使用crontab命令的用户

  • /etc/cron.daily:每天执行一次的脚本

  • /etc/cron.hourly:每小时执行一次的脚本

  • /etc/cron.monthly:每月执行一次的脚本

  • /etc/cron.weekly:每星期执行一次的脚本

/etc/crontab文件负责管理和维护任务:

$ cat /etc/crontab
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root

# For details see man 4 crontabs

# Example of job definition:
# .---------------- minute (0 - 59)
# |  .------------- hour (0 - 23)
# |  |  .---------- day of month (1 - 31)
# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# |  |  |  |  |
# *  *  *  *  * user-name  command to be executed

其中:

  • SHELL变量指定系统使用的shell版本

  • PATH指定系统执行命令的路径

  • MAILTO指定邮件发送的用户,如果为root,邮件会发送到/var/spool/mail/root文件中

cron表达式

用户定义的crontab文件保存在 /var/spool/cron 目录中,每个crontab任务以创建者的名字命名。crontab文件中每一行都代表一项任务,每条命令包括6个字段,前5个代表时间,第6个字段是要执行的命令。

五颗星:* * * * *

  • 第1颗星:分钟 minute,取值 0~59;

  • 第2颗星:小时 hour,取值 0~23;

  • 第3颗星:天 day,取值 1~31;

  • 第4颗星:月 month,取值 1~12;

  • 第5颗星:星期 week,取值 0~7,0 和 7 都表示星期天。

可以使用4种操作符:

  • * :当前代表的所有取值范围内的数字

  • /:需要间隔的数字

  • -:某个区间,比如1-3表示1, 2, 3

  • ,:分散的数字,可以不连续,比如1, 3, 5

下面举几个例子:

# 每5分钟构建一次
H/5 * * * *

# 每2小时构建一次
H H/2 * * *

# 每天8点到22点,每2小时构建一次
H 8-22/2 * * *

# 每天8点,22点各构建一次
H 8,22 * * *

crontab命令

crontab 命令用来配置定时任务,语法如下:

crontab [options] file
crontab [options]

常用options:

  • -u <user> :定义用户

  • -e:编辑 crontab表

  • -l: 列出用户crontab表

  • -r:删除用户crontab表

  • -i:删除提示

  • -n <hostname> 设置用户crontab主机名

  • -c:获取运行用户crontab的主机名

  • -s:selinux 上下文

  • -x <mask> :开启调试

crontab定时示例

先写一个用于采集CPU性能信息的脚本(cpu_Perf.sh):

#!/bin/bash
mpstat -P ALL 1 2 >> /var/cron/perf.log

下面来添加一个定时任务:

执行 命令crontab -e ,输入下面的cron表达式,每分钟执行一次CPU性能采集脚本:

* * * * * /var/cron/cpu_Perf.sh

保存。命令保存到了 /var/spool/cron/ 目录下的root文件中(当前用户为root):

$ cat /var/spool/cron/root 
* * * * * /var/cron/cpu_Perf.sh
$ crontab -l
* * * * * /var/cron/cpu_Perf.sh

保存成功后,每一分钟就会执行一次脚本。

Linux anacron 定时任务

如果服务器关机或者无法运行任务,定时任务就不会执行,服务器恢复后,定时任务不会执行没有执行的定时任务。这种场景下可以使用anacron命令,它与crond功能相同,增加了执行被跳过任务的功能。一旦服务器启动,anacron就会检查配置的定时任务是否错过了上一次执行,如果有,将立即运行这个任务,且只运行一次(不管错过了多少个周期)。

也就是说, anacron 是用来保证由于系统原因导致错过的定时任务可以在系统正常后执行的服务。

anacron命令

可以使用 anacron 命令来管理 anacron 服务,语法格式如下:

anacron [options] [job] ...
anacron -T [-t anacrontab-file]

options选项:

  • -s:串行调用任务

  • -f:强制执行任务,忽略设置的周期

  • -n:没有delay执行任务,隐含调用了-s参数

  • -d:把信息输出到标准输出设备和系统日志中

  • -q:禁止向标准输出发送消息,只能和-d选项配合使用。

  • -u:更新时间戳但不执行任务

  • -V:打印版本信息

  • -h:打印帮助信息

  • -t <file> :使用指定的配置文件,忽略默认的/etc/anacrontab文件。

  • -T:Anacrontab测试

  • -S <dir>:指定存放timestamp文件的路径

job/etc/anacrontab 文件中定义的工作名 job-identifier

anacron执行过程

下面来介绍一下anacron的执行过程:

1、根据脚本需要执行的频率,将脚本安装到/etc/cron.[hourly|daily|weekly|monthly] 目录中:

/etc/cron.hourly
/etc/cron.daily
/etc/cron.monthly
/etc/cron.weekly

2、crond 服务会执行/etc/cron.d/0hourly 中指定的cron 任务,

$ cat /etc/cron.d/0hourly
# Run the hourly jobs
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
01 * * * * root run-parts /etc/cron.hourly

每小时运行一次 run-parts 程序,而 run-parts 程序执行 /etc/cron.hourly 中的所有的shell脚本。

/etc/cron.hourly 目录中包含 0anacron 脚本:

$ ls /etc/cron.hourly
0anacron  mcelog.cron

3、 0anacron 脚本通过 /etc/anacrontab 配置文件来运行anacron程序。

$ cat /etc/anacrontab
# /etc/anacrontab: configuration file for anacron

# See anacron(8) and anacrontab(5) for details.

SHELL=/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
# the maximal random delay added to the base delay of the jobs
RANDOM_DELAY=45
# the jobs will be started during the following hours only
START_HOURS_RANGE=3-22

#period in days   delay in minutes   job-identifier   command
1       5       cron.daily              nice run-parts /etc/cron.daily
7       25      cron.weekly             nice run-parts /etc/cron.weekly
@monthly 45     cron.monthly            nice run-parts /etc/cron.monthly
  • RANDOM_DELAY=45 :表示最大随机延迟时间为45分钟。

  • START_HOURS_RANGE=3-22 : 执行的时间范围为03:00—22:00

/etc/anacrontab 配置文件执行cron.[daily|weekly|monthly] 目录中的可执行文件。

anacron的监测周期为每天、每周和每月,每天执行一次/etc/cron.daily 目录中的程序,每周执行一次 /etc/cron.weekly 中的程序,每月执行一次 /etc/cron.monthly 中的程序。

anacron不能在指定某个时间运行某个程序,它的设计目的是在特定的时间间隔运行某个程序,例如每天,每周日或者每月第一天的03:00运行某个程序。如果因为某种原因(关机或者服务器异常)没有执行,anacron会在服务器正常后运行一次错过的执行。

那么,anacron 是如何判断这些定时任务错过了执行呢?

其实是通过读取上次执行 anacron 的时间记录文件,通过两个时间的差值判断是否超过指定间隔时间(1天、1周和1月)。

/var/spool/anacron/ 目录中的 cron.[daily|weekly|monthly] 文件记录了上一次执行 cron任务 的时间:

$ ls /var/spool/anacron/
cron.daily  cron.monthly  cron.weekly
$ cat /var/spool/anacron/cron.daily
20211123

cron表达式应用

前面介绍了在Linux中通常用 crond 服务来实现任务定时执行,在很多场景都会用到定时任务,比如定时提醒,定时发送邮件等。比如python中可以使用APScheduler库执行定时任务,Java可以使用Quartz框架实现,Go语言使用 github.com/robfig/cron 包。

在持续测试平台Jenkins中经常会配置定时执行任务,下面简单介绍一下Jenkins定时构建配置方法。

Jenkins定时构建

在配置Jenkins任务时,构建定时任务主要有两种形式:

  • 一种是配置周期触发(Build periodically),在特定时间进行自动触发测试流程。

  • 第二种是Poll SCM:定时检查源码变更,如果有更新就checkout新的代码下来,然后执行构建动作。

在【Build Triggers】中选择 Build periodically 或者 Poll SCM

_images/build-triggers-periodically.png

在Schedule中输入cron表达式来配置定时任务。

Jenkins也可以创建多个定时,比如在每个工作日的9:30和每周五22:30构建:

30 9 * * 1-5
30 22 * * 5

Docker简介及安装

容器技术(Linux Container,LXC)是一种轻量级的虚拟化技术,容器镜像运行在一个隔离环境中,像集装箱一样,把应用封装起来,应用之间互不干扰,实现进程的隔离。Docker 是常用的一种容器技术,本文将简要介绍Docker及Docker安装方法。

Docker简介

Docker是什么

Docker基于Go语言开发,在2013年正式发布,是一个是用于构建、部署和管理容器化应用程序的开源平台,Docker 允许开发人员将应用程序打包到容器中,容器将应用程序源代码、操作系统库以及所需的依赖结合在一起,可以发布到任何流行的系统中。Docker具有以下优点:

  • 使开发人员能够使用简单命令自动化构建、部署、运行、更新容器,缩短开发及运行代码之间的周期,快速交付应用。

  • 应用隔离:不同软件运行环境兼容依赖问题,每个容器都可以看作是一个不同的微服务,容器之间互不影响。

  • 轻量级,比创建虚拟机快得多

  • 运行环境可移植,容器镜像将应用运行环境,包括代码、依赖、资源文件等打包。

_images/docker.png

Docker与虚拟机的区别

虚拟机(Virtual machine, VM)是对计算机系统的仿真,操作系统(OS)及其应用程序共享单个主机服务器的硬件资源,硬件是虚拟化的,每个虚拟机都有自己的底层操作系统。管理程序(hypervisor)位于硬件和虚拟机之间,负责创建和运行 VM 的软件、固件或硬件。

前面讲过,Docker也是一种虚拟化技术,它只虚拟化操作系统,而不像虚拟机那样虚拟化操作系统和硬件资源。主要区别如下:

  • 容器与容器之间只是进程的隔离,通过名称空间隔离,而虚拟机是完全的资源隔离,可能更安全。

  • 虚拟机的启动可能需要几分钟,Docker启动只需几秒钟甚至更短。

  • 容器共享宿主操作系统的内核,而虚拟机使用完全独立的内核,需虚拟化内核。

  • 虚拟机是操作系统和硬件的虚拟化,Docker是操作系统的虚拟化

_images/docker-vs-vm1.png

Docker Engine

Docker Engine 是一个客户机/服务器 (C/S架构) 应用,主要包括三个部分:

  • server:守护进程(dockerd 命令),Docker Daemon

  • REST API:客户端与守护进程间的通信接口

  • CLI:command line interface (CLI) ,命令行接口客户端(docker 命令)

_images/docker-engine.png

CLI 使用 REST API 与 Docker Daemon 进行通信,实现对Docker Daemon的控制和交互。也可以使用 UNIX 套接字、网络接口进行通信。守护进程构建、运行和管理 Docker 对象(镜像、容器、网络和volumes)。Docker 客户机和守护进程可以在同一个系统上运行,也可以将 Docker 客户机连接到远程 Docker 守护进程。

_images/docker-architecture1.png

https://docs.docker.com/get-started/overview/
Docker daemon

Docker 守护进程(dockerd)是后台服务进程,是生存期较长的进程,负责监听 Docker API 请求,管理 Docker 对象。守护进程还可以与其他守护进程通信来管理 Docker 服务。

Docker client

Docker 客户端(docker)是 Docker 用户与 Docker 交互的主要方式,客户端将命令发送给守护进程,然后守护进程执行这些命令,Docker 客户端可以与多个守护进程进行通信。

Docker Images

Docker镜像是一个只读模板,其中包含创建 Docker 容器的说明。通常,一个镜像都可能依赖一个或多个下层的镜像组成的另一个镜像。Docker镜像可以从Docker仓库中下载,也可以自己创建(Dockerfile)。

Docker Registry

Docker仓库是集中存放Docker镜像的地方,默认公共仓库为 Docker Hub,也可以自己配置私人仓库。当使用 docker pulldocker run 命令时,将从配置的仓库中提取所需的镜像。使用 docker push 命令时,镜像将被推送到配置的仓库中。

Docker Containers

Docker容器是镜像运行后的进程,是镜像的可运行实例,默认情况下,容器之间是隔离的。

Docker安装

Docker安装可参考官方文档:https://docs.docker.com/engine/install/

Windows 10

下载地址 : https://hub.docker.com/editions/community/docker-ce-desktop-windows

Linux

安装方法有两种,一种是设置docker源进行安装(推荐方法),另一种是是下载安装包(CentOS和Ubuntu对应RPM、DEB包)进行手动安装,一般在安装主机没有网络的情况下使用这种方法。(RPM、DEB包介绍及安装方法可参考Linux系统介绍

下面介绍一下CentOS下的docker安装方法(也可参考官方文档:https://docs.docker.com/engine/install/centos/),Ubuntu系统下docker的安装参考官方文档:https://docs.docker.com/engine/install/ubuntu/

要求CentOS 7 或者 CentOS 8

1. 卸载旧版本
$ sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
2. 安装依赖、添加源
# 安装yum-utils包
$ sudo yum install -y yum-utils device-mapper-persistent-data lvm2
# 设置yum源
$ sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# a
$ sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
3. 安装Docker Engine

安装最新版本的Docker Engine 和 containerd

$ sudo yum install docker-ce docker-ce-cli containerd.io

或者安装指定版本:

# 列出可用版本
$ yum list docker-ce --showduplicates | sort -r
docker-ce.x86_64            3:20.10.2-3.el7                    docker-ce-stable 
docker-ce.x86_64            3:20.10.2-3.el7                    @docker-ce-stable
docker-ce.x86_64            3:20.10.1-3.el7                    docker-ce-stable 
docker-ce.x86_64            3:20.10.0-3.el7                    docker-ce-stable 
# 安装指定版本
$ sudo yum install docker-ce-20.10.2 docker-ce-cli-20.10.2 containerd.io
4. 启动Docker
# 启动
$ sudo systemctl start docker
# 开机启动
$ sudo systemctl enable docker
5. 检验Docker Engine是否安装成功
# 运行hello-world镜像
$ sudo docker run hello-world
# 或者 查看docker版本
$ docker version

配置阿里云镜像加速器

默认是从Docker Hub下载镜像,为了更快的下载docker镜像,可以配置国内的镜像服务器,下面介绍阿里云镜像配置方法。

阿里云控制台地址:https://homenew.console.aliyun.com/

  1. 进入容器镜像服务 _images/aliyun-mirrors.png

  2. 设置登陆密码 首次使用需要设置密码: _images/aliyun-mirrors-pwd.png

  3. 设置镜像加速点击进入镜像加速器:https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors _images/aliyun-mirrors2.png 选择对应的操作系统,按照操作步骤进行操作。

常见问题

报错信息:

Failed to Setup IP tables: Unable to enable SKIP DNAT rule:  (iptables failed: iptables --wait -t nat -I DOCKER -i br-48bc3090b33e -j RETURN: iptables: No chain/target/match by that name.

原因是关闭防火墙之后docker需要重启:

service docker restart

参考:

Docker常用命令

本文介绍常用Docker命令,以搭建Web服务器Nginx为例介绍docker相关命令。

基本命令

查看Docker版本信息:

$ docker version

查看Docker系统信息:

$ docker info

从Docker Hub查找镜像

$ docker search 镜像名
# 搜索nginx镜像
$ docker search nginx

拉取镜像

$ docker pull nginx
[root@server server]# docker pull nginx
Using default tag: latest
latest: Pulling from library/nginx
a076a628af6f: Pull complete 
0732ab25fa22: Pull complete 
d7f36f6fe38f: Pull complete 
f72584a26f32: Pull complete 
7125e4df9063: Pull complete 
Digest: sha256:10b8cc432d56da8b61b070f4c7d2543a9ed17c2b23010b43af434fd40e2ca4aa
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest
[root@server server]# 

下载指定版本的镜像

$ docker pull nginx:1.19.6

镜像的可用版本可在docker hub中查看:https://hub.docker.com/_images/docker-nginx-tag.png

镜像管理

查看所有已下载镜像

$ docker images
[root@server server]#  docker images
REPOSITORY                   TAG               IMAGE ID       CREATED         SIZE
nginx                        latest            f6d0b4767a6c   3 weeks ago     133MB
app                          v1                db282454f6b3   7 months ago    83.1MB
<none>                       <none>            1acc89e1a291   7 months ago    152MB
bitnami/mariadb              latest            08498502c6b7   7 months ago    319MB
bitnami/testlink             latest            41feee91d195   7 months ago    826MB
prom/prometheus              latest            39d1866a438a   7 months ago    142MB
mysql                        5.7               9cfcce23593a   7 months ago    448MB
python                       3.7-alpine        6a5ca85ed89b   8 months ago    72.5MB
jenkins/jenkins              lts               5d1103b93f92   8 months ago    656MB
[root@server server]#  

删除镜像

$ docker rmi nginx:latest
# 或者使用IMAGE ID
$ docker rmi f6d0b4767a6c
# 强制删除镜像
$ docker rmi -f f6d0b4767a6c

标记本地镜像

$ docker tag nginx:latest nginx:test
# 修改镜像名称
$ docker tag nginx:latest nginx_test
[root@server server]# docker images
REPOSITORY                   TAG               IMAGE ID       CREATED         SIZE
nginx                        latest            f6d0b4767a6c   3 weeks ago     133MB
nginx                        test              f6d0b4767a6c   3 weeks ago     133MB
[root@server server]# docker tag nginx:latest nginx_test
REPOSITORY                   TAG               IMAGE ID       CREATED         SIZE
nginx                        latest            f6d0b4767a6c   3 weeks ago     133MB
nginx                        test              f6d0b4767a6c   3 weeks ago     133MB
nginx_test                   latest            f6d0b4767a6c   3 weeks ago     133MB
[root@server server]# docker rmi nginx:test
Untagged: nginx:test
[root@server server]# docker rmi nginx_test:latest
Untagged: nginx_test:latest

将指定镜像打包成 tar 归档文件

$ docker save nginx > nginx_test.tar
$ docker save nginx -o nginx_test.tar

导入打包的镜像

$ docker load < nginx_test.tar

查看镜像创建历史

$ docker history nginx

容器管理

运行容器

# 开启nginx服务
$ docker run -p 80:80 -d --name=nginx nginx:latest 

-d: 后台运行容器,并返回容器ID --name: 为容器指定一个名称 -p: 指定端口映射:主机(宿主)端口:容器端口 **-v:**挂载目录,将主机的目录映射到容器目录

[root@server server]# docker run -p 80:80 -d --name=nginx nginx:latest
651ce76dd80fa58e3cdf2abeb9c08662bfcf68176738bb3881d0bcb851aa1a11
[root@server server]# 

浏览器输入服务器IP地址 _images/docker-nginx-welcome.png

挂载目录

# 将主机目录/home/server/nginx/html映射到容器目录/usr/share/nginx/html
$ docker run -p 80:80 -d --name=nginx -v /home/server/nginx/html:/usr/share/nginx/html nginx:latest 

在主机目录/home/server/nginx/html下新建一个index.html文件,输入内容:<h1>Hello World !</h1>

[root@server server]# cd /home/haiyong/nginx/html
[root@server html]# vim index.html
[root@server html]# cat index.html 
<h1>Hello World !</h1>
[root@server html]# 

浏览器刷新 _images/docker-nginx-index.png

查看运行的容器:

$ docker ps
$ docker ps -a
[root@server server]# docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED         STATUS         PORTS                NAMES
651ce76dd80f   nginx:latest   "/docker-entrypoint.…"   6 minutes ago   Up 6 minutes   0.0.0.0:80->80/tcp   nginx
[root@server server]# docker ps -a
CONTAINER ID   IMAGE                 COMMAND                  CREATED         STATUS                    PORTS                                              NAMES
651ce76dd80f   nginx:latest          "/docker-entrypoint.…"   8 minutes ago   Up 7 minutes              0.0.0.0:80->80/tcp                                 nginx
3bab7ac2a2af   jenkins/jenkins:lts   "/sbin/tini -- /usr/…"   6 months ago    Exited (255) 8 days ago   0.0.0.0:8080->8080/tcp, 0.0.0.0:50000->50000/tcp   jenkins
2c5ae10a7543   mysql:5.7             "docker-entrypoint.s…"   6 months ago    Exited (255) 8 days ago   0.0.0.0:3306->3306/tcp, 33060/tcp                  mysql-test
[root@server server]# 

查看容器中运行的进程

$ docker top nginx
[root@server server]# docker top nginx
UID                 PID                 PPID                C                   STIME               TTY                 TIME                CMD
root                118225              118205              0                   22:58               ?                   00:00:00            nginx: master process nginx -g daemon off;
101                 118284              118225              0                   22:58               ?                   00:00:00            nginx: worker process

实时监控容器资源消耗

$ docker stats nginx
[root@server server]# docker stats nginx
CONTAINER ID   NAME      CPU %     MEM USAGE / LIMIT     MEM %     NET I/O           BLOCK I/O         PIDS
651ce76dd80f   nginx     0.00%     1.492MiB / 1.777GiB   0.08%     3.97kB / 3.66kB   73.7kB / 24.6kB   2
CONTAINER ID   NAME      CPU %     MEM USAGE / LIMIT     MEM %     NET I/O           BLOCK I/O         PIDS
651ce76dd80f   nginx     0.00%     1.492MiB / 1.777GiB   0.08%     3.97kB / 3.66kB   73.7kB / 24.6kB   2
CONTAINER ID   NAME      CPU %     MEM USAGE / LIMIT     MEM %     NET I/O           BLOCK I/O         PIDS
651ce76dd80f   nginx     0.00%     1.492MiB / 1.777GiB   0.08%     3.97kB / 3.66kB   73.7kB / 24.6kB   2
CONTAINER ID   NAME      CPU %     MEM USAGE / LIMIT     MEM %     NET I/O           BLOCK I/O         PIDS

查看容器日志

$ docker logs -f nginx

获取容器/镜像的元信息

$ docker inspect nginx
$ docker inspect -f '{{.Id}}' nginx

-f : 格式化字符串,输出格式使用Go语言模板。

[root@server server]# docker inspect nginx
[
    {
        "Id": "651ce76dd80fa58e3cdf2abeb9c08662bfcf68176738bb3881d0bcb851aa1a11",
        "Created": "2021-02-02T14:58:47.047835997Z",
        "Path": "/docker-entrypoint.sh",
        "Args": [
            "nginx",
            "-g",
            "daemon off;"
        ],
        "State": {
            "Status": "running",
            "Running": true,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 118225,
            "ExitCode": 0,
            "Error": "",
            "StartedAt": "2021-02-02T14:58:48.290043299Z",
            "FinishedAt": "0001-01-01T00:00:00Z"
        },
............................
[root@server server]# docker inspect -f '{{.Id}}' nginx
651ce76dd80fa58e3cdf2abeb9c08662bfcf68176738bb3881d0bcb851aa1a11

[root@server server]# docker inspect -f '{{.State.StartedAt}}' nginx
2021-02-02T14:58:48.290043299Z

docker inspect返回的容器信息中记录了容器的磁盘挂载目录,可以使用grep命令筛选出Mounts字段内容:

$ docker inspect nginx | grep Mounts -A 10
        "Mounts": [
            {
                "Type": "bind",
                "Source": "/home/server/nginx/html",
                "Destination": "/usr/share/nginx/html",
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            }
        ],
        "Config": {

查看容器内文件结构及更改

$ docker diff nginx
[root@server server]# docker diff webserver
C /etc
C /etc/nginx
C /etc/nginx/conf.d
C /etc/nginx/conf.d/default.conf
C /root
A /root/.bash_history
C /var
C /var/cache
C /var/cache/nginx
A /var/cache/nginx/client_temp
A /var/cache/nginx/fastcgi_temp
A /var/cache/nginx/proxy_temp
A /var/cache/nginx/scgi_temp
A /var/cache/nginx/uwsgi_temp
C /run
A /run/nginx.pid

**A:**添加了文件或目录 **B:**文件或目录被删除 **C:**文件或目录被修改

启动,停止容器

# 启动已经被停止的容器
$ docker start nginx

# 重启容器
$ docker restart nginx

# 暂停容器中所有的进程
$ docker pause nginx

# 恢复容器中所有的进程
$ docker unpause nginx

# 杀掉一个运行中的容器
$ docker kill nginx

# 停止一个运行中的容器
$ docker stop nginx

# 删除容器
$ docker rm nginx

# 强制删除容器
$ docker rm -f nginx
[root@server server]# docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED        STATUS        PORTS                NAMES
651ce76dd80f   nginx:latest   "/docker-entrypoint.…"   21 hours ago   Up 21 hours   0.0.0.0:80->80/tcp   nginx
[root@server server]# docker stop nginx
nginx
[root@server server]# docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
[root@server server]# docker start nginx
nginx
[root@server server]# docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED        STATUS        PORTS                NAMES
651ce76dd80f   nginx:latest   "/docker-entrypoint.…"   21 hours ago   Up 1 second   0.0.0.0:80->80/tcp   nginx
[root@server server]# docker rm nginx
Error response from daemon: You cannot remove a running container 651ce76dd80fa58e3cdf2abeb9c08662bfcf68176738bb3881d0bcb851aa1a11. Stop the container before attempting removal or force remove
[root@server server]# docker stop nginx
nginx
[root@server server]# docker rm nginx  
nginx
[root@server server]# docker start nginx
Error response from daemon: No such container: nginx
Error: failed to start containers: nginx
[root@server server]# docker run -p 80:80 -d --name=nginx nginx:latest 
e0abbac7464794b5f2fbd328b841aaa83ffeff6c2072324b584cbbee4c68c36f

容器交互

在容器中执行命令

$ docker exec -it nginx ls
# 开启一个交互模式的终端,exit退出
$ docker exec -it nginx bash
# 使用root账号进入容器
$ docker exec -it -u root nginx bash
[root@server server]# docker exec -it nginx ls     
bin   docker-entrypoint.d   home   media  proc  sbin  tmp
boot  docker-entrypoint.sh  lib    mnt    root  srv   usr
dev   etc                   lib64  opt    run   sys   var
[root@server server]# docker exec -it nginx echo "test"
test
[root@server server]# docker exec -it nginx bash
root@ad4c10c7cec2:/# ls
bin   dev                  docker-entrypoint.sh  home  lib64  mnt  proc  run   srv  tmp  var
boot  docker-entrypoint.d  etc                   lib   media  opt  root  sbin  sys  usr
root@ad4c10c7cec2:/# exit
exit
[root@haiyong haiyong]# 

复制文件

# 将容器文件拷贝到主机
$ docker cp nginx:/etc/hosts hosts

# 将主机文件拷贝到容器中
$ docker cp hosts nginx:/etc/hosts

Dockerfile语法指令及Docker镜像构建

在工作中,通常会根据项目需要制作镜像,Docker可以通过读取Dockerfile文件中的指令来自动构建镜像,Dockerfile文本文件包含镜像构建的命令,通过 docker build 执行 Dockerfile中的一系列指令来自动构建镜像。除了Dockerfile的方式外,也可以使用Docker commit来制作镜像,本文将介绍Dockerfile语法Docker镜像的构建方法。

常用Dockerfile指令

Dockerfile官方文档:https://docs.docker.com/engine/reference/builder/

Docker 顺序执行Dockerfile文件中的指令,指令不区分大小写,为了区分,建议都大写。Dockerfile以 FROM 指令开始,FROM指令指定了构建的父镜像(基础镜像),Dockerfile使用 # 注释行,下面列出其它常用指令:

  • COPY:从本地复制文件,复制文件或者目录到容器里指定路径

  • ADD:可以从网络或者本地复制,将主机构建环境(上下文)目录中的文件和目录、以及一个URL标记的文件拷贝到镜像中,tar类型文件会自动解压。当需要从远程复制文件时,最好使用 curl 或 wget 命令来代替 ADD 命令。

  • LABEL:为镜像生成元数据标签信息

  • WORKDIR:指定工作目录,为后续的RUN、CMD、 ENTRYPOINT、ADD指令配置工作目录。

  • USER:指定运行容器时的用户名或UID,后续命令执行也会使用指定用户。

  • RUN:Dockerfile RUN命令是执行命令的核心部分,在docker build时执行。它接受命令作为参数并用于创建镜像。每条RUN命令在当前基础镜像上执行,并且会提交一个新镜像层:RUN pip install flask

  • CMD:容器运行 docker run 时执行的默认命令。

  • ENV:容器启动的环境变量。

  • ARG:构建环境的环境变量。

  • ENTRYPOINT:指定容器的“入口”。

  • HEALTHCHECK:用于指定某个程序或者指令来监控 docker 容器服务的运行状态

Dockerfile构建容器

常用文件、命令:

  • .dockerignore:设置希望构建时需要忽略的文件,过滤指定文件

  • docker build -f Dockerfile文件名:指定Dockerfile文件

  • docker build -t 标签:添加标签

  • docker build --no-cache:不使用缓存,也就是每次构建时,不管有没有安装过都进行重新构建

  • docker build --build-arg:传递ARG指令变量

1. 创建Dockerfile文件

构建一个dockerfile文件,定制一个Nginx镜像,添加容器健康检查。 Dockerfile:

# 基于 nginx:latest 镜像构建
FROM nginx:latest

# 指定信息
LABEL maintainer="test_dockerfile"

# 设置环境变量
ENV NGINX_VERSION latest
ARG workpath=/data/html/

# 切换root用户
USER root

# 执行命令,安装cur软件,设置软链接把ngin服务的日志显示到终端
RUN apt-get -yq update && apt-get install -y curl && \
ln -sf /dev/stdout /var/log/nginx/access.log && \
ln -sf /dev/stderr /var/log/nginx/error.log

# 挂载卷
VOLUME ["/data"]

# 设置工作目录
WORKDIR $workpath

# 复制 index.html 文件到nginx的html目录下
COPY index.html /usr/share/nginx/html

# 映射80端口
EXPOSE 80

# 此处CMD作为 ENTRYPOINT的参数。
CMD ["nginx","-g","daemon off;"]
# CMD ["-g","daemon off;"]
# CMD nginx -g daemon off
# 设置容器启动的命令
ENTRYPOINT ["nginx","-g","daemon off;"]

STOPSIGNAL SIGRTMAX

# 检查容器健康,通过访问 Nginx服务80端口,来判断容器服务是否健康
HEALTHCHECK --interval=5s --timeout=3s \
  CMD curl -fs http://localhost/ || exit 1

index.html文件内容:

<h1>Hello World !</h1>

2. 构建镜像:docker build

在Dockerfile 文件目录下执行构建:

$ docker build -t nginx:testv1 -f Dockerfile .
  • nginx:testv1:镜像名称:镜像标签

  • Dockerfile:Dockerfile 文件名,默认文件名为Dockerfile

  • . 表示当前目录,代表本次执行的上下文路径

[root@server test_dockerfile]# pwd
/root/docker/test_dockerfile
[root@server test_dockerfile]# ls
Dockerfile  index.html
[root@server test_dockerfile]# docker build -t nginx_demo:v1 .
Sending build context to Docker daemon  4.096kB
Step 1/13 : FROM nginx:latest
 ---> f6d0b4767a6c
Step 2/13 : LABEL maintainer="test_dockerfile"
 ---> Running in 6c4b611a19e9
Removing intermediate container 6c4b611a19e9
 ---> 6a6f12ed39ad
Step 3/13 : ENV NGINX_VERSION latest
 ---> Running in e9cfc405af5a
Removing intermediate container e9cfc405af5a
 ---> 6608a514dc4a
Step 4/13 : ARG workpath=/data/html/
 ---> Running in 31ec17310301
Removing intermediate container 31ec17310301
 ---> 04b7f5b51c63
Step 5/13 : USER root
 ---> Running in 1d6aaf7f9d13
Removing intermediate container 1d6aaf7f9d13
 ---> 3568d2cf3a36
Step 6/13 : RUN apt-get install -y curl && ln -sf /dev/stdout /var/log/nginx/access.log && ln -sf /dev/stderr /var/log/nginx/error.log
 ---> Running in fcf7a55bbb4a
Reading package lists...
Building dependency tree...
Reading state information...
curl is already the newest version (7.64.0-4+deb10u1).
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
Removing intermediate container fcf7a55bbb4a
 ---> 20cb644a11c3
Step 7/13 : VOLUME ["/data"]
 ---> Running in ebaa3b7e6dbf
Removing intermediate container ebaa3b7e6dbf
 ---> 246093dbcc45
Step 8/13 : WORKDIR $workpath
 ---> Running in 494a62d4166b
Removing intermediate container 494a62d4166b
 ---> 2afb818a2a35
Step 9/13 : COPY index.html /usr/share/nginx/html
 ---> 1fee5e32c1fc
Step 10/13 : EXPOSE 80
 ---> Running in 2a80075b76f3
Removing intermediate container 2a80075b76f3
 ---> 3ef9846b592e
Step 11/13 : CMD ["nginx","-g","daemon off;"]
 ---> Running in db5ab895a85b
Removing intermediate container db5ab895a85b
 ---> 4e70e4e4ef95
Step 12/13 : STOPSIGNAL SIGRTMAX
 ---> Running in d7ceb8fdbd59
Removing intermediate container d7ceb8fdbd59
 ---> 68c8bb3b43f9
Step 13/13 : HEALTHCHECK --interval=5s --timeout=3s   CMD curl -fs http://localhost/ || exit 1
 ---> Running in 3cb2690c7c13
Removing intermediate container 3cb2690c7c13
 ---> e20cc62ae3e5
Successfully built e20cc62ae3e5
Successfully tagged nginx_demo:v1

查看镜像:

[root@server test_dockerfile]# docker images | grep nginx_demo
nginx_demo                   v1                adfe6b7f7297   5 minutes ago   133MB

3. 运行镜像:docker run

[root@server test_dockerfile]# docker run -d --name=nginx-test -p 8080:80 nginx_demo:v1
b0bd21087663   nginx_demo:v1   "/docker-entrypoint.…"   6 minutes ago    Up 6 minutes (unhealthy)   80/tcp                   admiring_swanson
[root@server test_dockerfile]# 

docker ps 查看容器

[root@server test_dockerfile]# docker ps | grep nginx_demo
710628d0ad55   nginx_demo:v1   "/docker-entrypoint.…"   2 minutes ago       Up 2 minutes (unhealthy)   0.0.0.0:8080->80/tcp     nginx-test
[root@server test_dockerfile]# 

浏览器输入:192.168.30.8:8080 _images/dockerfile-nginx-test.png

可以进入容器查看设置的环境变量

[root@server test_dockerfile]# docker exec -it 710628d0ad55 bash
root@b0bd21087663:/data/html# 
root@b0bd21087663:/data/html# 
root@b0bd21087663:/data/html# pwd
/data/html
root@b0bd21087663:/data/html# ls
index.html
root@b0bd21087663:/data/html# env
HOSTNAME=b0bd21087663
PWD=/data/html
PKG_RELEASE=1~buster
HOME=/root
NJS_VERSION=0.5.0
TERM=xterm
SHLVL=1
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
NGINX_VERSION=latest
_=/usr/bin/env
root@b0bd21087663:/data/html# id
uid=0(root) gid=0(root) groups=0(root)
root@b0bd21087663:/data/html# df -h
Filesystem               Size  Used Avail Use% Mounted on
overlay                   45G   22G   24G  48% /
tmpfs                     64M     0   64M   0% /dev
tmpfs                    910M     0  910M   0% /sys/fs/cgroup
shm                       64M     0   64M   0% /dev/shm
/dev/mapper/centos-root   45G   22G   24G  48% /data
tmpfs                    910M     0  910M   0% /proc/asound
tmpfs                    910M     0  910M   0% /proc/acpi
tmpfs                    910M     0  910M   0% /proc/scsi
tmpfs                    910M     0  910M   0% /sys/firmware
root@b0bd21087663:/data/html# 

Docker commit

Docker commit一般用做从一个运行状态的容器来创建一个新的镜像,对外不可解释,不知道容器有什么应用,不方便排查问题,可维护性差。Dockerfile的方式更容易排查问题。

Docker commit构建命令:

$ docker commit 容器名 新镜像名:tag

对于上面构建的镜像,如果对index.html文件内容修改后重新打包一个镜像,我们可以使用Docker commit来构建:

[root@server ~]# docker commit nginx-test nginx_demo:v2

启动:

[root@server ~]# docker run -d --name=nginx-test2 -p 8080:80 nginx_demo:v2

常用Windows cmd命令

本文列出一些常用的 windows cmd命令,使用windows + r键后输入命令或者打开cmd.exe命令提示符输入,其中cmd命令提示符可以通过使用windows + r键后输入cmd打开

杀掉进程

$ taskkill /im chromedriver.exe /f
# 或者
$ wmic process where name="chromedriver.exe" call terminate

切换盘符目录

切换到其它盘

# 方法1
C:\Users\10287>d:

D:\>

# 方法2
C:\Users\10287>cd /d d:

D:\>

设置windows系统时区

参考:https://winaero.com/blog/set-time-zone-windows-10/

tzutil /l  //查看所有可设置时区
tzutil /g //查看当前时区
tzutil /s "China Standard Time" //设置时区  
tzutil /s "China Standard Time_dstoff" //关闭夏令时

打开资源管理器

explorer

关机重启

shutdown /? 查看帮助信息 关机

shutdown -s -t 60 # 60s 后关机
rononce -p # 15s 后关机
shutdown -s -t 0 # 立即关机
shutdown -p # 立即关机

或者使用wmic命令:

wmic process call create shutdown.exe

重启

shutdown -r -t 60 # 60s 后重启
shutdown -r -t 0 # 立即重启

休眠

shutdown -h

在rononce -p、shutdown -s或者shutdown -r倒计时结束之前执行shutdown -a可以取消关机或者重启操作

按住 shift 并点重启可以使重启后进入 BIOS

windows远程管理

mstsc

无法远程复制文件问题:

  1. 结束进程rdpclip.exe

  2. 重新开启进程:win + r 输入rdpclip.exe

windows计算器

calc

打开记事本

notepad

打开系统属性窗口

sysdm.cpl

打开系统属性窗口后,点击【高级】,可以打开【环境变量】设置系统环境变量

打开控制面板

control

打开剪贴板

Win10:windows + v

打开屏幕键盘

osk

服务设置

services.msc

_images/services-msc.png

注册表编辑

regedt32

任务管理器

taskmgr

写字板

write

画图板

mspaint

防火墙

firewall.cpl

其它

重置 Windows 10 本地帐户密码:https://support.microsoft.com/zh-cn/help/4028457/windows-10-reset-your-local-account-password

Windows 网络管理命令

本文列出一些常用的 Windows 网络管理命令。

ping

ping: 测试网络连接情况

  • -n:要发送的回显请求数

  • -t:ping 主机直到中断

  • -i:生存时间ttl

  • -6:IPv6

$ ping 192.168.20.8 -n 3

Pinging 192.168.20.8 with 32 bytes of data:
Reply from 192.168.20.8: bytes=32 time<1ms TTL=64
Reply from 192.168.20.8: bytes=32 time<1ms TTL=64
Reply from 192.168.20.8: bytes=32 time<1ms TTL=64

Ping statistics for 192.168.20.8:
    Packets: Sent = 3, Received = 3, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 0ms, Maximum = 0ms, Average = 0ms

网络信息查询

netstat

netstat: 协议统计和当前 TCP/IP 网络连接

  • -t 列出所有tcp连接

  • -a:显示所有连接和侦听端口

  • -n:以数字形式显示地址和端口号

  • -o:显示进程 ID

  • -p proto:显示指定的协议的连接,TCP、UDP、TCPv6 或 UDPv6

  • -s:显示每个协议的统计。默认情况下,显示IP、IPv6、ICMP、ICMPv6、TCP、TCPv6、UDP 和 UDPv6的统计信息,可使用-p 选项指定协议。

  • -e:显示以太网统计。此选项可以与 -s 选项结合使用。

  • -r:显示路由信息

$ netstat -ano -p tcp
Active Connections

  Proto  Local Address          Foreign Address        State           PID
  TCP    0.0.0.0:21             0.0.0.0:0              LISTENING       4896
  TCP    0.0.0.0:135            0.0.0.0:0              LISTENING       1032
  TCP    0.0.0.0:445            0.0.0.0:0              LISTENING       4
  TCP    0.0.0.0:902            0.0.0.0:0              LISTENING       10388
  TCP    0.0.0.0:912            0.0.0.0:0              LISTENING       10388
  TCP    0.0.0.0:1080           0.0.0.0:0              LISTENING       11476
  TCP    0.0.0.0:2425           0.0.0.0:0              LISTENING       7728
  TCP    0.0.0.0:5040           0.0.0.0:0              LISTENING       7940
  TCP    0.0.0.0:5357           0.0.0.0:0              LISTENING       4

查询5037端口占用:

$ netstat -ano | findstr 5037 
TCP    0.0.0.0:5037           0.0.0.0:0              LISTENING       34212

找到对应进程(也可以在任务管理器中查看):

$ tasklist | findstr 34212
adb.exe                      34212 Console                    1     10,692 K

通过PID或者进程名杀死进程:

$ taskkill -pid 34212 -f -t # taskkill /pid 34212 /f /t
$ taskkill -f -im adb.exe # taskkill /f /im adb.exe

网卡信息

$ ipconfig
$ ipconfig /all
$ netsh interface ipv4 show config
$ netsh interface ipv6 show config
$ wmic nic list brief

路由配置

route add [Destination] mask [netmask] [gw] metric [测量值]

  • -p:添加永久路由

  • Destination: 指定该路由的网络目标。

  • mask:当添加一个网络路由时,需要使用网络掩码。

  • gw:路由数据包通过网关。注意,你指定的网关必须能够达到。

  • metric:设置路由跳数。

# ipv4
$ route -p add 23.23.23.0 mask 255.255.255.0 192.168.97.60
route delete 23.23.23.0
# ipv6
$ netsh interface ipv6 add/del route 2001::/64 "Local Area Connection 2" 2001::2

查看路由表

$ netstat -r
$ route print
$ route print -4
$ route print -6
$ netsh interface ipv4 show route
$ netsh interface ipv6 show route

禁用启用网卡

$ netsh interface set interface eth0 disabled # 禁用网卡
$ netsh interface set interface name="接口名称" admin=DISABLE

$ netsh interface set interface eth0 enabled #启用网卡
$ netsh interface set interface name="接口名称" admin=ENABLE

$ netsh interface ipv6 set interface name="接口名称"  disable/enable

$ netsh interface show interface #显示接口

通过python脚本自动化控制:

import os
os.popen('netsh interface set interface name="接口名称" admin=DISABLE')

释放、更新地址

# ipv4
$ ipconfig /release
$ ipconfig /renew
# ipv6
$ ipconfig /release6
$ ipconfig /renew6

添加、删除IP地址

# ipv4
$ netsh interface ip add address "本地连接" 192.168.1.100 255.255.255.0
$ netsh interface ip delete address "本地连接" 192.168.1.100
## 设置静态IP地址
$ netsh interface ip set address name="eth1" source=static address=192.168.5.125 mask=255.255.255.0

# ipv6
$ netsh interface ipv6 delete address 本地连接 2001::1
$ netsh interface ipv6 add/del address 本地连接 2001::1

常用Windows 快捷键

windows 快捷键

打开 cmd

  • 当前目录下打开cmd:Windows 文件资源管理器路径栏中输入 cmd

  • 当前目录下打开cmd:在文件夹中,按shift键,点击右键,选择在此处打开cmd

  • user目录下:Windows+r,然后输入cmd

另外,在文件上shift+右键会多出来一个 “复制为路径” 选项

cmd 命令窗口中输入start .会打开处于当前目录的资源管理器 cmd 命令窗口按下 F7 可以显示历史命令记录

搜索

win + s或直接 win键 打开开始菜单后输入名称快捷搜索打开应用和文件

记事本

打开,命令窗口输入:

notepad

记事本第一行写上.LOG:关闭时会在最后一行插入编辑时间

文件资源管理器

Windows + e:打开文件资源管理器 在路径栏输入shell:startup 或者启动 进入启动目录 路径栏输入shell:appsfolder 进入应用程序目录

选中文件ALT + 回车 或者 ALT + 双击文件:查看文件属性

应用程序窗口

关闭Windows自带的程序窗口

  • 点击右上角的叉关闭

  • 双击窗口左上角的图标关闭

  • ALT + f4,在桌面按下 ALT + f4会弹出关机菜单

  • ALT + 空格 + c

Windows + ↑↓←→:调整窗口布局

ALT + TAB :程序窗口切换

Windows + 1234等数字键:按任务栏上的顺序快捷切换窗口

Windows + g打开Xbox便捷工具,比如截屏、录屏

Windows + d:显示桌面或恢复桌面 Windows + m:最小化所有窗口 Windows + Shift + m:恢复最小化窗口

浏览器

清空浏览器缓存:Ctrl+Shift+Delete

VBSscript实现后台运行Windows bat脚本

VBScript 是Visual Basic 语言的轻量级版本,本文介绍使用VBS实现在后台运行bat脚本。

先编写一个简单的bat脚本(test_bat.bat):使用Python打开一个简单的 http 服务器

@echo off

echo start
cmd /k "python -m http.server 8100"
echo end
pause

下面来测试一下这个脚本,双击test_bat.bat,会打开如下窗口:

_images/python-http-server.png

浏览器访问 http://127.0.0.1:8100/

_images/python-http-server2.png

可以看到HTTP服务搭建成功。

也可以使用 netstat 命令查看8100端口对应服务是否启动:

$ netstat -nao | findstr 8100
  TCP    0.0.0.0:8100           0.0.0.0:0              LISTENING       17220
  TCP    127.0.0.1:1024         127.0.0.1:8100         TIME_WAIT       0
$ 
$ tasklist | findstr 17220
python.exe                   17220 Console                    1     18,800 K

如何实现在后台运行呢?可以使用VBScript来实现。

编写vbs文件test_bat.vbs:

Set WshShell = CreateObject("WScript.Shell") 
WshShell.Run chr(34) & "test_bat.bat" & Chr(34), 0

0 表示后台运行,如果设置为1,会显示cmd窗口。

双击test_bat.vbs运行,浏览器访问 http://127.0.0.1:8100/ 查看服务是否启动 或者使用如下命令:

$ netstat -nao | findstr 8100
  TCP    0.0.0.0:8100           0.0.0.0:0              LISTENING       1788

$ tasklist | findstr 1788
python.exe                    1788 Console                    1     18,680 K

可以看到HTTP server启动成功。

杀掉HTTP server:

$ taskkill -pid 1788 -f -t
SUCCESS: The process with PID 1788 (child process of PID 18576) has been terminated.

如果bat脚本需要传入参数怎么实现呢?可以使用WScript.Arguments对象获取参数,下面直接给出实现方式,将端口号作为参数传入:

test_bat2.bat:

@echo off

echo start
python -m http.server %1
echo end

pause

test_bat2.vbs:

dim args
Set args = WScript.Arguments
Set WshShell = CreateObject("WScript.Shell") 

WshShell.run "cmd /c " &args(0) &args(1),0

cmd命令窗口运行

$ test_bat2.vbs test_bat2.bat " 8100"

在实际使用过程中,通常不会手动双击运行脚本,比如在自动化测试中,需要自动启动一个tshark抓包程序, 我们只需要它在后台运行。下面举一个Python运行bat脚本的示例程序。

def start_bat(self, port):
    """启动 HTTP server
    :port: 服务端口号
    """
    self.stop_process(port)
    dir_path = os.path.dirname(os.path.realpath(__file__))  # 当前路径
    print(dir_path)

    os.system(f'{dir_path}/test_bat.vbs "{dir_path}/test_bat.bat" " {port}"')

    for l in range(3):
        sleep(3)
        if self.check_process(port):
            print("http server successfully")
            return True
    print("http server started failed")
    return False

完整代码:https://github.com/hiyongz/ShellNotes/blob/main/test_vbs.py

--THE END--

通过bat脚本配置系统环境变量

本文介绍使用bat脚本添加系统环境变量

添加PATH环境变量

添加PATH环境变量,如果已经存在则不添加。

介绍2种方法来循环搜索路径是否已经存在:

@echo off

echo ---------------------------------------
set pan=%~d0
set filePath=%~p0 
set filePath=%pan%%filePath%
echo current path: %filePath%

REM 添加PATH环境变量:如果已经存在则不添加
echo ---------------------------------------
SET add_path=

SET toAdd=D:\software\Nmap
SET MYPATHCOPY=%PATH%
call :search1
echo %add_path%

SET toAdd=C:\Program Files\Go\bin
SET MYPATHCOPY=%PATH%
call :search2
echo %add_path%

echo add the path: %add_path%
call set xx=%Path%;%add_path%
wmic ENVIRONMENT where "name='Path' and username='<system>'" set VariableValue="%xx%"

pause
REM TIMEOUT /T 10

REM 方法1
:search1
for /f "tokens=1* delims=;" %%a in ("%MYPATHCOPY%") do (
	if "%toAdd%"=="%%a" (
		goto :isFinded
	)
	set MYPATHCOPY=%%b
    goto :search1
)
set add_path=%toAdd%;%add_path%
goto :EOF

REM 方法2
:search2
for /f "delims=; tokens=1,2*" %%p in ("%MYPATHCOPY%") do (
   REM @echo %%~p
   SET MYPATHCOPY=%%~q;%%~r
   if "%toAdd%"=="%%p" (
        REM echo %%p
	    goto :isFinded
    )
	goto :search2
)
set add_path=%toAdd%;%add_path%
goto :EOF

:isFinded
echo The path already exists: %toAdd%
goto :EOF

新建系统变量

1、使用 setx 来设置:

@echo off

set ENV_Path=%PYTHONPATH%
setx /M PYTHONPATH "D:\Anaconda3"

pause

2、使用 wmic 命令设置:

@echo off

::如果存在,先删除PYTHONPATH
wmic ENVIRONMENT where "name='PYTHONPATH'" delete

:: 创建系统变量PYTHONPATH
wmic ENVIRONMENT create name="PYTHONPATH",username="<system>",VariableValue="D:\Anaconda3"

一些windows批处理脚本

本文记录一些平时使用到的bat语法。

1. 获取当前目录

获取当前路径

@echo off

set DriveLetter=%~d0
echo %DriveLetter%

set filePath=%~p0
echo %filePath%
 
set filePath=%DriveLetter%%filePath%
echo current path: %filePath%
echo current path: %cd%

pause

执行结果:

D:
\ProgramWorkspace\ShellNotes\Windows\
current path: D:\ProgramWorkspace\ShellNotes\Windows\
current path: D:\ProgramWorkspace\ShellNotes\Windows

2. 获取目录中的文件和子目录

可以使用 dir 命令来获取某个目录下的文件或者子目录文件,使用 dir /? 命令查看帮助文档。

下面介绍几种使用方法:

# 显示当前目录下的文件、子目录以及子目录下的文件
dir /a /b /s

# 只显示当前目录下的文件
dir /b /a-d

# 从大到小排序
dir /b /a-d /o-s

# 显示后缀为bat的文件
dir /b /a-d /o-s *.bat

bat脚本打印当前目录下的bat文件:

@echo off

for /f "delims=\" %%a in ('dir /b /a-d /o-s "%cd%\*.bat"') do (
  echo %%a
)

pause

3. 读取配置文件

创建一个配置文件 config.ini :

host=192.168.0.1
port=8100

读取host和port的值:

@echo off

:: 读取配置
for /f "tokens=1,2 delims==" %%a in (config.ini) do (
	if %%a==host set host=%%b
	if %%a==port set port=%%b
) 

echo host: %host%
echo port: %port%

pause

运行结果:

host: 192.168.0.1
port: 8100

4. 清空文件内容

清空 test.log 文件中的内容:

cd.>test.log

linux shell清空文件内容方法参考Linux常用命令:文件操作命令

5. 打印换行

使用 echo. 打印换行:

@echo off

echo hello
echo.
echo world

pause 

6. 设置窗口显示颜色

语法:

COLOR [attr]

颜色属性 attr 可用于设置背景和前景的设置,可以设置的颜色:

  • 0 = 黑色

  • 1 = 蓝色

  • 2 = 绿色

  • 3 = 浅绿色

  • 4 = 红色

  • 5 = 紫色

  • 6 = 黄色

  • 7 = 白色

  • 8 = 灰色

  • 9 = 淡蓝色

  • A = 淡绿色

  • B = 淡浅绿色

  • C = 淡红色

  • D = 淡紫色

  • E = 淡黄色

  • F = 亮白色

例如设置窗口为白色背景,红色文字:

@echo off

color 74

echo Hello world !

pause

效果: _images/cmd-color.jpg

关注公众号【测试开发小记】及时接收最新技术文章!

_images/wechat.png