2013-02-19 21:53:34 wingSys 阅读数 1762

看<<unix高级程序设计>> 等书, 常会看到 kill(1) , conect(2) , select(2) 这样的写法.

1,2 表示什么?   

Linux下最通用的领域及其名称及说明如下:

领域 名称 说明

1 用户命令, 可由任何人启动的。

2 系统调用, 即由内核提供的函数。

3 例程, 即库函数。

4 设备, 即/dev目录下的特殊文件。

5 文件格式描述, 例如/etc/passwd。

6 游戏, 不用解释啦!

7 杂项, 例如宏命令包、惯例等。

8 系统管理员工具, 只能由root启动。

9 其他(Linux特定的), 用来存放内核例行程序的文档。

n 新文档, 可能要移到更适合的领域。

o 老文档, 可能会在一段期限内保留。

l 本地文档, 与本特定系统有关的。


在使用man 查询这些命令的时候,  可以用下面这样的格式:

$man  数字  命令

例如 :  $man 1 kill   #表示命令kill 

            $man 2 kill   #表示系统调用 kill



2017-10-23 23:13:35 Quartu_flag 阅读数 503

        当我们在使用man查询命令时会发现命令后面会有一个数字,如ls命令后面的1,shutdown后面的8。

LS(1)                            User Commands                           LS(1)

NAME
       ls - list directory contents
...... 

shutdown(8)                 System Manager's Manual                shutdown(8)

NAME
       shutdown - bring the system down
...... 
            那么这些数字有什么含义呢?使用man man命令可以看到一下的内容。

......
The table below shows the section numbers of the manual followed by the
       types of pages they contain.

       1   Executable programs or shell commands
       2   System calls (functions provided by the kernel)
       3   Library calls (functions within program libraries)
       4   Special files (usually found in /dev)
       5   File formats and conventions eg /etc/passwd
       6   Games
       7   Miscellaneous  (including  macro  packages  and  conventions), e.g.
           man(7), groff(7)
       8   System administration commands (usually only for root)
       9   Kernel routines [Non standard]
...... 
        一般我们使用较多的是1,5,8

                1.用户在Shell环境中可以操作的命令或可执行文件。

                5.配置文件或某些文件格式。

                8.系统管理员可用的管理命令。

2015-08-24 19:38:40 halazi100 阅读数 441
1.内存分配和回收的相关函数
    STL容器->自动分配和自动回收;
    |
    C++语言->new/delete;/*不是函数,没有括号,是操作符;*/
    |
    C语言->malloc()/free();
    |
    Unix系统函数->sbrk()/brk();/*都可以自动分配和自动回收;*/
    |
    Unix系统函数->mmap()分配/munmap()回收;
    |        (//用户层)
--------------------------------------------------
    Unix系统调用(内核层)->kmalloc(),vmalloc();

2.进程的内存空间
    2.1进程和程序的概念
        程序是保存在硬盘上的"可执行文件";
        进程是运行在内存中的程序实例;
        也就是说,程序是静态的文件,进程是内存中真正运行的部分;
    2.2一个进程的内存空间如何组成 /* 重点中的重点 */

       +--------------------------------+ (3Gb)
       |6.栈stack                       |
       +--------------------------------+
       |5.堆heap                        |
       +--------------------------------+   ^
       |4.BSS段(没有初值或者初值为0)    |   |
       +--------------------------------+   |
       |3.数据段(有初值的全局变量)      |   |
       +--------------------------------+   |
       |2.只读数据                      |   |
       |1.代码区                        |
       +--------------------------------+ (0Gb)

---------------------------------------------------------------
6->栈区:    保存局部变量(包括函数形参,块变量,函数返回值等);
            不同函数调用的空间遵循先进先出的原则;
            /* 内存的分配和回收都自动进行; */
5->堆区:    动态分配内存的区域,也叫自由区,受系统保护;
            new/delete/malloc()/free()都是针对堆区;
            堆区的内存完全由程序员管理,包括分配和回收;
            如果程序员没有回收将造成内存泄漏,直到进程结束;
------------------------
4->BSS段:   没有初值或初值为0的普通全局变量;
            /* BSS段会在main()执行之前自动清0; */
------------------------
3->全局区:  保存static变量和初值非0的全局变量;
            /* 主函数执行前分配,进程结束时回收; */
2->只读常量区: 存储字符串的字面值及const全局变量;
               字符串字面值就是双引号""括起来的字符串;
               /* 在某些资料中把该区并入代码区; */
1->代码区:  存放代码(包括函数)的区域;/* 只读的区域; */
--------------------------------------------------------------
注:
    对于普通全局变量,若初值为0则放BSS段,若有初值则放全局区;
    对于普通局部变量(不管有没有初值)放在栈区;
    static修饰的变量(不管是全局还是局部的变量)都放在全局区;
    不建议static修饰局部变量,类似于钉子户,该消失的时候未能消失;
    const修饰的全局变量放在只读区;
    const修饰的局部变量放在栈区;

3.Unix/Linux的虚拟内存空间
    在Unix/Linux系统中,内存地址其实是一个虚拟的内存地址,不是真实的物理内存地址;
    每个进程在启动时,就先天赋予了0~4GB的虚拟内存地址(与实际物理内存大小无关); 虚拟内存地址本质上就是一个整数,这个整数通过"内存映射"对应一个物理内存的地址; 但先天不对应任何的物理内存; 虚拟内存地址自身存储不了任何数据,只有内存映射之后才能存储数据,否则引发段错误(core dumped);
    malloc()做内存分配时,先做内存的映射,然后返回虚拟内存地址; 程序员所接触到的内存地址都是虚拟内存的地址;
    在进程的这4G虚拟内存被赋予时,并不是都做了内存映射,或许只映射了几K的物理内存,让程序正常运行就够了;
    其中第0~3G是给用户使用的,叫用户空间;第3~4G是给系统内核使用的,叫内核空间;用户空间的程序不能直接访问内核空间,但可以通过内核提供的系统函数进入内核空间;
    其中第0-3G是每个进程都会有的,第3-4G是所有进程共享的,每个进程被分配有8K的内核空间,叫内核栈;
    内存的管理是以"字节"作为基本单位;内存的映射以"内存页"作为基本单位;在目前主流的操作系统中就是4096字节(4k,0x1000);
    内存映射可以映射物理内存,也可以映射硬盘上的文件;
    代码区和只读常量区在一起;
    BSS段和全局区在一起;
    堆区和栈区都是独立的;

Linux系统中,几乎一切都可以用文件表示(包括进程process);
    /proc/进程PID/ 目录下会记录进程相关的数据,但这个数据不是保存在文件中的,是内存中的数据,所以文件大小(占用磁盘的大小)为0;
    /proc和/sys都是内存文件系统;
    cat /proc/进程PID/maps 可以查看内存使用的信息;
    ls -l /proc/10566 | more //可以分页查看

每个进程都会使用0~3G的用户空间,从小到大的次序是:代码区,只读常量区,全局区,BSS段,堆区,栈区;
堆区和栈区离得非常远,堆区在靠近0的位置从小向大延展,栈区在靠近3G的位置从大向小延展;
/*
 * 进程内存空间演示
 */
#include <stdio.h>
#include <stdlib.h>
int i1 = 10;        //i1在全局区
static int i2 = 20;    //static变量i2在全局区
int i3;                //没有初值的全局变量i3在BSS段
const int i4 = 40;    //const全局变量i4在只读区

void func(int i5) {    //i5在栈区
    int i6;            //局部变量在栈区
    static int i7 = 70;    //static变量i7在全局区
    const int i8 = 80;    //局部变量在栈区
    int *pi = malloc(4);//栈区pi指向手动分配的内存堆区
    char *s1 = "abc";    //s1保存字符串字面值指向只读常量区
    char s2[] = "abc";    //s2是局部变量在栈区,"abc"是字符串字面值在只读区,数组保存字符串的一份拷贝,数据保存到栈区;//

    printf("@栈区i5: %p\n", &i5);
    printf("@栈区i6: %p\n", &i6);
    printf("@全局区i7: %p\n", &i7);
    printf("@栈区i8: %p\n", &i8);
    printf("@栈区pi: %p, pi指向堆区: %p\n", &pi, pi);
    printf("@栈区s1: %p\n", &s1);
    printf("@栈区s1: %p, s1指向只读区@: %p\n", &s1, s1);
    printf("@只读区\"abc\": %p\n", "abc");
    printf("@栈区s2: %p, s2指向栈区: %p\n", &s2, s2);
}

int main() {
    printf("pid = %d\n", getpid());    //取进程的ID;
    printf("@全局i1: %p\n", &i1);
    printf("@全局i2: %p\n", &i2);
    printf("@BSS段i3: %p\n", &i3);
    printf("@只读常量i4: %p\n", &i4);
    printf("@代码func: %p\n", &func);
    func(1);
    printf("please use cat /proc/%d/maps \n", getpid());
    printf("sleeping 100s ...\n");
    sleep(100);        //睡眠100s后退出;
    return 0;
}



pid = 7851
@全局i1: 0x8049a2c
@全局i2: 0x8049a30
@BSS段i3: 0x8049a40
@只读常量i4: 0x8048714
@代码func: 0x8048484
@栈区i5: 0xbf970950
@栈区i6: 0xbf97093c
@全局区i7: 0x8049a34
@栈区i8: 0xbf970938
@栈区pi: 0xbf970934, pi指向堆区: 0x920b008
@栈区s1: 0xbf970930
@栈区s1: 0xbf970930, s1指向只读区@: 0x8048718
@只读区"abc": 0x8048718
@栈区s2: 0xbf97092c, s2指向栈区: 0xbf97092c

-----------#cat /proc/5841/maps--------------
00227000-003b7000 r-xp 00000000 08:18 1573894    /lib/libc-2.12.so
003b7000-003b9000 r--p 00190000 08:18 1573894    /lib/libc-2.12.so
003b9000-003ba000 rw-p 00192000 08:18 1573894    /lib/libc-2.12.so
003ba000-003bd000 rw-p 00000000 00:00 0
00b4f000-00b50000 r-xp 00000000 00:00 0          [vdso]
00e7c000-00e9a000 r-xp 00000000 08:18 1573887    /lib/ld-2.12.so
00e9a000-00e9b000 r--p 0001d000 08:18 1573887    /lib/ld-2.12.so
00e9b000-00e9c000 rw-p 0001e000 08:18 1573887    /lib/ld-2.12.so
08048000-08049000 r-xp 00000000 08:18 1048674    /home/uc/day03/a.out
08049000-0804a000 rw-p 00000000 08:18 1048674    /home/uc/day03/a.out
0920b000-0922c000 rw-p 00000000 00:00 0          [heap]
b7729000-b772a000 rw-p 00000000 00:00 0
b7743000-b7745000 rw-p 00000000 00:00 0
bf95e000-bf973000 rw-p 00000000 00:00 0          [stack]
---------------------------------------------

size命令可以查看程序中内存区域的情况:
#size a.out
   text       data        bss        dec        hex    filename
   1796        276         12       2084        824    a.out

    获取进程ID使用函数getpid();
    查看内存页的大小使用函数getpagesize();
    每个进程都有自己的0~4G的虚拟内存空间,但它们映射的实际物理内存完全不同,进程之间的内存空间互不干扰;
    不同进程的相同编号的虚拟地址空间对应不同的物理空间;

引发段错误的常见原因
    使用了没有映射的虚拟内存地址;
    执行了没有权限的操作,比如修改只读区;

字符串的处理和数据结构的基本应用
---------string_func.c----------------
/*
 * 字符串操作注意事项演示
 * 2015-07-12
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* 1字符串的声明和赋值 */
void str_pointer_strcpy() {
    /* =是在修改地址(将地址值赋值), strcpy()是修改地址中的内容(值); */
    /* 指向只读区的用=, 否则用strcpy比较好 */
    char *s1 = "abc";    /* s1在栈区,保存了"abc"(只读区)的首地址 */
    char s2[] = "abc";    /* s2是局部变量(数组), s2保存了"abc"的拷贝 */
    char *s3 = s2;        /* s3是普通局部变量在栈区,保存了数组s2的地址 */
    s1 = "123";        //对! 改地址,此时s1指向了"123";
    //strcpy(s1, "123");//段错误;修改只读区,此时s1是指向只读区的指针
    //s2 = "123"; //数组是常指针,不能再次改变指向,只可以改变其中的内容
    strcpy(s2, "123");    //对! 改变(s2数组的)内容
    strcpy(s3, "123");    //对! 改值;因s3现在是s2数组的首地址,结果会将"123"存入数组
    //s3 = "123"; //对! 改地址(栈区->只读常量区),但不安全;
    char *pi = malloc(sizeof(int));    /* pi 指向分配的堆内存 */
    //pi = "123";//将pi指向"123"只读区,用改地址的方式会造成堆内存泄漏(堆地址丢失);
    strcpy(pi, "123");    //比较安全的方式;pi仍指向堆内存(4个字节有效),内存存放内容为"123"字符串;
}

/* 2字符串的长度用strlen();sizeof取的是大小不是长度 */
void str_len_sizeof() {
    int i;
    char s4[] = { };    /* 数组的大小是0 */
    printf("s4 addr = %p, strlen = %d, sizeof = %d\n", s4, strlen(s4), sizeof(s4));
    strcpy(s4, "1234567");    /* 数组的可以当指针, strcpy关心的是指针 */
    /* s4[0-7] 是否合法/安全? 不安全 */
    /* strlen的参数是个指针, 而sizeof则会判断类型 */
    printf("s4's addr: %p, s4[0]'s addr: %p, s4[1]'s addr: %p\n", s4, &s4[0], &s4[1]);    /* s4[0]就是s4 */
    printf("s4's addr: %p, s4[0]: %p, s4[1]: %p\n", s4, s4[0], s4[1]);    /* s4[]存放了"1234567"的数据拷贝 */
    /* s4是一个在栈区的局部变量 */
    printf("strlen(s4) = %d, sizeof(s4) = %d\n", strlen(s4), sizeof(s4));    // strlen = 7, sizeof = 0
    /* 如果把strcpy一行注释掉,运行结果是strlen和曾经有初值的一次一样,sizeof为0; */
    for (i = 0; i <= strlen(s4) - 1; i++) {
        printf("strlen(s4) = %d, s4[%d] = %x\n", strlen(s4), i, s4[i]);
        /* s4[0-7] 是否合法/安全? 不安全 */
        /* 指针可以当数组,数组可以当指针 */
        /* 越界的会是乱码 */
    }
    printf("\n");
}

/* 3字符串的拼接,比如文件和所在目录拼接 */
void str_sprintf() {
    char *file = "hello.c";
    char *path = "/home/soft01";
    char buf[100] = { };
    sprintf(buf, "%s/%s", path, file);    /* 字符串拼接常用的函数 */
    /* 等价于
     * strcpy(buf, path);
     * strcat(buf, "/");
     * strcat(buf, file);
     */
    printf("%s\n", buf);
}

/* 4利用指针的操作进行字符串功能,比如拆分 */
void str_sscanf() {
    char *s5 = "zhangfei 25";
    char name[20] = { };
    int age;
    sscanf(s5, "%s %d", name, &age);    /* 将s5按格式拆分成name和age */
    /*
     * int i;
     * for(i = 0; i < strlen(s5); i++){
     *     if (*(s5+i) == ' ') {
     *         memcpy(name, s5, i);
     *         strcpy(age, s5+i+1);
     *         break;
     *     }
     * }
     */
    printf("name = %s, age = %d\n", name, age);
}

/* 5字符串和基本类型之间的转换(int,double); */
void str_int_convert() {
    char *s6 = "123";
    int num = 456;
    //sscanf()/sprintf()
    char buf2[20] = { };
    sprintf(buf2, "%d", num);    /* 将num输出的456(字符串)放入字符数组buf2 */
    printf("buf2 is string: %s\n", buf2);
    int num2;
    sscanf(s6, "%d", &num2);    /* 将s6的"123"作为输入, 作为数字类型放入num中 */
    printf("num2 = integer: %d\n", num2);
    /* 其实printf("%d\n", num);输出到屏幕时已经转换为字符串 */
    /* scanf("%d", &num);要求从键盘输入时,输入的都是字符串 */
    /* 从键盘输入的都作为字符串 */
}

/* C语言关于字符串操作的基本要求是特重点 */
int main()
{
    str_pointer_strcpy();
    str_len_sizeof();
    str_sprintf();
    str_sscanf();
    str_int_convert();
    return 0;
}



2017-07-23 16:15:05 simple_the_best 阅读数 4255

Shell 里面的中括号(包括单中括号与双中括号)可用于一些条件的测试:

  • 算术比较, 比如一个变量是否为0, [ $var -eq 0 ]
  • 文件属性测试,比如一个文件是否存在,[ -e $var ], 是否是目录,[ -d $var ]
  • 字符串比较, 比如两个字符串是否相同, [[ $var1 = $var2 ]]

[] 常常可以使用 test 命令来代替,后面有介绍。

算术比较

对变量或值进行算术条件判断:

[ $var -eq 0 ]  # 当 $var 等于 0 时,返回真
[ $var -ne 0 ]  # 当 $var 不等于 0 时,返回真

需要注意的是 [ 与 ] 与操作数之间一定要有一个空格,否则会报错。比如下面这样就会报错:

[$var -eq 0 ]  或 [ $var -ne 0] 

其他比较操作符:

操作符 意义
-gt 大于
-lt 小于
-ge 大于或等于
-le 小于或等于

可以通过 -a (and) 或 -o (or) 结合多个条件进行测试:

[ $var1 -ne 0 -a $var2 -gt 2 ]  # 使用逻辑与 -a
[ $var1 -ne 0 -o $var2 -gt 2 ]  # 使用逻辑或 -o

文件系统属性测试

使用不同的条件标志测试不同的文件系统属性。

操作符 意义
[ -f $file_var ] 变量 $file_var 是一个正常的文件路径或文件名 (file),则返回真
[ -x $var ] 变量 $var 包含的文件可执行 (execute),则返回真
[ -d $var ] 变量 $var 包含的文件是目录 (directory),则返回真
[ -e $var ] 变量 $var 包含的文件存在 (exist),则返回真
[ -c $var ] 变量 $var 包含的文件是一个字符设备文件的路径 (character),则返回真
[ -b $var ] 变量 $var 包含的文件是一个块设备文件的路径 (block),则返回真
[ -w $var ] 变量 $var 包含的文件可写(write),则返回真
[ -r $var ] 变量 $var 包含的文件可读 (read),则返回真
[ -L $var ] 变量 $var 包含是一个符号链接 (link),则返回真

使用方法如下:

fpath="/etc/passwd"
if [ -e $fpath ]; then
  echo File exits;
else
  echo Does not exit;
fi

字符串比较

在进行字符串比较时,最好使用双中括号 [[ ]]. 因为单中括号可能会导致一些错误,因此最好避开它们。

检查两个字符串是否相同:

[[ $str1 = $str2 ]]

str1str2 时,返回真。也就是说,str1 和 str2 包含的文本是一样的。其中的单等于号也可以写成双等于号,也就是说,上面的字符串比较等效于 [[ $str1 == $str2 ]].

注意 = 前后有一个空格,如果忘记加空格, 就变成了赋值语句,而非比较关系了。

字符串的其他比较情况:

操作符 意义
[[ $str1 != $str2 ]] 如果 str1 与 str2 不相同,则返回真
[[ -z $str1 ]] 如果 str1 是空字符串,则返回真
[[ -n $str1 ]] 如果 str1 是非空字符串,则返回真

使用逻辑运算符 && 和 || 可以轻松地将多个条件组合起来, 比如:

str1="Not empty"
str2=""
if [[ -n $str1 ]] && [[ -z $str2 ]];
then
  echo str1 is nonempty and str2 is empty string.
fi

test 命令也可以从来执行条件检测,用 test 可以避免使用过多的括号,[] 中的测试条件同样可以通过 test 来完成。

if [ $var -eq 0 ]; then echo "True"; fi

等价于

if test $var -eq 0; then echo "True"; fi

参考:
- [1] Linux Shell 脚本攻略

2010-06-06 22:43:00 iamliqiao 阅读数 569

 

它们看上去像某种函数调用,但不是。 这些数字表示可在"Unix manual"中的哪一部分找到对应的文档。 你可以输入"man 3 ctime"在手册的第三部分寻找到"ctime"的手册页。

传统的Unix手册页分部如下:

1 用户层面命令 
2 系统调用 
3 库函数 
4 设备和设备驱动 
5 文件格式 
6 游戏 
7 各式零碎杂物,如宏包等 
8 系统维护命令

一些Unix版本使用非数字的分部名。 比如Xenix用"C"代表命令,"S"代表函数。 一些新版本的Unix需要用"man -s # title"代替"man # title"

每个部分都有一个简介,可用"man # intro"阅读,#表示部分的编号。

某些场合,编号是必要的,以区别同名的命令和系统调用。比如系统可能存在time(1),time命令的手册页,同时还有time(3),判断当前时间的子程序调用。这时就需要用man 1 time和man 3 time,指明你感兴趣的手册页。

你也可在一些系统中看到其它的分部,甚至上述分部的亚部,例如Ultrix有3m, 3n, 3x and 3yp等。

 

没有更多推荐了,返回首页