主页

C语言基础

2021-09-26
c语言

变量和初始化 #

外部变量 #

  • 外部变量和函数具有如下性质:通过同一个名字引用的所有外部变量实际上都是引用同一个对象。
  • 如果外部变量的定义和变量的使用不在同一个文件中,需要在相应的变量声明中强制性的使用关键字extern。
  • 变量的声明用于说明变量的属性(主要是变量的类型),而变量的定义除此外还将引起存储器的分配。以下语句如果放在所有函数的外部,那么这两条语句将定义外部变量sp和val,并为其分配存储单元。
int sp;
//声明外部变量必须指定数组长度。
double val[100];
  • 下面这两行声明了两个外部变量,并没有建立变量或分配存储空间。
extern int sp;
extern double val[];

静态变量 #

  • 用static声明限定外部变量和函数,可以将其声明后的对象的作用域限定为被编译源文件的剩余部分,通过static限定外部对象,可以隐藏外部对象
  • 通常情况下,函数名是全局可访问的,对于整个程序各个部分而言都可见。但如果将函数声明为static类型,则该函数除了对该函数声明所在的文件可见外,其他文件都无法访问。
  • static也可用于声明内部变量,但是不管函数是否被调用,它一直存在。static类型的内部变量是一种只能在某个特定函数中使用但是一直占用存储空间的变量。

初始化 #

  • 在不进行显式初始化的情况下,外部变量和静态变量都将被初始化为0,而内部变量和寄存器变量的初值则没有定义。
  • 对于外部变量和静态变量来说,初始化变量表达式必须是常量表达式,且只初始化一次。
  • 数组的初始化实在声明后紧跟一个初始化列表。
//当省略数组的长度时,编译器将把花括号中的长度作为数组的长度
int days[] = {31, 28, 31,30};

//字符数组的初始化方式如下
char pattern[] = "oule";
//等价于
char pattern = {'o', 'u', 'l', 'e', '\0'};

运算 #

  • 计算char类型或short类型时,会将其转化为int类型来计算。

预处理器 #

  • #include将指定文件的内容包含到当前文件中。
  • #define 名字 替换文本名字替换为替换文本
  • sizeof可以用来计算任一对象的长度,如sizeof(int)
  • 条件包括
#if SYSTEM == SYSV
    #define HDR "sysv.h"
#elif SYSTEM == BSD
    #define HDR "bsd.h"
#else
    #define HDR "default.h"
#endif

#include HDR
#ifdef HDR
	printf("DEF HDR");
#endif

指针与数组 #

  • &表示取一个对象的地址
//把c的地址给p
p = &c 
  • *作用于指针时,将访问指针所指向的对象。
  • 指针只能指向某种特定类型的对象(void*除外)。
  • 通过数组下表能实现的操作都可以通过指针来实现。
int a[] = {10, 11, 12, 13, 14, 15, 16, 17, 18, 19};
//将指针pa指向数组的第0个元素,pa的值为a[0]的地址
//等价于pa = a;
int *pa = &a[0];
//*pa 和 a[0] 的含义是相同的
int x1 = *pa;
printf("x1 的值为 %d\n", x1);
//&a[1] 和 a + 1 的含义是相同的
int x2 = *(a + 1);
printf("x2 的值为 %d\n", x2);
//pa[2] 和 *pa[2] 的含义是相同的
int x3 = pa[2];
printf("x3 的值为 %d\n", x3);
  • 数组和指针的不同点

    • 指针是一个变量,所以pa = apa++都是合法的。
    • 数组名不是变量,a = paa++非法。
  • 在函数的定义中,以下两种形参是等价的:

char s[];
char *s;
  • 可以将数组的一部分传递给函数:
//将起始于a[2]的子数组的地址传递给函数f
f(&a[2]);
//或
f(a + 2);

字符指针 #

  • 字符串常量是一个字符数组,在字符串的内部表示中,字符数组以空字符\0结尾。

  • 下面两个定义之间有很大的差别:

//定义了一个指针,指向了一个字符串常量,不能修改字符串的值
char *pmessage = "now is the time";

//定义了一个数组,数组中的单个字符可以修改
char a[] = "now is the time";

二维数组和指针数组 #

//真正的二维数组,分配了200个int类型长度的存储空间
int a[10][20];
//仅分配了10个指针,并没有对指针进行初始化,需要显式的进行初始化
//b的每个元素都是int *类型的指针,b并非是二维数组
int *b[10];

//例:
int *b[10];
int x1 = 1;
b[0] = &x1;

int x2[] = {21, 22};
b[1] = x2;
//相当于是一维数组,数组中的每个元素是字符串指针
char *name[] = {"illegal month", "jan", "feb", "mar"};
//二维数组,数组中的每个元素的长度是15,不够补充\0
char aname[][15] = {"illegal month", "jan", "feb", "mar"};

结构 #

//声明方式
struct point {
    int x;
    int y;
};

void print1(struct point *pt);

int main()
{
    struct point pt;
    pt.x = 1;
    pt.y = 2;
    print1(&pt);
}

void print1(struct point *pt)
{
    //pt->x 等价于 (*pt).x
    printf("x is %d\ny is %d\n", pt->x, pt->y);
}

类型定义typedef #

  • typedef用来建立新的数据类型名。
//类型定义
typedef int Length;
//声明变量
Length len, maxlen;

typedef struct point {
    int x;
    int y;
} Pointx;
Pointx px;

union #

  • 一个变量可以合法的保存多种数据类型中的任何一种类型的对象。
union u_tag {
    int ival;
    float fval;
    char *swal;
}u;

ubuntu

2021-09-25
linux

记录使用ubuntu的一些发现

  • 提升体验的一个软件apt install gnome-shell-extension-dash-to-panel;apt remove gnome-shell-extension-ubuntu-dock重启之后在gnome-tweaks中打开该扩展即可。它类似于windows的状态栏,比之前ubuntu自带的收藏栏和状态栏分开的情况好多了,而且可定制的程度高。 此种方式下载的已经过时,在ubuntu20上会有bug,最新版本可以通过 GNOME Shell Extensions下载,该网站需要安装浏览器扩展插件、本地主机安装chrome-gnome-shell,安装完后和直接在该网站下载Dash to Panel即可。参考链接: Installation · home-sweet-gnome/dash-to-panel Wiki · GitHub

  • neofetch 命令行显示系统信息、logo。

  • ctrl + d 文件夹添加到左边栏

  • gnome-screenshot --interactive --area 截图

  • sudo apt install papirus-icon-theme 好看的图标

  • 创建一个桌面应用图标:

#/usr/share/applications目录下
[Desktop Entry]
Name=Typora
Exec=/opt/Typora-linux-x64/Typora %f
Icon=/opt/Typora-linux-x64/resources/assets/icon/icon_256x256.png
Type=Application

The Exec key

linux开机

2021-09-24
linux

流程如下 #

  1. 加载BIOS的硬件信息、进行自我测试,根据设定取得第一个可开机的装置;
  2. 读取并执行第一个开机装置内的MBR的bootloader(如grub2);
  3. 依据bootloader的设定载入kernel,kernel会开始侦测硬件和载入驱动程序;
  4. 在硬件驱动成功后,kernel会主动呼叫systemd程序,并以default.target流程开机;
    1. systemd执行sysinit.target初始化系统及basic.target准备操作系统;
    2. systemd启动multi-user.target下的服务;
    3. systemd执行multi-user.target下的/etc/rc.d/rc.local文件;
    4. systemd执行multi-user.target下的getty.target及登入服务;
    5. systed执行graphical需要的服务。

BIOS(UEFI)、MBR(GPT)、bootloader #

  • BIOS(固件)是开机的时候,计算机系统会主动执行的第一个程序。通过BIOS去加载CMOS的信息,通过CMOS内的设置取得主机的各项硬件设置。例:CPU与周边设备的沟通时钟、开机设备的搜寻顺序、硬盘的大小和类型等,取得这些信息后,BIOS还会进行开机自测试(Power-on Self Test),然后开始执行硬件侦测的初始化,并设定PnP设备。之后再定义出可开机设备顺序,接下来就会开始进行开机设备的读取了。BIOS通过硬件的INT13中断功能来读取MBR,只要BIOS能检测到硬盘,就能通过INT13来读取磁盘的第一个磁区内的MBR软件。
  • UEFI(Unified Extension Firmware Interface)是取代BIOS的。
  • 整颗磁盘的第一个扇区特别重要,它记录了整颗磁盘的重要信息,早期磁盘的第一个扇区的包含重要的分区格式MBR(master boot record),后来多了一个新的磁盘分区格式,称为GPT(guid partition table)。
  • MBR可以安装开机管理程序,其和分区表通常放在磁盘的第一个扇区,这个扇区通常是512字节。开机管理程序占446字节,分区表占64字节。分区表最多只能有四组记录。
  • GPT将磁盘的所有区块以LBA(logical block address,预设为512字节)来规划,GPT使用34个LBA区块来记录分区信息,整个磁盘的最后33个LBA拿来作为备份。
  • boot loader的功能:①提供菜单;②装入核心文件;③转交其他loader。每个文件系统都会保留一块开机扇区提供操作系统安装bootloader,通常操作系统会安装一份boot loader到他自己的文件系统中。

  • 当boot loader开始读取内核文件后,linux会将核心解压到内存中,并使用核心的功能,开始测试cpu、网卡、声卡等装置,此时linux核心会以自己的功能重新侦测一次硬件。一般来说,核心文件被放在/boot中,并取名为/boot/vmlinuz。linux核心可以动态加载模块,这些核心模块放在/lib/modules目录中,开机过程中根目录采用只读方式挂载。虚拟文件系统(Initial RAM Filesystem)一般使用的文件名为/boot/initrd或/boot/initramfs。

  • linux预设情况下会提供6个终端让使用者登陆,切换方式为[ctrl]+[alt]+[f1]~[f6],6个终端命名为tty1~tty6。在centos7中,开机后系统只会提供一个tty,其他的是不存在的,当要切换时,系统才产生额外的tty2,tty3…。

make

2021-09-16
linux

  • 当执行make时,make会在当时的目录下搜索Makefile(makefile)文件,而makefile里面则记录了原始码如何编译的详细信息,make按照makefile去编译这些文件。当在编译完成之后,修改了某个源码文件,执行make时,make只会针对被修改的文件进行编译。通常软件开发商会写一支侦测程序来侦测使用者的作业环境,以及该作业环境是否有软件开发商所需要的其他功能,在侦测程序侦测完毕后,会主动建立Makefile,通常这个检查程序的文件名为configure或config。
  • tarball就是将软件的所有原始码文件先以tar打包,然后再压缩。tarball文件通常包括:源代码文件;侦测程序文件(configure或config);本软件的简易说明和安装说明(INSTALL或README)。
#-lm表示的是使用libm.so这个库,这个命令可以拆成两部分来看:l表示加入到某个函数库,m表示使用libm.so这个库,lib和扩展名.so或.a不需要写。
#-L/lib表示在这个路径下寻找库。
gcc test.c -lm -L/lib -L/lib64
#-I后面跟的路径就是设置要去搜索的include文件(如c语言的头文件)的目录。
gcc test.c -lm -I/usr/include
#将源码编译为目标文件,不链接
gcc -c hello.c
#-o将编译的结果输出为特定的文件,-Wall会输出经过信息。
gcc -o hello hello.c -Wall

makefile文件规则 #

#变量左右可以有空格,变量左边不能有tab键;变量和变量内容在等号两边不能有":"。
#变量习惯以大写字母为主。
#使用${xxx}或者$(xxx)来使用变量。
LIBS = -lm
OBJS = hello.o test.o
main:${OBJS}
	#tab必须是命令的第一个字符
	GCC -O MAIN ${OBJS} ${LIBS}
clean:
	rm -rf main ${OBJS}
	
#通过make clean来执行命令
#$@表示当前的目标,如这里的clean或main
  • 一般情况下,安装的基本步骤是:①./configure;②make clean;③make;④make install。

  • 通常会将自己安装的软件放到/usr/local下,将源代码放到/usr/local/src下。

鸟哥的 Linux 私房菜 – 第二十一章、软件安装:源代码与 Tarball (vbird.org)

nginx负载均衡

2021-09-13
nginx

nginx支持三种负载均衡的方法:

  1. 轮询(round-robin):按照顺序分配服务。
  2. least-connected:下一个请求被分配给连接数最少的服务。
  3. ip-hash:通过一个哈希算法来决定一个ip地址访问哪个后台服务,能保证一个ip一定会访问一个相同的后台服务(除非后台服务不可访问)。这种方式解决的问题是:如果某个ip已经登录了某个服务,当用户再次访问时会定位到该服务,解决了会话丢失的问题。

轮询算法(默认情况) #

http {
    upstream myapp1 {
        server example1.com;
        server example2.com;
        server example3.com;
    }
    server {
        listen 80;
        location / {
            proxy_pass http://myapp1;
        }
    }
}

使用least_conn命令的least-connected算法。 #

    upstream myapp1 {
        least_conn;
        server example1.com;
        server example2.com;
        server example3.com;
    }

使用ip_hash命令的ip-hash算法。 #

    upstream myapp1 {
        ip_hash;
        server example1.com;
        server example2.com;
        server example3.com;
    }

权重 #

upstream myapp1 {
        server srv1.example.com weight=3;
        server srv2.example.com;
        server srv3.example.com;
    }

参考链接: Using nginx as HTTP load balancer

shell脚本

2021-09-09
linux

  • 用户可以透过应用程序来指挥kernel,让kernel来完成我们所需要的硬件任务,因为程序是在最外层,类似鸡蛋的外壳一样,所以就叫壳程序(shell)。shell是提供用户操作系统的一个接口。

  • bash全称就是Bourne Again SHell,是linux预设的shell。

  • 系统中合法的shell都会写入到/etc/shells这个文件。当用户登录的时候,系统会提供一个shell,这个shell就记录在/etc/passwd这个文件中。

  • bash有很多内建指令,如cd等,可以通过type这个指令观察。

  • 一行输不完,可以通过\来换行。

  • shell脚本中第一行的#!/bin/bash宣告这个script使用的是bash的语法。

  • 当使用bash(sh)或者./xxx.sh来下达指令时,是在子程序中执行的;通过source来执行脚本时,是在父程序中执行的。子程序:在当前shell的情况下,去启动另一个新的shell,新的shell就是子程序。子程序会继承父进程的环境变量,但不会继承父进程的自定义变量。

  • login shell是取得bash时需要输入完整的登录账号密码的就是login shell。

  • non-login shell就是取得bash接口不需要重复的登入。如从图形化界面进入linux后,开启每个bash都不需要再次输入用户名和密码。这就是non-login shell。

  • login shell会读取/etc/profile(系统整体的设定,每个使用者登入取得bash时一定会读取的配置文件。)和~/.bash_profile或~/.bash_login或~/.profile(个人的设定)的文件。

  • non-login shell会读取~/.bashrc、/etc/bashrc、/etc/profile.d(不同的linux会有些不同)。

  • source可以立即读入配置文件的内容。

变量定义 #

  • 环境变量如PATH等,通常使用大写字符来表示,当输入了一个命令ls,系统会通过PATH这个遍历里面的内容记录的路径来顺序搜索指令。
  • 变量在使用时,需要加上在前面加上$。如$PATH,${PATH}
  • 通过envexport可以查询系统中所有的环境变量。

变量 #

  1. 设定变量直接使用等号=,如myname=xiaoxiang,等号两边不能有空格;
  2. 变量内容若有空格可以使用单引号或者双引号括起来,但是双引号内的特殊符号如$会保持原本的特性,而单引号内的特殊字符则是纯文字
  3. 当需要为变量扩增内容内容时,可以使用PATH=$PATH:/home/bin
  4. 通过export JAVA_HOME使得变量JAVA_HOME变成了环境变量。
  5. 通常大写字符为系统默认变量,自行设定的变量可以使用小写字符。
  6. 取消变量可以使用unset myname

read,array,declare #

  • read可以读取键盘输入的变量。如read -p "please input:" -t 10 name 。其中-p是提示信息,-t是倒计时,系统不会一直等待输入,name就是变量,会将输入的信息给这个变量。
  • declare、typeset是宣告变量的类型(shell默认类型是字符串)。declare命令如果用在函数中,声明的变量只在函数内部有效,等同于local命令。
    • declare -a var将var声明为数组类型array。
    • declare -i var将var声明为整数类型integer(bash中的数值计算最多只能达到整数形态)。
    • declare -x var将var声明为环境变量。
    • declare -r var将变量声明为只读类型readonly,改变量不可更改,不能unset。
    • declare -p var查看变量的类型。

数组 #

  • 数组可以采用逐个赋值的方法创建。也可以一次性赋值。
ARRAY[INDEX]=value
ARRAY=(value1 value2 ... valueN)
  • 读取元素
#输出单个元素,${}是必须的
echo ${array[0]}
#输出所有元素
echo ${foo[@]}
#循环遍历所有元素,数据要放在双引号中
for i in "${names[@]}"; do
  echo $i
done

#数组赋值
hobbies=( "${activities[@]}" )
#获取数组长度
echo ${#a[@]}

通配符与特殊符号 #

符号 意义
* 代表0到无穷多个任意字符
代表一定有一个的任意字符
[] 代表一定有一个在括号内的字符
[-] 表示一定有一个在编码顺序内的所有字符,如[0-9]表示一定有一个数字
[^] 表示反向选择,如[^abc]就表示一定有一个字符,但不是abc中的一个。

变量内容的删除与取代 #

符号 含义
# 从最左边开始,删除匹配最短的那个
## 从最左边开始,删除匹配最长的那个
% 从最右边开始,删除匹配最短的那个
%% 从最右边开始,删除匹配最长的那个
/旧字符串/新字符串 若变量内容符合旧字符串,则第一个旧字符串会被新字符串取代
//旧字符串/新字符串 若变量内容符合旧字符串,则全部旧字符串会被新字符串取代
#例:
path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:"
#去掉了开始的/usr/local/sbin:
echo ${path#/*:}
#输出为空
echo ${path##/*:}
#去掉了末尾的/bin:
echo ${path%/*:}
#输出为空
echo ${path%%/*:}
#将第一个出现的usr替换为USR
echo ${path/usr/USR}
#将所有的sbin替换为SBIN
echo ${path//sbin/SBIN}

tr:删除字符串中的一段文字,或者进行文字的替换。 #

  • cat example.txt | tr [a-z] [A-Z]将输出的文件中的所有小写字符变成大写字符。
  • cat /etc/passwd | tr -d ':'删除输出文件中的所有冒号:

变量的测试与内容替换 #

#减号-:当str不存在的时候,str=root,而当str存在(为空也视为存在)则str=$str
str=${username-root}
#:- 当str为空或不存在,str=root;str不为空则str=$str
str=${str:-root}

cut:将一段数据切出来 #

  • cat filename |cut -d '分隔字符' -f num:-d后面跟分隔字符,将数据分为几段,-f表示取出第几段。
  • cat filename |cut -c 12-:-c表示每一行都获取从第12个字符后面的所有字符(注意12后面有个减号)。

命令执行的判断依据 ; && || #

  • 命令之间用;隔开,分号前的指令执行完后会立刻接着执行后面的指令。
  • 命令之间用&&连接,表示当上一个指令正确执行完成后,才会接着执行下一个命令,这里使用到了上面提到的$?变量。如ls /tmp/abc && touch /tmp/abc/hehe,当不存在abc这个目录时,touch命令不会执行。
  • 命令之间用||连接,当上一个指令错误执行完成后,才会接着执行下一个命令。如ls /tmp/abc || mkdir /tmp/abc && touch /tmp/abc/hehe,当abc路径不存在时,会创建abc路径,并执行touch命令;而如果abc路径存在,则会直接执行touch命名。

格式化打印输出 #

  • %ns表示n个字符;%ni表示n个整数数字数;%N.nf表示一共N个数字,小数点占n个。
  • \n表示换行,\t表示tab键

正则 #

  • vi、grep、awk、seq等工具支持正则表达式;cp、ls不支持正则表达式,只能使用bash本身的通配符。
规则 意义
^word 寻找以word开始的行
word$ 寻找以行尾为word的行
. 代表任意一个字符
\ 转义字符
* 重复前一个字符0到无穷次
[abc] 搜寻含有a或b或c的那一行,[]只代表一个待搜寻的字符
[a-z] 搜寻两个字符间的所有连续字符,这个连续与ASCII编码有关。
[^abc] 反向选择,不要有a或者b或者c的行
\{n,m\} \{n,m\} 连续n到m个的前一个字符
\{n\} 连续n个前一个字符
\{n,\} 连续n个以上的前一个字符
[:alnum:] 代表a-z,A-Z,0-9
[:alpha:] 代表A-Z,a-z
[:blank:] 代表空格和[Tab]
[:digit:] 代表数字
[:lower:]、[:upper:] 代表小写字符、代表大写字符
[:space:] 任何会产生空白的字符,包括空格,[Tab],CR等
[:xdigit:] 代表16进位的数字类型。

test指令 #

文件的判断 #

命令 解释
test -e filename 判断文件是否存在
-f 是否为文件
-d 是否为目录
-r 是否有可读的权限
-w 是否有可写的权限
-x 是否有可执行的权限
-nt(newer than) 判断file1是否比file2新,例:test file1 -nt file2
-ot(older than) 判断file1是否比file2旧
-ef 判断两个文件是否是同一个文件,其实是判断两个文件是否指向同一个inode。

两个整数之间的判断 如:test n1 -eq n2 #

命令 介绍
-eq 两数值相等
-ne 两数值不等
-gt(greater than)/ -ge(greater than or equal) n1大于 / 大于等于n2
-lt / -le n1小于 / 小于等于n2

判断字符串的数据 #

命令 介绍
test -z string 若字符串为空串,则为true
test -n string 若字符串为非空串,则为true
test str1 == str2(bash中一个等号和两个等号是一样的) 若str1等于str2,则返回true
test str1 != str2 若str1不等于str2,则返回true

条件判断,如test -r filename -a -x filename #

命令 介绍
-a(and) 与,两条件同时成立返回true
-o(or) 或,任何一个条件成立就返回true
! 非,如test ! -x file,当file不具备执行条件时返回true

shell中的默认变量 #

  • shell定义了一些默认的变量。
tar -c -v -f example.tar example/
$0  $1 $2 $3    $4       $5
  • $#表示命令后面的参数个数,上面就是5。
  • $@表示"$1" “$2” “$3” “$4” “$5”。
  • $* 表示"$1 $2 $3 $4 $5"
  • $$ 当前shell的PID。
  • $? 上一个执行指令的回传值,一般一个指令执行完后,会回传一个0值。
  • $本身也是一个变量,代表着当前shell的PID,通过$$使用该变量。
  • ?是一个变量,代表上一个指令传回来的值,一般来说,当我们成功执行了一个指令,则会返回0值,如果执行错误,就会传回一个错误代码,通过$?来调用。

算数运算 #

  • ((...))语法可以进行整数的算术运算,((...))会自动忽略内部的空格。
((foo = 5 + 5))
echo $foo
  • 如果要结果,需要在((...))前面加上美元符号$((...))
total_mem=$(( 1 + 2 ))
#可以使用括号来改变运算顺序
echo $(( (2 + 3) * 4 ))
  • ((...))支持+ - * / %(取余) **(指数) ++ --++--这两个运算符有前缀和后缀的区别。作为前缀是先运算后返回值,作为后缀是先返回值后运算。

expr #

  • expr命令支持算术运算,可以不使用((...))语法,只支持整数。
foo=3
expr $foo + 2

条件判断式 #

if #

  • 中括号[ ]和test类似,也可以来进行数据的判断,中括号的两端需要有空格来分割。
if [ 条件判断式1 ];then
	指令
	指令
	exit 0
elif [ 条件判断式2 ];then
	指令
	指令
else
	指令
	指令
fi

#可以if后面可以跟上多个条件
if [ 条件判断式1 ] || [ 条件判断式2 ];then
if [ 条件判断式1 ] && [ 条件判断式2 ];then

case #

case $变量名称 in
	"第一个变量名称")
		指令
		指令
		;;
	"第二个变量名称")
		指令
		指令
		;;
	#下面这个有点类似于C语言的default
	*)
		指令
		指令
		;;
esac
#例:
case ${1} in 
    "--host"|"--ip")
        init_dir
        build_image
        modify_ip_address ${2}
        echo -e "文件已安装到\e[36m${base_dir}\e[0m下, 稍后请进入该目录下执行后续操作"
        ;;
    "build_image")
        build_image
        ;;
    *)
        display_help
        ;;
esac

函数function #

  • shell是从上往下执行,所以函数要放在程序的最前面。
#function关键字是可选的
#可以通过test abc来给函数传递参数
function test(){
	指令
	指令
}
  • return命令用于从函数返回一个值。函数执行到这条命令,就不再往下执行了,直接返回了。return后面可以不跟参数。

循环 #

不定循环 #

#当condition条件不成立时终止循环
while [ condition ]
do
	指令
	指令
done

#当condition条件成立时终止循环
until [ conditon ]
do
	指令
	指令
done

固定循环 #

for var in con1 con2 con3
do
	指令
	指令
done

#或

for (( 初始值; 限制值;执行步阶))
do
	指令
	指令
done
#一个案例
for (( i=1; i<=10; i=i+1)); do
	printf "%i\n" $i
done
#一个ping很多机器的shell脚本
#!bin/bash
network=82.156.3
#seq是sequence,会连续生成1到254之间的数
for site in $(seq 1 254)
do
		#-c表示ping几次,-w表示超时时间,单位是秒
        ping -c 1 -w 1 ${network}.${site} > /dev/null 2>&1
        if [ $? -eq 0 ];then
                echo "${network}.${site} is ok"
        else
                echo "${network}.${site} id down"
        fi
done
#计算多个容器使用内存之和

#!/bin/bash
total_mem=0
#获取要计算内存的容器名称
for item in $(docker ps | grep kuam | awk '{print $NF}'); do
    #获取容器的pid
    for pid in $(docker top ${item}  | grep -v PID | awk '{print $2}'); do
        #获取占用的内存
        mem=$(cat /proc/${pid}/status | grep -i vmrss | awk '{print $2}')
        echo "${item} PID:${pid} MEM:${mem}"
        #内存求和
        total_mem=$(( ${total_mem} + ${mem} ))
    done
done
echo "total mem: ${total_mem}"

shell调试 #

  • shell [-nvx] xxx.sh:-n查询语法是否正确;-v先输出文件内容再执行shell脚本;-x执行前先将使用到的script输出到屏幕上。

#

#!/bin/bash

#上传的文件路径
file_path="/tmp/blog.tar"
#文件放的位置
blog_dir="/opt/web/front/xiaoxiang.space"

#检查上传的文件是否存在
if [ !  -e "${file_path}" ];then
    echo "文件不存在"
    exit 0
fi

#检查当前是否有scp进程,没有就说明文件已经上传完成
scp_status=$(ps aux | grep scp | grep -v grep)
while [ -n "${scp_status}" ]
do
    sleep 1s
    scp_status=$(ps aux | grep scp | grep -v grep)
done
echo "传输完成..."

#将上传的文件解压到对应位置
mkdir -p ${blog_dir}
rm -rf "${blog_dir:?}/*"
if tar -xvf ${file_path} -C ${blog_dir};then
    echo "部署成功,文件位置为${blog_dir}"
fi

#删掉上传的文件
rm -f ${file_path}

jmeter

2021-09-06
java

  • 默认情况下JMeter的堆大小为1GB,可以调整堆的大小。可以在启动脚本时指定这些参数,也可以在bin路径下创建setenv.bat(windows)或setenv.sh(linux),格式如下:
#windows
set HEAP=-Xms2g -Xmx2g -XX:MaxMetaspaceSize=256m

#linux
export HEAP="-Xms1024m -Xmx1024m"
  • 解决cookie跨域CookieManager.check.cookies=false

命令行模式(CLI Mode) #

  • -n指定JMeter运行在cli模式。
  • -t指定JMX文件。
  • -l 指定jtl文件的名称,该文件是用来记录结果。
  • -e加载完测试后生成报告。
  • -o生成报告的文件夹的位置,必须为空或者不存在。
jmeter -n -t  test.jmx -l sso.jtl -e -o test

参考链接: Apache JMeter - User’s Manual: Getting Started

  • 类似于JDBC的jar包需要放在JMETER_HOME/lib路径下;开发的jmeter工具应放在JMETER_HOME/lib/ext路径下。

springboot配置

2021-09-01
java

springboot配置 #

配置加载顺序 #

  • 优先级从高到低
  1. 命令行传入的参数。
  2. SPRING_APPLICATION_JSON中的属性,是以JSON格式配置在系统环境变量中的内容。
  3. java:comp/env中的JNDI属性。
  4. java的系统属性,可以通过System.getProperties()获得的内容。
  5. 操作系统的环境变量。
  6. 通过random.*配置的随机属性。
  7. **位于当前jar包之外,针对于特定的环境的而指定的配置文件。**如application-prod.yml。
  8. 位于当前jar包内,针对于特定环境的而指定配置文件。
  9. 位于当前jar包外的application.properties和yml文件。
  10. 位于当前jar包内的application.properties和yml文件。
  11. 在@Configuration注解修饰的类中,通过@PropertySource注解定义的属性。
  12. 应用默认属性,使用SpringAppication.setDefaultProperties定义的内容。

注入到类 #

  1. resources/properties/person.properties
person.name=xiaoxiang
person.age=21
person.sex=1
person.weight=67
person.height=177
  1. java/space/xiaoxiang/properties/Person
@Component
@PropertySource(value = "classpath:properties/person.properties",ignoreResourceNotFound = false)
@ConfigurationProperties(prefix = "person")
@Data //必须要有setter方法,否则无法注入
public class Person {
    private String name;
    private int age;
    private int sex;
    private double weight;
    private double height;
    private String description;
}
  1. controller中注入
@Autowired
private Person person;

注入某个字段 #

  1. application.yml
sbl:
  hostname: xiaoxiang.space
  1. controller
@RestController
public class IndexController {

    //注入
    @Value("${sbl.hostname}")
    private String sblHostname;
	
    //...
}

参数引用 #

  • 在application.yml中的各个参数之间,可以通过placeholder的方式进行引用。
sbl:
  hostname: ${hostname}
hostname: xiaoxiang.space

使用随机数 #

#随机字符串
value1: ${random.value}
#随机int
value2: ${random.int}
#随机long
value3: ${random.long}
#10以内的随机数
value4: ${random.int(10)}
#10-20的随机数
value5: ${random.int[10,20]}

参考链接: Spring Boot 2.x基础教程:配置文件详解 | 程序猿DD