C语法

C 语言是一种通用的、面向过程式的计算机程序设计语言。1972 年,为了移植与开发 UNIX 操作系统,丹尼斯·里奇在贝尔电话实验室设计开发了 C 语言。 // 单行注释以//开始。(仅适用于C99或更新的版本。) /* 多行注释是这个样子的。(C89也适用。) */ // 常数: #define 关键词 define表示创建变量或分配存储单元,而declaration指的是说明变量的性质并不分配存储单元 #define DAYS_IN_YEAR 365 // 以枚举的方式定义常数 enum days {SUN = 1, MON, TUE, WED, THU, FRI, SAT}; // MON自动被定义为2,TUE被定义为3,以此类推。 // 用#include来导入头文件 #include <stdlib.h> #include <stdio.h> #include <string.h> // <尖括号>间的文件名是C标准库的头文件。 // 标准库以外的头文件,使用双引号代替尖括号。 #include "my_header.h" // 函数的签名可以事先在.h文件中定义, // 也可以直接在.c文件的头部定义。 void function_1(char c); void function_2(void); // 如果函数出现在main()之后,那么必须在main()之前 // 先声明一个函数原型 int add_two_ints(int x1, int x2); // 函数原型 // 你的程序的入口是一个返回值为整型的main函数 int main() { // 用printf打印到标准输出,可以设定格式, // %d 代表整数, \n 代表换行 printf("%d\n", 0); // => 打印 0 // 所有的语句都要以分号结束 /////////////////////////////////////// // 类型 /////////////////////////////////////// // 在使用变量之前我们必须先声明它们。 // 变量在声明时需要指明其类型,而类型能够告诉系统这个变量所占用的空间 // int型(整型)变量一般占用4个字节 int x_int = 0; // short型(短整型)变量一般占用2个字节 short x_short = 0; // char型(字符型)变量会占用1个字节 char x_char = 0; char y_char = 'y'; // 字符变量的字面值需要用单引号包住 // long型(长整型)一般需要4个字节到8个字节; 而long long型则至少需要8个字节(64位) long x_long = 0; long long x_long_long = 0; // float一般是用32位表示的浮点数字 float x_float = 0.0; // double一般是用64位表示的浮点数字 double x_double = 0.0; // 整数类型也可以有无符号的类型表示。这样这些变量就无法表示负数 // 但是无符号整数所能表示的范围就可以比原来的整数大一些 unsigned short ux_short; unsigned int ux_int; unsigned long long ux_long_long; // 单引号内的字符是机器的字符集中的整数。 '0' // => 在ASCII字符集中是48 'A' // => 在ASCII字符集中是65 // char类型一定会占用1个字节,但是其他的类型却会因具体机器的不同而各异 // sizeof(T) 可以返回T类型在运行的机器上占用多少个字节 // 这样你的代码就可以在各处正确运行了 // sizeof(obj)返回表达式(变量、字面量等)的尺寸 printf("%zu\n", sizeof(int)); // => 4 (大多数的机器字长为4) // 如果`sizeof`的参数是一个表达式,那么这个参数不会被演算(VLA例外,见下) // 它产生的值是编译期的常数 int a = 1; // size_t是一个无符号整型,表示对象的尺寸,至少2个字节 size_t size = sizeof(a++); // a++ 不会被演算 printf("sizeof(a++) = %zu where a = %d\n", size, a); // 打印 "sizeof(a++) = 4 where a = 1" (在32位架构上) // 数组必须要被初始化为具体的长度 char my_char_array[20]; // 这个数组占据 1 * 20 = 20 个字节 int my_int_array[20]; // 这个数组占据 4 * 20 = 80 个字节 // (这里我们假设字长为4) // 可以用下面的方法把数组初始化为0: char my_array[20] = {0}; // 索引数组和其他语言类似 -- 好吧,其实是其他的语言像C my_array[0]; // => 0 // 数组是可变的,其实就是内存的映射! my_array[1] = 2; printf("%d\n", my_array[1]); // => 2 // 在C99 (C11中是可选特性),变长数组(VLA)也可以声明长度。 // 其长度不用是编译期常量。 printf("Enter the array size: "); // 询问用户数组长度 char buf[0x100]; fgets(buf, sizeof buf, stdin); // stroul 将字符串解析为无符号整数 size_t size = strtoul(buf, NULL, 10); int var_length_array[size]; // 声明VLA printf("sizeof array = %zu\n", sizeof var_length_array); // 上述程序可能的输出为: // > Enter the array size: 10 // > sizeof array = 40 // 字符串就是以 NUL (0x00) 这个字符结尾的字符数组, // NUL可以用'\0'来表示. // (在字符串字面量中我们不必输入这个字符,编译器会自动添加的) char a_string[20] = "This is a string"; printf("%s\n", a_string); // %s 可以对字符串进行格式化 /* 也许你会注意到 a_string 实际上只有16个字节长. 第17个字节是一个空字符(NUL) 而第18, 19 和 20 个字符的值是未定义。 */ printf("%d\n", a_string[16]); // => 0 // byte #17值为0(18,19,20同样为0) // 单引号间的字符是字符字面量 // 它的类型是`int`,而 *不是* `char` // (由于历史原因) int cha = 'a'; // 合法 char chb = 'a'; // 同样合法 (隐式类型转换 // 多维数组 int multi_array[2][5] = { {1, 2, 3, 4, 5}, {6, 7, 8, 9, 0} } // 获取元素 int array_int = multi_array[0][2]; // => 3 /////////////////////////////////////// // 操作符 /////////////////////////////////////// // 多个变量声明的简写 int i1 = 1, i2 = 2; float f1 = 1.0, f2 = 2.0; int a, b, c; a = b = c = 0; // 算数运算直截了当 i1 + i2; // => 3 i2 - i1; // => 1 i2 * i1; // => 2 i1 / i2; // => 0 (0.5,但会被化整为 0) f1 / f2; // => 0.5, 也许会有很小的误差 // 浮点数和浮点数运算都是近似值 // 取余运算 11 % 3; // => 2 // 你多半会觉得比较操作符很熟悉, 不过C中没有布尔类型 // 而是用整形替代 // (C99中有_Bool或bool。) // 0为假, 其他均为真. (比较操作符的返回值总是返回0或1) 3 == 2; // => 0 (false) 3 != 2; // => 1 (true) 3 > 2; // => 1 3 < 2; // => 0 2 <= 2; // => 1 2 >= 2; // => 1 // C不是Python —— 连续比较不合法 int a = 1; // 错误 int between_0_and_2 = 0 < a < 2; // 正确 int between_0_and_2 = 0 < a && a < 2; // 逻辑运算符适用于整数 !3; // => 0 (非) !0; // => 1 1 && 1; // => 1 (且) 0 && 1; // => 0 0 || 1; // => 1 (或) 0 || 0; // => 0 // 条件表达式 ( ? : ) int a = 5; int b = 10; int z; z = (a > b) ? a : b; // 10 “若a > b返回a,否则返回b。” // 增、减 char *s = "iLoveC" int j = 0; s[j++]; // "i" 返回s的第j项,然后增加j的值。 j = 0; s[++j]; // => "L" 增加j的值,然后返回s的第j项。 // j-- 和 --j 同理 // 位运算 ~0x0F; // => 0xF0 (取反) 0x0F & 0xF0; // => 0x00 (和) 0x0F | 0xF0; // => 0xFF (或) 0x04 ^ 0x0F; // => 0x0B (异或) 0x01 << 1; // => 0x02 (左移1位) 0x02 >> 1; // => 0x01 (右移1位) // 对有符号整数进行移位操作要小心 —— 以下未定义: // 有符号整数位移至符号位 int a = 1 << 32 // 左移位一个负数 int a = -1 << 2 // 移位超过或等于该类型数值的长度 // int a = 1 << 32; // 假定int32位 /////////////////////////////////////// // 控制结构 /////////////////////////////////////// if (0) { printf("I am never run\n"); } else if (0) { printf("I am also never run\n"); } else { printf("I print\n"); } // While循环 int ii = 0; while (ii < 10) { // 任何非0的值均为真 printf("%d, ", ii++); // ii++ 在取值过后自增 } // => 打印 "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, " printf("\n"); int kk = 0; do { printf("%d, ", kk); } while (++kk < 10); // ++kk 先自增,再被取值 // => 打印 "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, " printf("\n"); // For 循环 int jj; for (jj=0; jj < 10; jj++) { printf("%d, ", jj); } // => 打印 "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, " printf("\n"); // *****注意*****: // 循环和函数必须有主体部分,如果不需要主体部分: int i; for (i = 0; i <= 5; i++) { ; // 使用分号表达主体(null语句) } // 多重分支:switch() switch (some_integral_expression) { case 0: // 标签必须是整数常量表达式 do_stuff(); break; // 如果不使用break,控制结构会继续执行下面的标签 case 1: do_something_else(); break; default: // 假设 `some_integral_expression` 不匹配任何标签 fputs("error!\n", stderr); exit(-1); break; } /////////////////////////////////////// // 类型转换 /////////////////////////////////////// // 在C中每个变量都有类型,你可以将变量的类型进行转换 // (有一定限制) int x_hex = 0x01; // 可以用16进制字面量赋值 // 在类型转换时,数字本身的值会被保留下来 printf("%d\n", x_hex); // => 打印 1 printf("%d\n", (short) x_hex); // => 打印 1 printf("%d\n", (char) x_hex); // => 打印 1 // 类型转换时可能会造成溢出,而且不会抛出警告 printf("%d\n", (char) 257); // => 1 (char的最大值为255,假定char为8位长) // 使用<limits.h>提供的CHAR_MAX、SCHAR_MAX和UCHAR_MAX宏可以确定`char`、`signed_char`和`unisigned char`的最大值。 // 整数型和浮点型可以互相转换 printf("%f\n", (float)100); // %f 格式化单精度浮点 printf("%lf\n", (double)100); // %lf 格式化双精度浮点 printf("%d\n", (char)100.0); /////////////////////////////////////// // 指针 /////////////////////////////////////// // 指针变量是用来储存内存地址的变量 // 指针变量的声明也会告诉它所指向的数据的类型 // 你可以使用得到你的变量的地址,并把它们搞乱,;-) int x = 0; printf("%p\n", &x); // 用 & 来获取变量的地址 // (%p 格式化一个类型为 void *的指针) // => 打印某个内存地址 // 指针类型在声明中以*开头 int* px, not_a_pointer; // px是一个指向int型的指针 px = &x; // 把x的地址保存到px中 printf("%p\n", (void *)px); // => 输出内存中的某个地址 printf("%zu, %zu\n", sizeof(px), sizeof(not_a_pointer)); // => 在64位系统上打印“8, 4”。 // 要得到某个指针指向的内容的值,可以在指针前加一个*来取得(取消引用) // 注意: 是的,这可能让人困惑,'*'在用来声明一个指针的同时取消引用它。 printf("%d\n", *px); // => 输出 0, 即x的值 // 你也可以改变指针所指向的值 // 此时你需要取消引用上添加括号,因为++比*的优先级更高 (*px)++; // 把px所指向的值增加1 printf("%d\n", *px); // => 输出 1 printf("%d\n", x); // => 输出 1 // 数组是分配一系列连续空间的常用方式 int x_array[20]; int xx; for (xx=0; xx<20; xx++) { x_array[xx] = 20 - xx; } // 初始化 x_array 为 20, 19, 18,... 2, 1 // 声明一个整型的指针,并初始化为指向x_array int* x_ptr = x_array; // x_ptr现在指向了数组的第一个元素(即整数20). // 这是因为数组通常衰减为指向它们的第一个元素的指针。 // 例如,当一个数组被传递给一个函数或者绑定到一个指针时, //它衰减为(隐式转化为)一个指针。 // 例外: 当数组是`&`操作符的参数: int arr[10]; int (*ptr_to_arr)[10] = &arr; // &arr的类型不是`int *`! // 它的类型是指向数组的指针(数组由10个int组成) // 或者当数组是字符串字面量(初始化字符数组) char arr[] = "foobarbazquirk"; // 或者当它是`sizeof`或`alignof`操作符的参数时: int arr[10]; int *ptr = arr; // 等价于 int *ptr = &arr[0]; printf("%zu, %zu\n", sizeof arr, sizeof ptr); // 应该会输出"40, 4"或"40, 8" // 指针的增减多少是依据它本身的类型而定的 // (这被称为指针算术) printf("%d\n", *(x_ptr + 1)); // => 打印 19 printf("%d\n", x_array[1]); // => 打印 19 // 你也可以通过标准库函数malloc来实现动态分配 // 这个函数接受一个代表容量的参数,参数类型为`size_t` // 系统一般会从堆区分配指定容量字节大小的空间 // (在一些系统,例如嵌入式系统中这点不一定成立 // C标准对此未置一词。) // malloc并不是从一个在编译时就确定的固定大小的数组中分配存储空间,而是在需要的时候向操作系统申请空间 // 程序中可能不通过malloc调用申请空间,因此malloc管理的空间不一定是连续的 int *my_ptr = malloc(sizeof(*my_ptr) * 20); for (xx=0; xx<20; xx++) { *(my_ptr + xx) = 20 - xx; // my_ptr[xx] = 20-xx } // 初始化内存为 20, 19, 18, 17... 2, 1 (类型为int) // 对未分配的内存进行取消引用会产生未定义的结果 printf("%d\n", *(my_ptr + 21)); // => 谁知道会输出什么 // malloc分配的区域需要手动释放 // 否则没人能够再次使用这块内存,直到程序结束为止 free(my_ptr); // 字符串通常是字符数组,但是经常用字符指针表示 // (它是指向数组的第一个元素的指针) // 一个优良的实践是使用`const char *`来引用一个字符串字面量, // 因为字符串字面量不应当被修改(即"foo"[0] = 'a'犯了大忌) const char* my_str = "This is my very own string"; printf("%c\n", *my_str); // => 'T' // 如果字符串是数组,(多半是用字符串字面量初始化的) // 情况就不一样了,字符串位于可写的内存中 char foo[] = "foo"; foo[0] = 'a'; // 这是合法的,foo现在包含"aoo" function_1(); } // main函数结束 /////////////////////////////////////// // 函数 /////////////////////////////////////// // 函数声明语法: // <返回值类型> <函数名称>(<参数>) int add_two_ints(int x1, int x2){ return x1 + x2; // 用return来返回一个值 } /* 函数是按值传递的。当调用一个函数的时候,传递给函数的参数 是原有值的拷贝(数组除外)。你在函数内对参数所进行的操作 不会改变该参数原有的值。 但是你可以通过指针来传递引用,这样函数就可以更改值 例子:字符串本身翻转 */ // 类型为void的函数没有返回值 void str_reverse(char *str_in){ char tmp; int ii = 0; size_t len = strlen(str_in); // `strlen()`` 是C标准库函数 for (ii = 0; ii < len / 2; ii++) { tmp = str_in[ii]; str_in[ii] = str_in[len - ii - 1]; // 从倒数第ii个开始 str_in[len - ii - 1] = tmp; } } /* char c[] = "This is a test."; str_reverse(c); printf("%s\n", c); // => ".tset a si sihT" */ // 如果引用函数之外的变量,必须使用extern关键字 int i = 0; void testFunc() { extern int i; // 使用外部变量 i } // 使用static确保external变量为源文件私有 static int i = 0; // 其他使用 testFunc()的文件无法访问变量i void testFunc() { extern int i; } //**你同样可以声明函数为static** /////////////////////////////////////// // 用户自定义类型和结构 /////////////////////////////////////// // Typedefs可以创建类型别名 typedef int my_type; my_type my_type_var = 0; // struct是数据的集合,成员依序分配,按照 // 编写的顺序 struct rectangle { int width; int height; }; // 一般而言,以下断言不成立: // sizeof(struct rectangle) == sizeof(int) + sizeof(int) //这是因为structure成员之间可能存在潜在的间隙(为了对齐)[1] void function_1(){ struct rectangle my_rec; // 通过 . 来访问结构中的数据 my_rec.width = 10; my_rec.height = 20; // 你也可以声明指向结构体的指针 struct rectangle *my_rec_ptr = &my_rec; // 通过取消引用来改变结构体的成员... (*my_rec_ptr).width = 30; // ... 或者用 -> 操作符作为简写提高可读性 my_rec_ptr->height = 10; // Same as (*my_rec_ptr).height = 10; } // 你也可以用typedef来给一个结构体起一个别名 typedef struct rectangle rect; int area(rect r) { return r.width * r.height; } // 如果struct较大,你可以通过指针传递,避免 // 复制整个struct。 int area(const rect *r) { return r->width * r->height; } /////////////////////////////////////// // 函数指针 /////////////////////////////////////// /* 在运行时,函数本身也被存放到某块内存区域当中 函数指针就像其他指针一样(不过是存储一个内存地址) 但却可以被用来直接调用函数, 并且可以四处传递回调函数 但是,定义的语法初看令人有些迷惑 例子:通过指针调用str_reverse */ void str_reverse_through_pointer(char *str_in) { // 定义一个函数指针 f. void (*f)(char *); // 签名一定要与目标函数相同 f = &str_reverse; // 将函数的地址在运行时赋给指针 (*f)(str_in); // 通过指针调用函数 // f(str_in); // 等价于这种调用方式 } /* 只要函数签名是正确的,任何时候都能将任何函数赋给某个函数指针 为了可读性和简洁性,函数指针经常和typedef搭配使用: */ typedef void (*my_fnp_type)(char *); // 实际声明函数指针会这么用: // ... // my_fnp_type f; // 特殊字符 '\a' // bell '\n' // 换行 '\t' // tab '\v' // vertical tab '\f' // formfeed '\r' // 回车 '\b' // 退格 '\0' // null,通常置于字符串的最后。 // hello\n\0. 按照惯例,\0用于标记字符串的末尾。 '\\' // 反斜杠 '\?' // 问号 '\'' // 单引号 '\"' // 双引号 '\xhh' // 十六进制数字. 例子: '\xb' = vertical tab '\ooo' // 八进制数字. 例子: '\013' = vertical tab // 打印格式: "%d" // 整数 "%3d" // 3位以上整数 (右对齐文本) "%s" // 字符串 "%f" // float "%ld" // long "%3.2f" // 左3位以上、右2位以上十进制浮 "%7.4s" // (字符串同样适用) "%c" // 字母 "%p" // 指针 "%x" // 十六进制 "%o" // 八进制 "%%" // 打印 % /////////////////////////////////////// // 演算优先级 /////////////////////////////////////// //---------------------------------------------------// // 操作符 | 组合 // //---------------------------------------------------// // () [] -> . | 从左到右 // // ! ~ ++ -- + = *(type)sizeof | 从右到左 // // * / % | 从左到右 // // + - | 从左到右 // // << >> | 从左到右 // // < <= > >= | 从左到右 // // == != | 从左到右 // // & | 从左到右 // // ^ | 从左到右 // // | | 从左到右 // // && | 从左到右 // // || | 从左到右 // // ?: | 从右到左 // // = += -= *= /= %= &= ^= |= <<= >>= | 从右到左 // // , | 从左到右 // //---------------------------------------------------//

2017年5月8日 · 12 分钟 · Bug1024

Bash语法

bash 是一个为GNU计划编写的Unix shell。它的名字是一系列缩写:Bourne-Again SHell — 这是关于Bourne shell(sh)的一个双关语(Bourne again / born again)。 Bourne shell是一个早期的重要shell,由史蒂夫·伯恩在1978年前后编写,并同Version 7 Unix一起发布。bash则在1987年由布莱恩·福克斯创造。在1990年,Chet Ramey成为了主要的维护者。 ...

2017年5月7日 · 4 分钟 · Bug1024

Lua语法

Lua 是一个小巧的脚本语言。作者是巴西人。该语言的设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。 Lua脚本可以很容易的被C/C++代码调用,也可以反过来调用C/C++的函数,这使得Lua在应用程序中可以被广泛应用。不仅仅作为扩展脚本,也可以作为普通的配置文件,代替XML,Ini等文件格式,并且更容易理解和维护。 Lua由标准C编写而成,代码简洁优美,几乎在所有操作系统和平台上都可以编译,运行。 一个完整的Lua解释器不过200k,在目前所有脚本引擎中,Lua的速度是最快的。这一切都决定了Lua是作为嵌入式脚本的最佳选择。 ...

2017年4月30日 · 5 分钟 · Bug1024

性能监控之top

进程和CPU信息 参数 含义 load average: 0.06, 0.60, 0.48 系统负载,即任务队列的平均长度,1分钟、5分钟、15分钟前到现在的平均值, 按照经验小于0.7 x cpu核数则正常 Tasks: 29 total 进程总数 1 running 正在运行的进程数 28 sleeping 睡眠的进程数 0 stopped 停止的进程数 0 zombie 僵尸进程数 Cpu(s): 0.3% us 用户空间占用CPU百分比 1.0% sy 内核空间占用CPU百分比 0.0% ni 用户进程空间内改变过优先级的进程占用CPU百分比 98.7% id 空闲CPU百分比 0.0% wa 等待输入输出的CPU时间百分比 0.0% hi CPU服务于硬中断所耗费的时间总额 0.0% si、0.0%st CPU服务于软中断所耗费的时间总额、Steal Time 内存信息 参数 含义 Mem: 191272k total 物理内存总量 173656k used 使用的物理内存总量 17616k free 空闲内存总量 22052k buffers 用作内核缓存的内存量 Swap: 192772k total 交换区总量 0k used 使用的交换区总量 192772k free 空闲交换区总量 123988k cached 缓冲的交换区总量,内存中的内容被换出到交换区,而后又被换入到内存,但使用过的交换区尚未被覆盖, 该数值即为这些内容已存在于内存中的交换区的大小,相应的内存再次被换出时可不必再对交换区写入 进程统计信息 参数 含义 PID 进程id PPID 父进程id RUSER Real user name UID 进程所有者的用户id USER 进程所有者的用户名 GROUP 进程所有者的组名 TTY 启动进程的终端名.不是从终端启动的进程则显示为 ? PR 优先级 NI nice值.负值表示高优先级,正值表示低优先级 P 最后使用的CPU,仅在多CPU环境下有意义 %CPU 上次更新到现在的CPU时间占用百分比 TIME 进程使用的CPU时间总计,单位秒 TIME+ 进程使用的CPU时间总计,单位1/100秒 %MEM 进程使用的物理内存百分比 VIRT 进程使用的虚拟内存总量,单位kb,VIRT=SWAP+RES SWAP 进程使用的虚拟内存中,被换出的大小,单位kb. RES 进程使用的、未被换出的物理内存大小,单位kb,RES=CODE+DATA CODE 可执行代码占用的物理内存大小,单位kb DATA 可执行代码以外的部分(数据段+栈)占用的物理内存大小,单位kb SHR 共享内存大小,单位kb nFLT 页面错误次数 nDRT 最后一次写入到现在,被修改过的页面数. S 进程状态: D=不可中断的睡眠状态 R=运行 S=睡眠 T=跟踪/停止 Z=僵尸进程 COMMAND 命令名/命令行 WCHAN 若该进程在睡眠,则显示睡眠中的系统函数名 Flags 任务标志,参考 sched.h

2017年4月29日 · 2 分钟 · Bug1024

常用shell

内置变量 $0 脚本名称 $n 传给脚本/函数的第n个参数 $$ 脚本的PID $! 上一个被执行的命令的PID(后台运行的进程) $? 上一个命令的退出状态(管道命令使用${PIPESTATUS}) $# 传递给脚本/函数的参数个数 $@ 传递给脚本/函数的所有参数(识别每个参数) $* 传递给脚本/函数的所有参数(把所有参数当成一个字符串) 调试 # 抓包 tcpdump -i eth2 -w capture.cap tcp port 9501 and dst host 172.16.1.31 # 跟踪系统调用 strace -o strace.log -tt -f -e {call} -p {pid} # 开启coredump Mac下的cordump文件不在当前运行目录下,而是在系统指定目录,通常是/cores ulimit -c unlimited # 查看MTU cat /sys/class/net/eth0/mtu # -s 包的大小,Specifies the number of data bytes to be sent. ping -c 3 -s 2900 -M do 172.168.0.2 用户 # 新增用户 useradd user1 # 设置密码 passwd user1 # 新建用户组 groupadd group1 # 用户组新增用户 gpasswd -a user1 group1 # 修改目录所有者 chown -R user1:group1 dir1 文本处理 # 遍历查找当前目录下同时包含xxx和yyy的行 grep -r "xxx" . | grep "yyy" # 遍历查找当前目录下包含xxx或者yyy的行 grep -r . -e "xxx" -e "yyy" # 遍历查找当前目录下包含xxx但不包含yyy的行 grep -r "xxx" . | grep -v "yyy" # 查处字符串出现次数 grep -o "xxx"|wc -l # 显示file文件中匹配foo字串那行以及上下5行 grep -C 5 foo file # 显示foo及前5行 grep -B 5 foo file # 显示foo及后5行 grep -A 5 foo file # 匹配行带文件名,以下命令会返回类似结果结果:file1:hello file2:hhhhello grep -H hello file* # 查找7天内没访问过的文件 find path -atime +7 # 查找7天内访问过的文件 find path -atime -7 # 表示在当前目录及其子目录下查找普通文件中包含abc字符串的文件行,经常用于搜索代码 find . -type f|xargs grep 'abc' # 清理文件 find 路径 -name "*.log.*" -mtime +1 -delete # 从备份中的日志查询数据 bzcat xx.log.bz2 | grep "xxxx" bzgrep "xxxx" xx.log.bz2 # 消除重复行 sort unsort.txt | uniq # 统计各行在文件中出现的次数 sort unsort.txt | uniq -c # 找出重复行 sort unsort.txt | uniq -d # 统计行数,单词数,字符数 wc -[l][w][c] file # 清空文件,文件空间会立刻释放 echo "" > a.log # awk 转义需要两个反斜杆 awk -F'url\\[' '{print $2}' 磁盘管理 # 查看当前目录所占空间大小 du -sh # 查看当前目录下所有子文件夹排序后的大小: du -sh `ls` | sort # 查看当前正在写磁盘的进程id信息 iotop -o 进程管理 # 查看8080端口 lsof -i:8080 # 查看占用8080端口的进程 netstat -pan|grep 8080 # 查看用户username的进程所打开的文件 lsof -u username # 查询nginx进程当前打开的文件 lsof -c nginx # 查询指定的进程ID(23295)打开的文件: lsof -p 23295 # 查看打开文件数最多的10个进程 lsof +c 10 | awk '{print $1}' | sort | uniq -c | sort -rn | head 性能监控 # 查看页面交换发生状况 页面发生交换时,服务器的吞吐量会大幅下降,通常是内存不足导致,每秒采样1次,共采样3次 # sar不可用时,可以使用以下工具替代:linux下有 vmstat、Unix系统有prstat sar -W 1 3 # Linux上的ss命令可以用于替换netstat,ss直接读取解析/proc/net下的统计信息,相比netstat遍历/proc下的每个PID目录,速度快很多 ss -t -a 显示所有的TCP Sockets ss -u -a 显示所有的UDP Sockets ss -x src /tmp/a.sock 显示连接到/tmp/a.sock的进程 ss -o state [state TCP-STATE] 如ss -o state established显示所有建立的连接 系统信息 # 总核数 = 物理CPU个数 X 每颗物理CPU的核数 # 总逻辑CPU数 = 物理CPU个数 X 每颗物理CPU的核数 X 超线程数 # 查看物理CPU个数 cat /proc/cpuinfo| grep "physical id"| sort| uniq| wc -l # 查看每个物理CPU中core的个数(即核数) cat /proc/cpuinfo| grep "cpu cores"| uniq # 查看逻辑CPU的个数 cat /proc/cpuinfo| grep "processor"| wc -l 定时任务 格式:分钟[0-59] 小时[1-23] 日期[1-31] 月份[1-12] 星期[0-6] ...

2017年4月12日 · 5 分钟 · Bug1024

FastDFS

简介 由国人开发的, 用C语言实现的,开源的分布式文件系统,对文件进行管理,功能包括:文件存储、文件同步、文件访问(文件上传、文件下载)等,解决了大容量存储和负载均衡的问题, 特别适合以文件为载体的在线服务 设计 FastDFS中只有两个角色:Tracker和Storage。 Tracker作为中心结点,其主要作用是维护Storage信息,负载均衡和调度等。 Tracker会在内存和临时文件中记录Storage分组和Storage的状态等信息,不记录文件索引信息,占用的内存量很少。 而重要的文件索引信息将附属在Storage生成的文件ID中,这无疑去掉文件索引这一步,也提高了文件检索的性能。 存储 FastDFS采用了分组存储方式来保存文件的多个备份。 存储集群由一个或多个逻辑组构成,集群存储总容量为集群中所有组的存储容量(一个存储组的容量由该组中容量最小的Storage决定)之和。 一个组由一台或多台Storage组成,同组内的多台Storage之间是互备关系,同组内的存储服务器上的文件是完全一致的。 文件上传、下载、删除等操作可以在组内任意一台Storage上进行。 架构 ...

2017年4月9日 · 2 分钟 · Bug1024

Linux

Cgroup 计算资源 内存资源 IO资源 网络资源 进程 具有独立功能的程序,关于某个数据集合的一次运行过程 进程 = 程序 + 数据+ PCB 3个基本状态:ready(就绪等cpu)/running(运行)/waiting(等待事件的发生) PCB:进程存在的唯一标志 调度:状态转换时发生调度,IO密集型/CPU密集型,进程树,overhead(系统消耗) IPC:管道/共享内存(生产者/消费者)/消息传递(send/recv)/信号量/套接字,busy waiting CPU调度 FCFS(First-Come First-Served) SJF(Shortest-Job-First),preemptive(抢占式) Priority Scheduling Round Robin Multilevel Queue Scheduling Multilevel Feedback Queues 进程同步 entry section, critical section, exit section, remainder section 临界区使用原则:互斥(忙则等待),空闲让进,有限等待,让权等待 semaphore: wait()用于申请资源, signal()用于释放资源 生产者消费者问题,读者写者问题,哲学家进餐问题 管程 进程间通信 管道 文件和文件锁 共享内存 信号量 消息队列 死锁 两个或两个以上的进程由于竞争资源导致系统无法推进 产生必要条件:互斥,占有必等待,非抢占,循环等待 银行家算法(allocation,max,available) 内存管理 swapping, paging, segmentation 单CPU需要两个寄存器(基础+界限) 逻辑地址 物理地址 重定位寄存器 连续分配:固定分区,可变分区 离散分配:分页(页=>页框),分段,段页 虚拟存储 demand paging page replacement allocation of frames thrashing(抖动) 监控指标 load 特定事时间间隔内运行队列中的平均线程数 user time CPU执行用户进程所占用的时间 system time CPU在内核所花费的时间 nice time 系统在调整进程优先级的时候所花费的时间 idle time 系统空闲等待进程运行的时间 waiting time CPU在等待IO操作所花费的时间 hard irq time 系统处理硬件中断所占用的时间 soft irq time 系统处理软件中断所占用的时间 steal time 被强制等待虚拟机CPU的时间,占比较高表示当前虚拟机与该宿主其他虚拟机争用CPU频繁 磁盘剩余空间 使用df和du命令查看 网络traffic 使用sar命令查看 sar -n DEV 1 1 磁盘IO 使用iostat命令查看 iostat -d -k 内存使用 使用free命令查看 swap IO 使用vmstat命令查看 同步异步阻塞非阻塞 同步与异步关注的是消息通信机制 (synchronous communication/ asynchronous communication) 阻塞与非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态,主要是从CPU消耗上来说的 同步阻塞 最常用,IO性能较差,CPU大部分处于空闲 同步非阻塞 在网络IO是长链接且传输数据较小时可以有效提升性能 异步阻塞 在分布式数据库中常用,写一份记录通常会有一个是同步阻塞,而其他几份会采用异步阻塞方式写入其他机器 异步非阻塞 比较复杂,通常在集群间同步消息使用,例如cassandra,适合同时要传多份相同数据到不同机器,数据量不大但是异常频繁 僵尸进程与孤儿进程 在unix/linux中,正常情况下,子进程是通过父进程创建的,子进程再创建新的进程。子进程的结束和父进程的运行是一个异步过程,即父进程永远无法预测子进程到底什么时候结束。 当一个进程完成它的工作终止之后,它的父进程需要调用wait()或者waitpid()系统调用取得子进程的终止状态。 ...

2017年3月28日 · 4 分钟 · Bug1024

flag字段设计

多个字段实现状态 以商品为例,通常一个商品拥有多种状态标志,是否是打折商品,是否是推荐商品,是否是秒杀商品,对应表结构: id is_on_sale is_recommend is_seckill 1 1 0 1 2 0 0 1 3 1 1 1 这种方案不利于扩展,后期有新的标志需要再添加新的字段 ...

2017年3月22日 · 1 分钟 · Bug1024

UML系列

类图常见关系 泛化 Generalization 实现 Realization 关联 Association 聚合 Aggregation 组合 Composition 依赖 Dependency 泛化 继承关系,表示一般与特殊的关系 带三角箭头的实线,箭头指向父类 实现 类与接口的关系,表示类是接口所有特征和行为的实现 带三角箭头的虚线,箭头指向接口 关联 拥有的关系,它使一个类知道另一个类的属性和方法,双向的,代码体现为成员变量 带普通箭头的实心线,指向被拥有者 聚合 整体与部分的关系,且部分可以离开整体而单独存在,代码体现为成员变量 聚合关系是关联关系的一种,是强的关联关系,关联和聚合在语法上无法区分,必须考察具体的逻辑关系 带空心菱形的实心线,菱形指向整体 组合 整体与部分的关系,但部分不能离开整体而单独存在,代码体现为成员变量 带实心菱形的实线,菱形指向整体 依赖 使用的关系,即一个类的实现需要另一个类的协助,所以要尽量不使用双向的互相依赖,代码表现为局部变量、方法的参数或者对静态方法的调用 带箭头的虚线,指向被使用者

2017年3月21日 · 1 分钟 · Bug1024

JavaScript规范

为规范前端开发代码,提高代码质量,特制定此文档,其中声明,安全和分号这三节是必须执行的,组件类必须遵循注释规范。 声明 变量声明必须加var关键字,严格控制作用域; 建议使用驼峰式命名变量和函数,如:functionNamesLikeThis, variableNamesLikeThis, ClassNamesLikeThis,namespaceNamesLikeThis; 私有成员变量和方法命名以下划线开头,如:var _this; 常量定义单词全部大写,以下划线连接,但不要用const关键字来声明,如:SOME_CONSTANTS; 函数参数大于3个时,应以对象形式作为参数集传递; 禁止在代码块中声明函数,错误的范例:if (true) {function foo() {}}; 禁止用new来实例化基本类型,错误的范例:var x = new Boolean(false); 直接定义数组或对象,而不使用new关键字声明,错误的范例:var a = new Array();var o = new Object(); 使用单引号来定义字符串; 文件名必须全部用小写,文件名分隔符用中划线连接,版本连接符用实心点,合并文件的文件名连接符用下划线,如:passport-core.min.js和reset-1.0_utils-1.0.css; 安全 审查用户输入,如:从URL获取参数,使用跳转页面的referer,用于eval或DOM操作的用户数据; 禁止通过在iframe使用script进行跨域回调; 警惕jquery xss,禁止这样的写法:$(window.location.hash); 禁止引用站外资源; 分号 语句结束一定要加分号 ...

2017年3月17日 · 10 分钟 · Bug1024