友善交流技术...

发布新日志

  • Linux下Fork与Exec使用(转)

    2014-09-20 10:09:58

    Linux下Fork与Exec使用

    一、引言

      对于没有接触过Unix/Linux操作系统的人来说,fork是最难理解的概念之一:它执 行一次却返回两个值。fork函数是Unix系统最杰出的成就之一,它是七十年代UNIX早期的开发者经过长期在理论和实践上的艰苦探索后取得的成果,一 方面,它使操作系统在进程管理上付出了最小的代价,另一方面,又为程序员提供了一个简洁明了的多进程方法。与DOS和早期的Windows不 同,Unix/Linux系统是真正实现多任务操作的系统,可以说,不使用多进程编程,就不能算是真正的Linux环境下编程。

      多线程程序设计的概念早在六十年代就被提出,但直到八十年代中期,Unix系统中才引入多线程机制,如今,由于自身的许多优点,多线程编程已经得到了广泛的应用。

    下面,我们将介绍在Linux下编写多进程和多线程程序的一些初步知识。

    二、多进程编程

    什么是一个进程?进程这个概念是针对系统而不是针对用户的,对用户来说,他面对的概念是程序。当 用户敲入命令执行一个程序的时候,对系统而言,它将启动一个进程。但和程序不同的是,在这个进程中,系统可能需要再启动一个或多个进程来完成独立的多个任 务。多进程编程的主要内容包括进程控制和进程间通信,在了解这些之前,我们先要简单知道进程的结构。

      2.1 Linux下进程的结构

      Linux下一个进程在内存里有三部分的数据,就是"代码段"、"堆栈段"和"数据段"。其实学过汇编语言的人一定知道,一般的CPU都有上述三种段寄存器,以方便操作系统的运行。这三个部分也是构成一个完整的执行序列的必要的部分。

      "代码段",顾名思义,就是存放了程序代码的数据,假如机器中有数个进程运行相同的一个程 序,那么它们就可以使用相同的代码段。"堆栈段"存放的就是子程序的返回地址、子程序的参数以及程序的局部变量。而数据段则存放程序的全局变量,常数以及 动态数据分配的数据空间(比如用malloc之类的函数取得的空间)。这其中有许多细节问题,这里限于篇幅就不多介绍了。系统如果同时运行数个相同的程 序,它们之间就不能使用同一个堆栈段和数据段。  

      2.2 Linux下的进程控制

    在传统的Unix环境下,有两个基本的操作用于创建和修改进程:函数fork( )用来创建一个新的进程,该进程几乎是当前进程的一个完全拷贝;函数族exec( )用来启动另外的进程以取代当前运行的进程。Linux的进程控制和传统的Unix进程控制基本一致,只在一些细节的地方有些区别,例如在Linux系统 中调用vfork和fork完全相同,而在有些版本的Unix系统中,vfork调用有不同的功能。由于这些差别几乎不影响我们大多数的编程,在这里我们 不予考虑。

      2.2.1 fork()

      fork在英文中是"分叉"的意思。为什么取这个名字呢?因为一个进程在运行中,如果使用了fork,就产生了另一个进程,于是进程就"分叉"了,所以这个名字取得很形象。下面就看看如何具体使用fork,这段程序演示了使用fork的基本框架:

     1void main()
     2{
     3    int i;
     4    if ( fork() == 0 ) 
     5    {
     6       /* 子进程程序 */
     7       for ( i = 1; i <1000; i ++ ) 
     8          printf("This is child process\n");
     9    }
    10    else 
    11    {
    12       /* 父进程程序*/
    13       for ( i = 1; i <1000; i ++ ) 
    14       printf("This is process process\n");
    15    }
    16}

      程序运行后,你就能看到屏幕上交替出现子进程与父进程各打印出的一千条信息了。如果程序还在运行中,你用ps命令就能看到系统中有两个它在运行了。

      那么调用这个fork函数时发生了什么呢?fork函数启动一个新的进程,前面我们说过,这 个进程几乎是当前进程的一个拷贝:子进程和父进程使用相同的代码段;子进程复制父进程的堆栈段和数据段。这样,父进程的所有数据都可以留给子进程,但是, 子进程一旦开始运行,虽然它继承了父进程的一切数据,但实际上数据却已经分开,相互之间不再有影响了,也就是说,它们之间不再共享任何数据了。它们再要交 互信息时,只有通过进程间通信来实现,这将是我们下面的内容。既然它们如此相象,系统如何来区分它们呢?这是由函数的返回值来决定的。对于父进程, fork函数返回了子程序的进程号,而对于子程序,fork函数则返回零。在操作系统中,我们用ps函数就可以看到不同的进程号,对父进程而言,它的进程 号是由比它更低层的系统调用赋予的,而对于子进程而言,它的进程号即是fork函数对父进程的返回值。在程序设计中,父进程和子进程都要调用函数 fork()下面的代码,而我们就是利用fork()函数对父子进程的不同返回值用if...else...语句来实现让父子进程完成不同的功能,正如我 们上面举的例子一样。我们看到,上面例子执行时两条信息是交互无规则的打印出来的,这是父子进程独立执行的结果,虽然我们的代码似乎和串行的代码没有什么 区别。

      读者也许会问,如果一个大程序在运行中,它的数据段和堆栈都很大,一次fork就要复制一 次,那么fork的系统开销不是很大吗?其实UNIX自有其解决的办法,大家知道,一般CPU都是以"页"为单位来分配内存空间的,每一个页都是实际物理 内存的一个映像,象INTEL的CPU,其一页在通常情况下是 4086字节大小,而无论是数据段还是堆栈段都是由许多"页"构成的,fork函数复制这两个段,只是"逻辑"上的,并非"物理"上的,也就是说,实际执 行fork时,物理空间上两个进程的数据段和堆栈段都还是共享着的,当有一个进程写了某个数据时,这时两个进程之间的数据才有了区别,系统就将有区别的" 页"从物理上也分开。系统在空间上的开销就可以达到最小。

      下面演示一个足以"搞死"Linux的小程序,其源代码非常简单:

    1void main()
    2{
    3   for( ; ; )
    4   {
    5     fork();
    6   }
    7}

      这个程序什么也不做,就是死循环地fork,其结果是程序不断产生进程,而这些进程又不断产生新的进程,很快,系统的进程就满了,系统就被这么多不断产生 的进程"撑死了"。当然只要系统管理员预先给每个用户设置可运行的最大进程数,这个恶意的程序就完成不了企图了。

     

    2.2.2 exec( )函数族

    下面我们来看看一个进程如何来启动另一个程序的执行。在Linux中要使用exec函数族。系统 调用execve()对当前进程进行替换,替换者为一个指定的程序,其参数包括文件名(filename)、参数列表(argv)以及环境变量 (envp)。exec函数族当然不止一个,但它们大致相同,在 Linux中,它们分别是:execl,execlp,execle,execv,execve和execvp,下面我只以execlp为例,其它函数究 竟与execlp有何区别,请通过manexec命令来了解它们的具体情况。

      一个进程一旦调用exec类函数,它本身就"死亡"了,系统把代码段替换成新的程序的代码, 废弃原有的数据段和堆栈段,并为新程序分配新的数据段与堆栈段,唯一留下的,就是进程号,也就是说,对系统而言,还是同一个进程,不过已经是另一个程序 了。(不过exec类函数中有的还允许继承环境变量之类的信息。)

    那么如果我的程序想启动另一程序的执行但自己仍想继续运行的话,怎么办呢?那就是结合fork与exec的使用。下面一段代码显示如何启动运行其它程序:

     1#include <errno.h>
     2#include <stdio.h>
     3#include <stdlib.h>
     4
     5char command[256];
     6void main()
     7{
     8   int rtn; /*子进程的返回数值*/
     9   while(1) {
    10       /* 从终端读取要执行的命令 */
    11       printf( ">" );
    12       fgets( command, 256, stdin );
    13       command[strlen(command)-1= 0;
    14       if ( fork() == 0 ) {/* 子进程执行此命令 */
    15          execlp( command, NULL );
    16          /* 如果exec函数返回,表明没有正常执行命令,打印错误信息*/
    17          perror( command );
    18          exit( errno );
    19       }
    20       else {/* 父进程, 等待子进程结束,并打印子进程的返回值 */
    21          wait ( &rtn );
    22          printf( " child process return %d\n", rtn );
    23       }
    24   }
    25}

      此程序从终端读入命令并执行之,执行完成后,父进程继续等待从终端读入命令。熟悉DOS和 WINDOWS系统调用的朋友一定知道DOS/WINDOWS也有exec类函数,其使用方法是类似的,但DOS/WINDOWS还有spawn类函数, 因为DOS是单任务的系统,它只能将"父进程"驻留在机器内再执行"子进程",这就是spawn类的函数。WIN32已经是多任务的系统了,但还保留了 spawn类函数,WIN32中实现spawn函数的方法同前述 UNIX中的方法差不多,开设子进程后父进程等待子进程结束后才继续运行。UNIX在其一开始就是多任务的系统,所以从核心角度上讲不需要spawn类函 数。

      在这一节里,我们还要讲讲system()和popen()函数。system()函数先调 用fork(),然后再调用exec()来执行用户的登录 shell,通过它来查找可执行文件的命令并分析参数,最后它么使用wait()函数族之一来等待子进程的结束。函数popen()和函数 system()相似,不同的是它调用pipe()函数创建一个管道,通过它来完成程序的标准输入和标准输出。这两个函数是为那些不太勤快的程序员设计 的,在效率和安全方面都有相当的缺陷,在可能的情况下,应该尽量避免。

     

     2.3 Linux下的进程间通信

      详细的讲述进程间通信在这里绝对是不可能的事情,而且笔者很难有信心说自己对这一部分内容的 认识达到了什么样的地步,所以在这一节的开头首先向大家推荐著名作者Richard Stevens的著名作品:《Advanced Programming in the UNIX Environment》,它的中文译本《UNIX环境高级编程》已有机械工业出版社出版,原文精彩,译文同样地道,如果你的确对在Linux下编程有浓 厚的兴趣,那么赶紧将这本书摆到你的书桌上或计算机旁边来。说这么多实在是难抑心中的景仰之情,言归正传,在这一节里,我们将介绍进程间通信最最初步和最 最简单的一些知识和概念。

      首先,进程间通信至少可以通过传送打开文件来实现,不同的进程通过一个或多个文件来传递信 息,事实上,在很多应用系统里,都使用了这种方法。但一般说来,进程间通信(IPC:InterProcess Communication)不包括这种似乎比较低级的通信方法。Unix系统中实现进程间通信的方法很多,而且不幸的是,极少方法能在所有的Unix系 统中进行移植(唯一一种是半双工的管道,这也是最原始的一种通信方式)。而Linux作为一种新兴的操作系统,几乎支持所有的Unix下常用的进程间通信 方法:管道、消息队列、共享内存、信号量、套接口等等。下面我们将逐一介绍。

      2.3.1 管道

      管道是进程间通信中最古老的方式,它包括无名管道和有名管道两种,前者用于父进程和子进程间的通信,后者用于运行于同一台机器上的任意两个进程间的通信。

      无名管道由pipe()函数创建:

      #include <unistd.h>

      int pipe(int filedis[2]);

      参数filedis返回两个文件描述符:filedes[0]为读而打开,filedes[1]为写而打开。filedes[1]的输出是filedes[0]的输入。下面的例子示范了如何在父进程和子进程间实现通信。

     1 #define INPUT 0
     2 #define OUTPUT 1
     3 
     4 void main() {
     5    int file_descriptors[2];
     6    /*定义子进程号 */
     7    pid_t pid;
     8    char buf[256];
     9    int returned_count;
    10    /*创建无名管道*/
    11    pipe(file_descriptors);
    12    /*创建子进程*/
    13    if((pid = fork()) == -1) {
    14       printf("Error in fork\n");
    15       exit(1);
    16    }
    17    /*执行子进程*/
    18    if(pid == 0) {
    19       printf("in the spawned (child) process...\n");
    20       /*子进程向父进程写数据,关闭管道的读端*/
    21       close(file_descriptors[INPUT]);
    22       write(file_descriptors[OUTPUT], "test data", strlen("test data"));
    23       exit(0);
    24    } else {
    25       /*执行父进程*/
    26       printf("in the spawning (parent) process...\n");
    27       /*父进程从管道读取子进程写的数据,关闭管道的写端*/
    28       close(file_descriptors[OUTPUT]);
    29       returned_count = read(file_descriptors[INPUT], buf, sizeof(buf));
    30       printf("%d bytes of data received from spawned process: %s\n",
    31       returned_count, buf);
    32    }
    33 }

     在Linux系统下,有名管道可由两种方式创建:命令行方式mknod系统调用和函数mkfifo。下面的两种途径都在当前目录下生成了一个名为myfifo的有名管道:

      方式一:mkfifo("myfifo","rw");

      方式二:mknod myfifo p

      生成了有名管道后,就可以使用一般的文件I/O函数如open、close、read、write等来对它进行操作。下面即是一个简单的例子,假设我们已经创建了一个名为myfifo的有名管道。

     1/* 进程一:读有名管道*/
     2#include <stdio.h>
     3#include <unistd.h>
     4void main() {
     5    FILE * in_file;
     6    int count = 1;
     7    char buf[80];
     8    in_file = fopen("mypipe""r");
     9    if (in_file == NULL) {
    10        printf("Error in fdopen.\n");
    11        exit(1);
    12    }
    13    while ((count = fread(buf, 180, in_file)) > 0)
    14        printf("received from pipe: %s\n", buf);
    15    fclose(in_file);
    16}
    17/* 进程二:写有名管道*/
    18#include <stdio.h>
    19#include <unistd.h>
    20void main() {
    21    FILE * out_file;
    22    int count = 1;
    23    char buf[80];
    24    out_file = fopen("mypipe""w");
    25    if (out_file == NULL) {
    26        printf("Error opening pipe.");
    27        exit(1);
    28    }
    29    sprintf(buf,"this is test data for the named pipe example\n");
    30    fwrite(buf, 180, out_file);
    31    fclose(out_file);
    32}
    33

     

      2.3.2 消息队列

        消息队列用于运行于同一台机器上的进程间通信,它和管道很相似,事实上,它是一种正逐渐被淘汰的通信方式,我们可以用流管道或者套接口的方式来取代它,所以,我们对此方式也不再解释,也建议读者忽略这种方式。

      2.3.3 共享内存

      共享内存是运行在同一台机器上的进程间通信最快的方式,因为数据不需要在不同的进程间复制。 通常由一个进程创建一块共享内存区,其余进程对这块内存区进行读写。得到共享内存有两种方式:映射/dev/mem设备和内存映像文件。前一种方式不给系 统带来额外的开销,但在现实中并不常用,因为它控制存取的将是实际的物理内存,在Linux系统下,这只有通过限制Linux系统存取的内存才可以做到, 这当然不太实际。常用的方式是通过shmXXX函数族来实现利用共享内存进行存储的。

      首先要用的函数是shmget,它获得一个共享存储标识符。

      #include <sys/types.h>

      #include <sys/ipc.h>

      #include <sys/shm.h>

      int shmget(key_t key, int size, int flag);

      这个函数有点类似大家熟悉的malloc函数,系统按照请求分配size大小的内存用作共享 内存。Linux系统内核中每个IPC结构都有的一个非负整数的标识符,这样对一个消息队列发送消息时只要引用标识符就可以了。这个标识符是内核由IPC 结构的关键字得到的,这个关键字,就是上面第一个函数的 key。数据类型key_t是在头文件sys/types.h中定义的,它是一个长整形的数据。在我们后面的章节中,还会碰到这个关键字。

      当共享内存创建后,其余进程可以调用shmat()将其连接到自身的地址空间中。

      void *shmat(int shmid, void *addr, int flag);

      shmid为shmget函数返回的共享存储标识符,addr和flag参数决定了以什么方式来确定连接的地址,函数的返回值即是该进程数据段所连接的实际地址,进程可以对此进程进行读写操作。

      使用共享存储来实现进程间通信的注意点是对数据存取的同步,必须确保当一个进程去读取数据 时,它所想要的数据已经写好了。通常,信号量被要来实现对共享存储数据存取的同步,另外,可以通过使用shmctl函数设置共享存储内存的某些标志位如 SHM_LOCK、SHM_UNLOCK等来实现。

      2.3.4 信号量

      信号量又称为信号灯,它是用来协调不同进程间的数据对象的,而最主要的应用是前一节的共享内存方式的进程间通信。本质上,信号量是一个计数器,它用来记录对某个资源(如共享内存)的存取状况。一般说来,为了获得共享资源,进程需要执行下列操作:

      (1) 测试控制该资源的信号量。

      (2) 若此信号量的值为正,则允许进行使用该资源。进程将进号量减1。

      (3) 若此信号量为0,则该资源目前不可用,进程进入睡眠状态,直至信号量值大于0,进程被唤醒,转入步骤(1)。

      (4) 当进程不再使用一个信号量控制的资源时,信号量值加1。如果此时有进程正在睡眠等待此信号量,则唤醒此进程。

      维护信号量状态的是Linux内核操作系统而不是用户进程。我们可以从头文件/usr /src/linux/include /linux /sem.h 中看到内核用来维护信号量状态的各个结构的定义。信号量是一个数据集合,用户可以单独使用这一集合的每个元素。要调用的第一个函数是semget,用以获 得一个信号量ID。

      #include <sys/types.h>

      #include <sys/ipc.h>

      #include <sys/sem.h>

      int semget(key_t key, int nsems, int flag);

      key是前面讲过的IPC结构的关键字,它将来决定是创建新的信号量集合,还是引用一个现有 的信号量集合。    nsems是该集合中的信号量数。如果是创建新集合(一般在服务器中),则必须指定nsems;如果是引用一个现有的信号量集合 (一般在客户机中)则将nsems指定为0。

      semctl函数用来对信号量进行操作。

      int semctl(int semid, int semnum, int cmd, union semun arg);

      不同的操作是通过cmd参数来实现的,在头文件sem.h中定义了7种不同的操作,实际编程时可以参照使用。

    semop函数自动执行信号量集合上的操作数组。

      int semop(int semid, struct sembuf semoparray[], size_t nops);

      semoparray是一个指针,它指向一个信号量操作数组。nops规定该数组中操作的数量。

      下面,我们看一个具体的例子,它创建一个特定的IPC结构的关键字和一个信号量,建立此信号量的索引,修改索引指向的信号量的值,最后我们清除信号量。在下面的代码中,函数ftok生成我们上文所说的唯一的IPC关键字。

     1#include <stdio.h>
     2#include <sys/types.h>
     3#include <sys/sem.h>
     4#include <sys/ipc.h>
     5void main() {
     6    key_t unique_key; /* 定义一个IPC关键字*/
     7    int id;
     8    struct sembuf lock_it;
     9    union semun options;
    10    int i;
    11
    12    unique_key = ftok("."'a'); /* 生成关键字,字符'a'是一个随机种子*/
    13    /* 创建一个新的信号量集合*/
    14    id = semget(unique_key, 1, IPC_CREAT | IPC_EXCL | 0666);
    15    printf("semaphore id=%d\n", id);
    16    options.val = 1/*设置变量值*/
    17    semctl(id, 0, SETVAL, options); /*设置索引0的信号量*/
    18
    19    /*打印出信号量的值*/
    20    i = semctl(id, 0, GETVAL, 0);
    21    printf("value of semaphore at index 0 is %d\n", i);
    22
    23    /*下面重新设置信号量*/
    24    lock_it.sem_num = 0/*设置哪个信号量*/
    25    lock_it.sem_op = -1/*定义操作*/
    26    lock_it.sem_flg = IPC_NOWAIT; /*操作方式*/
    27    if (semop(id, &lock_it, 1== -1) {
    28        printf("can not lock semaphore.\n");
    29        exit(1);
    30    }
    31
    32    i = semctl(id, 0, GETVAL, 0);
    33    printf("value of semaphore at index 0 is %d\n", i);
    34
    35    /*清除信号量*/
    36    semctl(id, 0, IPC_RMID, 0);
    37}

     

      2.3.5 套接口

      套接口(socket)编程是实现Linux系统和其他大多数操作系统中进程间通信的主要方 式之一。我们熟知的WWW服务、FTP服务、TELNET服务等都是基于套接口编程来实现的。除了在异地的计算机进程间以外,套接口同样适用于本地同一台 计算机内部的进程间通信。关于套接口的经典教材同样是 Richard Stevens编著的《Unix网络编程:联网的API和套接字》,清华大学出版社出版了该书的影印版。它同样是Linux程序员的必备书籍之一。

      关于这一部分的内容,可以参照本文作者的另一篇文章《设计自己的网络蚂蚁》,那里由常用的几 个套接口函数的介绍和示例程序。这一部分或许是Linux进程间通信编程中最须关注和最吸引人的一部分,毕竟,Internet 正在我们身边以不可思议的速度发展着,如果一个程序员在设计编写他下一个程序的时候,根本没有考虑到网络,考虑到Internet,那么,可以说,他的设 计很难成功。

     

      3 Linux的进程和Win32的进程/线程比较

      熟悉WIN32编程的人一定知道,WIN32的进程管理方式与Linux上有着很大区别,在UNIX里,只有进程的概念,但在WIN32里却还有一个"线程"的概念,那么Linux和WIN32在这里究竟有着什么区别呢?

      WIN32里的进程/线程是继承自OS/2的。在WIN32里,"进程"是指一个程序,而" 线程"是一个"进程"里的一个执行"线索"。从核心上讲,WIN32的多进程与Linux并无多大的区别,在WIN32里的线程才相当于Linux的进 程,是一个实际正在执行的代码。但是,WIN32里同一个进程里各个线程之间是共享数据段的。这才是与Linux的进程最大的不同。

      下面这段程序显示了WIN32下一个进程如何启动一个线程。

     1 int g;
     2 DWORD WINAPI ChildProcess( LPVOID lpParameter ){
     3     int i;
     4     for ( i = 1; i <1000; i ++) {
     5         g ++;
     6         printf( "This is Child Thread: %d\n", g );
     7     }
     8     ExitThread( 0 );
     9 };
    10 
    11 void main()
    12 {
    13     int threadID;
    14     int i;
    15     g = 0;
    16     CreateThread( NULL, 0, ChildProcess, NULL, 0&threadID );
    17     for ( i = 1; i <1000; i ++) {
    18         g ++;
    19         printf( "This is Parent Thread: %d\n", g );
    20     }
    21 }

    在WIN32下,使用CreateThread函数创建线程,与Linux下创建进程不同,WIN32线程不是从创建处开始运行的,而是由 CreateThread指定一个函数,线程就从那个函数处开始运行。此程序同前面的UNIX程序一样,由两个线程各打印1000条信息。 threadID是子线程的线程号,另外,全局变量g是子线程与父线程共享的,这就是与Linux最大的不同之处。大家可以看出,WIN32的进程/线程 要比Linux复杂,在Linux要实现类似WIN32的线程并不难,只要fork以后,让子进程调用ThreadProc函数,并且为全局变量开设共享 数据区就行了,但在WIN32下就无法实现类似fork的功能了。所以现在WIN32下的C语言编译器所提供的库函数虽然已经能兼容大多数 Linux/UNIX的库函数,但却仍无法实现fork。

     

    对于多任务系统,共享数据区是必要的,但也是一个容易引起混乱的问题,在WIN32下,一个程序员很容易忘记线程之间的数据是共享的这一情况,一个 线程修改过一个变量后,另一个线程却又修改了它,结果引起程序出问题。但在Linux下,由于变量本来并不共享,而由程序员来显式地指定要共享的数据,使 程序变得更清晰与安全。

    至于WIN32的"进程"概念,其含义则是"应用程序",也就是相当于UNIX下的exec了。

    Linux也有自己的多线程函数pthread,它既不同于Linux的进程,也不同于WIN32下的进程,关于pthread的介绍和如何在Linux环境下编写多线程程序我们将在另一篇文章《Linux下的多线程编程》中讲述。

  • awk & sed 命令

    2012-08-23 13:15:38

    awk—sed 学习如下
     文档内容如下

    11862 root 20 0 352m 349m 177m R 91 8.6 420:39.13 t

    11862 root 20 0 352m 349m 177m R 99 8.6 420:49.41 t

    11862 root 20 0 352m 349m 177m R 101 8.6 420:59.84

    11862 root 20 0 352m 349m 177m R 96 8.6 421:10.21 t

    11862 root 20 0 352m 349m 177m R 101 8.6 421:20.50

    11862 root 20 0 352m 349m 177m R 99 8.6 421:28.56 t

    1、目标取9-10列数据
       sed -n '9,10p' file.log
       awk 'NR>=9&&NR<=10' file.log
    2、目标取9-10列求平均值
      sed -n '1,10p' file.log  | awk '{sum1=sum1+$9;$sum2=sum2+$10}END{print sum1/NR,sum2/NR}' 
  • Linux: Too many open filee 解决办法

    2012-04-06 17:29:30

    Linux系统默认最大打开文件数为1024个。

    1
    、相关命令:
    ulimit –a //
    查看当前设置
    ulimit –n 2048 //
    即设成2048,按实际需要设置,只是本shell生效的。重启或是重新链接都失效的。


    2
    、用户环境参数文件配置:
    /etc/profile中加入如下内容:

    if [ $SHELL = "/bin/ksh" ]; then 
    ulimit -p 16384 ulimit -n 65536 
    else 
    ulimit -u 16384 -n 65536 
    fi

    最好的解决办法,写入环境参数中来

    source /etc/profile 马上就可以生效的。

    ulimit -a 就可以看到修改后的数据

  • 删除7天前并大于1G的日志shell命令

    2012-04-05 11:03:42

    删除7天前并大于1G的日志shell命令

    1、脚本log.sh

    #!/bin/sh
    find /usr/local/apache-tomcat-6.0.20/logs -name "*log*"  -ctime +7 -size +1000000 | xargs rm -rf

    2、增加到执行计划中

    crontab -e

    30 23     * * *   /root/log.sh

    crontab -l 查看增加是否成功

     

  • find 命令常用集合

    2012-03-30 23:16:50

    通用格式:find pathname -options [-print -exec -ok]
    例子:
    find / -name filename 再根目录里面搜索文件名为filename的文件
    find /etc -name *s*在目录里面搜索带有s的文件
    find /etc -name *S 在目录里面搜索以s结尾的文件
    find /etc -name s*在目录里面搜索以s开头的文件
    find / -amin -10在系统中搜索最后10分钟访问的文件
    find / -atime -2查找在系统中最后48小时访问的文件
    find / -empty 查找在系统中为空的文件或者是文件夹
    find / -group groupname 查找在系统中属于groupname的文件
    find / -mmin -5查找在系统中最后5分钟修改过的文件
    find / -mtime -1查找在系统中最后24小时修改过的文件
    find /-nouser查找在系统中属于费用户的文件
    find / -user username 查找在系统中属于username的文件
    find / -ctime -1查找在系统中最后24小时被改变状态的文件
    find / -fstype type查找在系统中文件类型为?的文件
    find / -user user1name -or -user user2name查找在系统中属于user1name或着属于user2name的文件
    find / -user user1name -and -user2name在系统中查找既属于user1name又属于user2name用户的文件.

    一、find 命令格式


    1、find命令的一般形式为;

    find pathname -options [-print -exec -ok ...]


    2、find命令的参数;

    pathname: find命令所查找的目录路径。例如用.来表示当前目录,用/来表示系统根目录。
    -print: find命令将匹配的文件输出到标准输出。
    -exec: find命令对匹配的文件执行该参数所给出的shell命令。相应命令的形式为'command' { } \;,注意{ }和\;之间的空格。
    -ok: 和-exec的作用相同,只不过以一种更为安全的模式来执行该参数所给出的shell命令,在执行每一个命令之前,都会给出提示,让用户来确定是否执行。


    3、find命令选项

    -name
    按照文件名查找文件。
    -perm
    按照文件权限来查找文件。
    -prune
    使用这一选项可以使find命令不在当前指定的目录中查找,如果同时使用-depth选项,那么-prune将被find命令忽略。
    -user
    按照文件属主来查找文件。
    -group
    按照文件所属的组来查找文件。
    -mtime -n +n
    按照文件的更改时间来查找文件, - n表示文件更改时间距现在n天以内,+ n表示文件更改时间距现在n天以前。find命令还有-atime和-ctime 选项,但它们都和-m time选项。
    -nogroup
    查找无有效所属组的文件,即该文件所属的组在/etc/groups中不存在。
    -nouser
    查找无有效属主的文件,即该文件的属主在/etc/passwd中不存在。
    -newer file1 ! file2
    查找更改时间比文件file1新但比文件file2旧的文件。
    -type
    查找某一类型的文件,诸如:
    b - 块设备文件。
    d - 目录。
    c - 字符设备文件。
    p - 管道文件。
    l - 符号链接文件。
    f - 普通文件。
    -size n:[c] 查找文件长度为n块的文件,带有c时表示文件长度以字节计。
    -depth:在查找文件时,首先查找当前目录中的文件,然后再在其子目录中查找。
    -fstype:查找位于某一类型文件系统中的文件,这些文件系统类型通常可以在配置文件/etc/fstab中找到,该配置文件中包含了本系统中有关文件系统的信息。
    -mount:在查找文件时不跨越文件系统mount点。
    -follow:如果find命令遇到符号链接文件,就跟踪至链接所指向的文件。
    -cpio:对匹配的文件使用cpio命令,将这些文件备份到磁带设备中。

    另外,下面三个的区别:
      -amin n
      查找系统中最后N分钟访问的文件
      -atime n
      查找系统中最后n*24小时访问的文件
      -cmin n
      查找系统中最后N分钟被改变文件状态的文件
      -ctime n
      查找系统中最后n*24小时被改变文件状态的文件
       -mmin n
      查找系统中最后N分钟被改变文件数据的文件
      -mtime n
      查找系统中最后n*24小时被改变文件数据的文件

  • SED 单行脚本快速参考

    2011-12-12 16:31:56

    《SED 单行脚本快速参考》  

    常用命令总结:

     

    sed –I ‘1d’ aa.txt    //删除文件第一次

    $ sed '$d' aa.txt     //删除aa.txt文件的最后一行。

    Sed ‘/test/’d aa.txt   //删除 test所有的行

    sed G         //在每一行后面增加一空行

    sed 'G;G'   //在每一行后面增加两行空行

     

    sed –n ‘110’ aa.txt   //打印出文件前10  

    tail -10 aa.txt          //显示文件后10

    head -10 aa.txt        //显示文件的前10

    sed –I ‘s/Test/Fuck/g’ aa.txt   //在全文中查询Test 并替换成 Fuck ,-I 是写入到文件中

    sed '/test/'d  aa.txt    删除example文件所有包含test的行。

     

    SED 单行脚本快速参考 2005年12月29日

      英文标题:USEFUL ONE-LINE SCRIPTS FOR SED (Unix stream editor)
      原标题:HANDY ONE-LINERS FOR SED (Unix stream editor)
      整理:Eric Pement - 电邮:pemente[at]northpark[dot]edu 版本5.5
      译者:Joe Hong - 电邮:hq00e[at]126[dot]com
      在以下地址可找到本文档的最新(英文)版本:
      http://sed.sourceforge.net/sed1line.txt [1]
      http://www.pement.org/sed/sed1line.txt
      其他语言版本:
      中文 - http://sed.sourceforge.net/sed1line_zh-CN.html
      捷克语 - http://sed.sourceforge.net/sed1line_cz.html
      荷语 - http://sed.sourceforge.net/sed1line_nl.html
      法语 - http://sed.sourceforge.net/sed1line_fr.html
      德语 - http://sed.sourceforge.net/sed1line_de.html
      葡语 - http://sed.sourceforge.net/sed1line_pt-BR.html

    文本间隔:

      --------
      # 在每一行后面增加一空行
      sed G
      # 将原来的所有空行删除并在每一行后面增加一空行。
      # 这样在输出的文本中每一行后面将有且只有一空行。
      sed '/^$/d;G'
      # 在每一行后面增加两行空行
      sed 'G;G'
      # 将第一个脚本所产生的所有空行删除(即删除所有偶数行)
      sed 'n;d'
      # 在匹配式样“regex”的行之前插入一空行
      sed '/regex/{x;p;x;}'
      # 在匹配式样“regex”的行之后插入一空行
      sed '/regex/G'
      # 在匹配式样“regex”的行之前和之后各插入一空行
      sed '/regex/{x;p;x;G;}'

    编号:

      --------
      # 为文件中的每一行进行编号(简单的左对齐方式)。这里使用了“制表符”
      # (tab,见本文末尾关于'\t'的用法的描述)而不是空格来对齐边缘。
      sed = filename | sed 'N;s/\n/\t/'
      # 对文件中的所有行编号(行号在左,文字右端对齐)。
      sed = filename | sed 'N; s/^/ /; s/ *\(.\{6,\}\)\n/\1 /'
      # 对文件中的所有行编号,但只显示非空白行的行号。
      sed '/./=' filename | sed '/./N; s/\n/ /'
      # 计算行数 (模拟 "wc -l")
      sed -n '$='

    文本转换和替代:

      --------
      # Unix环境:转换DOS的新行符(CR/LF)为Unix格式。
      sed 's/.$//' # 假设所有行以CR/LF结束
      sed 's/^M$//' # 在bash/tcsh中,将按Ctrl-M改为按Ctrl-V
      sed 's/\x0D$//' # ssed、gsed 3.02.80,及更高版本
      # Unix环境:转换Unix的新行符(LF)为DOS格式。
      sed "s/$/`echo -e \\\r`/" # 在ksh下所使用的命令
      sed 's/$'"/`echo \\\r`/" # 在bash下所使用的命令
      sed "s/$/`echo \\\r`/" # 在zsh下所使用的命令
      sed 's/$/\r/' # gsed 3.02.80 及更高版本
      # DOS环境:转换Unix新行符(LF)为DOS格式。
      sed "s/$//" # 方法 1
      sed -n p # 方法 2
      # DOS环境:转换DOS新行符(CR/LF)为Unix格式。
      # 下面的脚本只对UnxUtils sed 4.0.7 及更高版本有效。要识别UnxUtils版本的
      # sed可以通过其特有的“--text”选项。你可以使用帮助选项(“--help”)看
      # 其中有无一个“--text”项以此来判断所使用的是否是UnxUtils版本。其它DOS
      # 版本的的sed则无法进行这一转换。但可以用“tr”来实现这一转换。
      sed "s/\r//" infile >outfile # UnxUtils sed v4.0.7 或更高版本
      tr -d \r <infile >outfile # GNU tr 1.22 或更高版本
      # 将每一行前导的“空白字符”(空格,制表符)删除
      # 使之左对齐
      sed 's/^[ \t]*//' # 见本文末尾关于'\t'用法的描述
      # 将每一行拖尾的“空白字符”(空格,制表符)删除
      sed 's/[ \t]*$//' # 见本文末尾关于'\t'用法的描述
      # 将每一行中的前导和拖尾的空白字符删除
      sed 's/^[ \t]*//;s/[ \t]*$//'
      # 在每一行开头处插入5个空格(使全文向右移动5个字符的位置)
      sed 's/^/ /'
      # 以79个字符为宽度,将所有文本右对齐
      sed -e :a -e 's/^.\{1,78\}$/ &/;ta' # 78个字符外加最后的一个空格
      # 以79个字符为宽度,使所有文本居中。在方法1中,为了让文本居中每一行的前
      # 头和后头都填充了空格。 在方法2中,在居中文本的过程中只在文本的前面填充
      # 空格,并且最终这些空格将有一半会被删除。此外每一行的后头并未填充空格。
      sed -e :a -e 's/^.\{1,77\}$/ & /;ta' # 方法1
      sed -e :a -e 's/^.\{1,77\}$/ &/;ta' -e 's/\( *\)\1/\1/' # 方法2
      # 在每一行中查找字串“foo”,并将找到的“foo”替换为“bar”
      sed 's/foo/bar/' # 只替换每一行中的第一个“foo”字串
      sed 's/foo/bar/4' # 只替换每一行中的第四个“foo”字串
      sed 's/foo/bar/g' # 将每一行中的所有“foo”都换成“bar”
      sed 's/\(.*\)foo\(.*foo\)/\1bar\2/' # 替换倒数第二个“foo”
      sed 's/\(.*\)foo/\1bar/' # 替换最后一个“foo”
      # 只在行中出现字串“baz”的情况下将“foo”替换成“bar”
      sed '/baz/s/foo/bar/g'
      # 将“foo”替换成“bar”,并且只在行中未出现字串“baz”的情况下替换
      sed '/baz/!s/foo/bar/g'
      # 不管是“scarlet”“ruby”还是“puce”,一律换成“red”
      sed 's/scarlet/red/g;s/ruby/red/g;s/puce/red/g' #对多数的sed都有效
      gsed 's/scarlet\|ruby\|puce/red/g' # 只对GNU sed有效
      # 倒置所有行,第一行成为最后一行,依次类推(模拟“tac”)。
      # 由于某些原因,使用下面命令时HHsed v1.5会将文件中的空行删除
      sed '1!G;h;$!d' # 方法1
      sed -n '1!G;h;$p' # 方法2
      # 将行中的字符逆序排列,第一个字成为最后一字,……(模拟“rev”)
      sed '/\n/!G;s/\(.\)\(.*\n\)/&\2\1/;//D;s/.//'
      # 将每两行连接成一行(类似“paste”)
      sed '$!N;s/\n/ /'
      # 如果当前行以反斜杠“\”结束,则将下一行并到当前行末尾
      # 并去掉原来行尾的反斜杠
      sed -e :a -e '/\\$/N; s/\\\n//; ta'
      # 如果当前行以等号开头,将当前行并到上一行末尾
      # 并以单个空格代替原来行头的“=”
      sed -e :a -e '$!N;s/\n=/ /;ta' -e 'P;D'
      # 为数字字串增加逗号分隔符号,将“1234567”改为“1,234,567”
      gsed ':a;s/\B[0-9]\{3\}\>/,&/;ta' # GNU sed
      sed -e :a -e 's/\(.*[0-9]\)\([0-9]\{3\}\)/\1,\2/;ta' # 其他sed
      # 为带有小数点和负号的数值增加逗号分隔符(GNU sed)
      gsed -r ':a;s/(^|[^0-9.])([0-9]+)([0-9])/\1\2,\3/g;ta'
      # 在每5行后增加一空白行 (在第5,10,15,20,等行后增加一空白行)
      gsed '0~5G' # 只对GNU sed有效
      sed 'n;n;n;n;G;' # 其他sed

    选择性地显示特定行:

      --------
      # 显示文件中的前10行 (模拟“head”的行为)
      sed 10q
      # 显示文件中的第一行 (模拟“head -1”命令)
      sed q
      # 显示文件中的最后10行 (模拟“tail”)
      sed -e :a -e '$q;N;11,$D;ba'
      # 显示文件中的最后2行(模拟“tail -2”命令)
      sed '$!N;$!D'
      # 显示文件中的最后一行(模拟“tail -1”)
      sed '$!d' # 方法1
      sed -n '$p' # 方法2
      # 显示文件中的倒数第二行
      sed -e '$!{h;d;}' -e x # 当文件中只有一行时,输入空行
      sed -e '1{$q;}' -e '$!{h;d;}' -e x # 当文件中只有一行时,显示该行
      sed -e '1{$d;}' -e '$!{h;d;}' -e x # 当文件中只有一行时,不输出
      # 只显示匹配正则表达式的行(模拟“grep”)
      sed -n '/regexp/p' # 方法1
      sed '/regexp/!d' # 方法2
      # 只显示“不”匹配正则表达式的行(模拟“grep -v”)
      sed -n '/regexp/!p' # 方法1,与前面的命令相对应
      sed '/regexp/d' # 方法2,类似的语法
      # 查找“regexp”并将匹配行的上一行显示出来,但并不显示匹配行
      sed -n '/regexp/{g;1!p;};h'
      # 查找“regexp”并将匹配行的下一行显示出来,但并不显示匹配行
      sed -n '/regexp/{n;p;}'
      # 显示包含“regexp”的行及其前后行,并在第一行之前加上“regexp”所
      # 在行的行号 (类似“grep -A1 -B1”)
      sed -n -e '/regexp/{=;x;1!p;g;$!N;p;D;}' -e h
      # 显示包含“AAA”、“BBB”或“CCC”的行(任意次序)
      sed '/AAA/!d; /BBB/!d; /CCC/!d' # 字串的次序不影响结果
      # 显示包含“AAA”、“BBB”和“CCC”的行(固定次序)
      sed '/AAA.*BBB.*CCC/!d'
      # 显示包含“AAA”“BBB”或“CCC”的行 (模拟“egrep”)
      sed -e '/AAA/b' -e '/BBB/b' -e '/CCC/b' -e d # 多数sed
      gsed '/AAA\|BBB\|CCC/!d' # 对GNU sed有效
      # 显示包含“AAA”的段落 (段落间以空行分隔)
      # HHsed v1.5 必须在“x;”后加入“G;”,接下来的3个脚本都是这样
      sed -e '/./{H;$!d;}' -e 'x;/AAA/!d;'
      # 显示包含“AAA”“BBB”和“CCC”三个字串的段落 (任意次序)
      sed -e '/./{H;$!d;}' -e 'x;/AAA/!d;/BBB/!d;/CCC/!d'
      # 显示包含“AAA”、“BBB”、“CCC”三者中任一字串的段落 (任意次序)
      sed -e '/./{H;$!d;}' -e 'x;/AAA/b' -e '/BBB/b' -e '/CCC/b' -e d
      gsed '/./{H;$!d;};x;/AAA\|BBB\|CCC/b;d' # 只对GNU sed有效
      # 显示包含65个或以上字符的行
      sed -n '/^.\{65\}/p'
      # 显示包含65个以下字符的行
      sed -n '/^.\{65\}/!p' # 方法1,与上面的脚本相对应
      sed '/^.\{65\}/d' # 方法2,更简便一点的方法
      # 显示部分文本——从包含正则表达式的行开始到最后一行结束
      sed -n '/regexp/,$p'
      # 显示部分文本——指定行号范围(从第8至第12行,含8和12行)
      sed -n '8,12p' # 方法1
      sed '8,12!d' # 方法2
      # 显示第52行
      sed -n '52p' # 方法1
      sed '52!d' # 方法2
      sed '52q;d' # 方法3, 处理大文件时更有效率
      # 从第3行开始,每7行显示一次
      gsed -n '3~7p' # 只对GNU sed有效
      sed -n '3,${p;n;n;n;n;n;n;}' # 其他sed
      # 显示两个正则表达式之间的文本(包含)
      sed -n '/Iowa/,/Montana/p' # 区分大小写方式

    选择性地删除特定行:

      --------
      # 显示通篇文档,除了两个正则表达式之间的内容
      sed '/Iowa/,/Montana/d'
      # 删除文件中相邻的重复行(模拟“uniq”)
      # 只保留重复行中的第一行,其他行删除
      sed '$!N; /^\(.*\)\n\1$/!P; D'
      # 删除文件中的重复行,不管有无相邻。注意hold space所能支持的缓存
      # 大小,或者使用GNU sed。
      sed -n 'G; s/\n/&&/; /^\([ -~]*\n\).*\n\1/d; s/\n//; h; P'
      # 删除除重复行外的所有行(模拟“uniq -d”)
      sed '$!N; s/^\(.*\)\n\1$/\1/; t; D'
      # 删除文件中开头的10行
      sed '1,10d'
      # 删除文件中的最后一行
      sed '$d'
      # 删除文件中的最后两行
      sed 'N;$!P;$!D;$d'
      # 删除文件中的最后10行
      sed -e :a -e '$d;N;2,10ba' -e 'P;D' # 方法1
      sed -n -e :a -e '1,10!{P;N;D;};N;ba' # 方法2
      # 删除8的倍数行
      gsed '0~8d' # 只对GNU sed有效
      sed 'n;n;n;n;n;n;n;d;' # 其他sed
      # 删除匹配式样的行
      sed '/pattern/d' # 删除含pattern的行。当然pattern
      # 可以换成任何有效的正则表达式
      # 删除文件中的所有空行(与“grep '.' ”效果相同)
      sed '/^$/d' # 方法1
      sed '/./!d' # 方法2
      # 只保留多个相邻空行的第一行。并且删除文件顶部和尾部的空行。
      # (模拟“cat -s”)
      sed '/./,/^$/!d' #方法1,删除文件顶部的空行,允许尾部保留一空行
      sed '/^$/N;/\n$/D' #方法2,允许顶部保留一空行,尾部不留空行
      # 只保留多个相邻空行的前两行。
      sed '/^$/N;/\n$/N;//D'
      # 删除文件顶部的所有空行
      sed '/./,$!d'
      # 删除文件尾部的所有空行
      sed -e :a -e '/^\n*$/{$d;N;ba' -e '}' # 对所有sed有效
      sed -e :a -e '/^\n*$/N;/\n$/ba' # 同上,但只对 gsed 3.02.*有效
      # 删除每个段落的最后一行
      sed -n '/^$/{p;h;};/./{x;/./p;}'

    特殊应用:

      --------
      # 移除手册页(man page)中的nroff标记。在Unix System V或bash shell下使
      # 用'echo'命令时可能需要加上 -e 选项。
      sed "s/.`echo \\\b`//g" # 外层的双括号是必须的(Unix环境)
      sed 's/.^H//g' # 在bash或tcsh中, 按 Ctrl-V 再按 Ctrl-H
      sed 's/.\x08//g' # sed 1.5,GNU sed,ssed所使用的十六进制的表示方法
      # 提取新闻组或 e-mail 的邮件头
      sed '/^$/q' # 删除第一行空行后的所有内容
      # 提取新闻组或 e-mail 的正文部分
      sed '1,/^$/d' # 删除第一行空行之前的所有内容
      # 从邮件头提取“Subject”(标题栏字段),并移除开头的“Subject:”字样
      sed '/^Subject: */!d; s///;q'
      # 从邮件头获得回复地址
      sed '/^Reply-To:/q; /^From:/h; /./d;g;q'
      # 获取邮件地址。在上一个脚本所产生的那一行邮件头的基础上进一步的将非电邮
      # 地址的部分剃除。(见上一脚本)
      sed 's/ *(.*)//; s/>.*//; s/.*[:<] *//'
      # 在每一行开头加上一个尖括号和空格(引用信息)
      sed 's/^/> /'
      # 将每一行开头处的尖括号和空格删除(解除引用)
      sed 's/^> //'
      # 移除大部分的HTML标签(包括跨行标签)
      sed -e :a -e 's/<[^>]*>//g;/</N;//ba'
      # 将分成多卷的uuencode文件解码。移除文件头信息,只保留uuencode编码部分。
      # 文件必须以特定顺序传给sed。下面第一种版本的脚本可以直接在命令行下输入;
      # 第二种版本则可以放入一个带执行权限的shell脚本中。(由Rahul Dhesi的一
      # 个脚本修改而来。)
      sed '/^end/,/^begin/d' file1 file2 ... fileX | uudecode # vers. 1
      sed '/^end/,/^begin/d' "$@" | uudecode # vers. 2
      # 将文件中的段落以字母顺序排序。段落间以(一行或多行)空行分隔。GNU sed使用
      # 字元“\v”来表示垂直制表符,这里用它来作为换行符的占位符——当然你也可以
      # 用其他未在文件中使用的字符来代替它。
      sed '/./{H;d;};x;s/\n/==/g' file | sort | sed '1s/==//;s/==/\n/g'
      gsed '/./{H;d};x;y/\n/\v/' file | sort | sed '1s/\v//;y/\v/\n/'
      # 分别压缩每个.TXT文件,压缩后删除原来的文件并将压缩后的.ZIP文件
      # 命名为与原来相同的名字(只是扩展名不同)。(DOS环境:“dir /b”
      # 显示不带路径的文件名)。
      echo @echo off >zipup.bat
      dir /b *.txt | sed "s/^\(.*\)\.TXT/pkzip -mo \1 \1.TXT/" >>zipup.bat
  • Telnet服务的配置步骤

    2010-05-12 13:31:41

    一、安装telnet软件包(通常要两个)。
      
      1、 telnet-client (或 telnet),这个软件包提供的是 telnet 客户端程序;
      2、是 telnet-server 软件包,这个才是真正的 Telnet server 软件包!
      安装之前先检测是否这些软件包已安装,方法如下:
      [root@wljs root]#rpm –q telnet
      [root@wljs root]#rpm –q telnet-client
      [root@wljs root]#rpm –q telnet-server
      如果没有检测到软件包,需要进行安装,red hat linux 9默认已安装了client软件包,一般只要安装telnet-server软件包即可:
      1、到我的ftp上下载软件包,方法如下:
      在虚拟控制台下依次输入:
      [root@wljs root]#ftp 210.45.160.27
      Name:ftp
      Password:ftp
      ftp>cd linux
      ftp>ls
      ftp>get telnet-0.17-25.i386.rpm
      ftp>get telnet-server-0.17-25.i386.rpm
      ftp>bye
      2、安装软件包
      #rpm –i telnet-0.17-25.i386.rpm
      #rpm –i telnet-server-0.17-25.i386.rpm
      
      二、启动telnet服务
      
      1、开启服务
      方法一:使用ntsysv,在出现的窗口之中,将 telnet 勾选起来,然后按下 OK 即可 !
      方法二:编辑 /etc/xinetd.d/telnet
      #vi /etc/xinetd.d/telnet
      [root@test root]# vi /etc/xinetd.d/telnet
      找到 disable = yes<==就是改这里,将 yes 改成 no 即可!服务预设是关闭的
      2、激活服务
      telnet 是挂在 xinetd 底下的,所以自然只要重新激活 xinetd 就能够将 xinetd 里头的设定重新读进来,所以刚刚设定的 telnet 自然也就可以被激活。
      [root@wljs root]# service xinetd restart
      
      三、测试服务
      
      [root@wljs root]#telnet ip(或者hostname)
      如果配置正确,系统提示输入远程机器的用户名和密码
      Login:
      Password:
      注:默认只允许普通用户
      
      四、设置telnet端口
      
      #vi /etc/services
      进入编辑模式后查找telnet(???怎样查找)
      会找到如下内容:
      telnet 23/tcp
      telnet 23/udp
      将23修改成未使用的端口号(如:2000),退出vi,重启telnet服务,telnet默认端口号就被修改了。
      
      五、Telnet服务限制
      
      如果原本的默认值你并不满意,那么你可以修改成比较安全一点的机制。假设你这个 Linux 是一部主机,而且他有两块网络接口,分别是对外的 192.168.0.1 与对内的210.45.160.17 这两个,如果你想要让对内的接口限制较松,而对外的限制较严格,你可以这样的来设定:
      #vi /etc/xinetd.d/telnet
      # 先针对对内的较为松散的限制来设定:
      service telnet
      { disable    = no         <==预设就是激活 telnet 服务
      bind       = 210.45.160.17    <==只允许经由这个适配卡的封包进来
      only_from    = 210.45.160.0/24   <==只允许 210.45.160.0/24 这个网段的主机联机进来使用 telnet 的服务
      .....
      }
      # 再针对外部的联机来进行限制
      service telnet
      
      {
      disable     = no<==预设就是激活 telnet 服务
      bind       = 192.168.0.1<==只允许经由这个适配卡的封包进来
      only_from    = 192.168.0.0/16<==只允许 192.168.0.0 ~ 192.168.255.255 这个网段联机进来使用 telnet 的服务
      only_from    = .edu.cn<==重复设定,只有教育网才能联机!
      no_access    = 192.168.25.{10,26}<==不许这些 PC 登入
      access_times  = 1:00-9:00 20:00-23:59 <==每天只有这两个时段开放服务
      ......
      }
      
      六、Telnet root用户的登入
      
      root 不能直接以 telnet 连接上主机。 telnet 不是很安全,默认的情况之下就是无法允许 root 以 telnet 登入 Linux 主机的 。若要允许root用户登入,可用下列方法
      [root @test /root]# vi /etc/pam.d/login
      #auth required pam_securetty.so #将这一行加上注释!
      
      或
      # mv /etc/securetty /etc/securetty.bak
      这样一来, root 将可以直接进入 Linux 主机。不过,建议不要这样做。还可以在普通用户进入后,切换到root用户,拥有root的权限!
      
      
    [NextPage]     安全的ssh
      
      SSH是一个用来替代TELNET、Rlogin以及Rsh的传统的远程登陆程序的工具,主要是想解决口令在网上明文传输的问题。为了系统安全和用户 自身的权益,推广SSH是必要的。SSH有两个不兼容的版本1.x,2.x!RedHat Linux 9将默认的远程管理服务设置成OpenSSH(一个ssh的替代产品)。不需要重新安装软件包!
      
      一、配置openssh服务器
      
      1、ssh的配置文件是/etc/ssh/ssh_config,一般不要修改!
      2、启动服务器!
      #ntsysv =>确认将sshd前面的勾已打上!
      3、手工启动OpenSSH:
      #service sshd start
      #service sshd restart(重新启动)
      4、停止服务器:
      #service sshd stop
      
      二、使用OpenSSH客户端
      
      Redhat linux 9默认已安装了OpenSSH的客户端,客户端和服务器连接时,可以使用两种验证方式:基于口令的验证方式和基于密匙的验证方式!
      1、基于口令的验证方式
      这种验证方式要求用户输入用户名称和密码!若没有指定用户名称和密码,则默认使用当前在客户机上的用户名!
      
      例1:直接登陆
      [root@wljs /]#ssh 210.45.160.17
      则登陆用户名为客户机当前用户名!
      例2:指定用户名登陆
      [root@wljs /]#ssh wwz@210.45.160.17
      或: [root@wljs /]#ssh –l wwz 210.45.160.17
      上面过程结束后,系统将会提示你输入用户名和密码!
      
      2、基于密匙的验证方式
      使用密匙的验证方式,用户先需要为自己创建一对密匙:公匙和私匙。(公匙用在要登陆的服务器上)
      OpenSSH公开密匙的密码体制有RSA、DSA!
      创建密匙:
      例:[root@wljs /]#ssh-keygen –t rsa
      回车后,要求输入使用密匙时的口令!这样便生成了公匙和私匙:放在用户主目录下的.ssh目录下,文件名:id_rsa.pub和id_rsa!必须将公匙复制到登陆的服务器的~/.ssh/目录下,并改名为:authorized_keys!然后,便可使用密匙方式登陆!
      #ssh [–l username] ip地址或主机名
      
      三、OpenSSH上常用的命令
      
      1、不登陆远程系统使用命令
      #ssh 210.45.160.17 [命令] [参数]
      2、本地系统和远程系统间文件的传输
      #scp a.txt root@210.45.160.17:/b.txt
      #scp root@210.45.160.17:/b.txt /c.txt
      3、sftp命令
      Sftp 命令和ftp命令类似,它是OpenSSH提供的网络传输文件的小工具,它更加安全,使用和ftp相似的命令:主要有如下几个:
      1、登陆
      #ftp 210.45.160.17
      2、ftp 会话的打开与关闭
      打开:open 210.45.160.27
      关闭:close
      3、文件的传输
      从ftp服务器上得到文件:
      Get a.txt
      向ftp上放文件
      Put a.txt
      4、退出ftp
      Bye
      5、其他
      bell:每个命令执行完毕后计算机响铃一次
      Cd ,ls 等一些常见命令也可以在ftp服务器目录中使用!
  • 如何使用NMON在Linux下

    2008-12-05 16:19:59

      本人用的RH9.0系统,现在已经有nmon工具
    一 :安装如下:
        unzip nmon_x86_11f.zip
        chmod 777 nmon_x86_rhel2
    二:如何使用
       命令
        ./nmon_x86_rhel2 -f -s 30 -c 120 >>Linux_$date_ip.nmon
       说明下:-f 输出文件;-s 时间间隔 ;-c 取的次数>>写到指定的文档中
    三:分析文件
       sftp
       put Linux_$date_ip.nmon 到本地
    四:用nmon分析工具
       分析数据
       nmon_analysers来分析数据
       
     
       
  • shell 读取配置文件

    2008-08-24 10:52:47

    shell 读取配置文件来取参数的值. 在许许多多自动化的脚本中,很学用.
    #!/bin/sh
     filepath="/home/test/test.txt"
    while read LINE
        do
         user=`echo $LINE | awk '{print $1}'`
         pwd=`echo $LINE | awk '{print $2}'`
      done <$filepath
     
  • linux 监控日志输出

    2008-05-26 10:54:06

    1.为了更好的记下Linux 的性能情况可以将日志文件输出出来
      top > top.log
      vmstat 5 10 > vmstat.log
      iostat 1 10 > iostat.log
    2.定期运行程序或者脚本是管理员要面临一个很普遍的问题,我刚搞Linux,稍微总结一下。(以下操作基于Redhat9)

    一、 使用crond监控程序运行程序

    1. 使用cron来定期执行任务
    使用crond (cron监控程序)来定期运行一些任务,比如备份日志、数据库、把日志发送到自己邮箱等等操作都可以又定期运行程序来完成。
    crond是个脚本,每次Linux启动的时候都自动起到该脚本,该脚本是 /etc/rc.d/init.d 下面的,每次系统启动的时候就自动会启动该目录下

    的脚本。
    cron有两个配置文件,一个/etc/crontab,是一个全局配置文件,一组是crontab命令生成生成的配置文件,是属于用户级的。

    一般对管理员来说,只要使用全局配置的/etc/crontab就配置文件就可以了,我们去打开配置文件看看:

    SHELL=/bin/bash
    PATH=/sbin:/bin:/usr/sbin:/usr/bin
    MAILTO=root
    HOME=/

    # run-parts
    01 * * * * root run-parts /etc/cron.hourly
    02 4 * * * root run-parts /etc/cron.daily
    22 4 * * 0 root run-parts /etc/cron.weekly
    42 4 1 * * root run-parts /etc/cron.monthly

    我们稍微来分析一下这个文件:

    /* 设置基于什么shell来运行,我们这里是基于bash shell */
    SHELL=/bin/bash

    /* 指定目录中有次文件的命令时,不需要完整目录路经 */
    PATH=/sbin:/bin:/usr/sbin:/usr/bin

    /* 使用cron实际工作时,见通过邮件来同志root用户 */
    MAILTO=root

    /* 与/etc/crontab配置文件相关的主目录为根目录 */
    HOME=/

    /* 好了,这里是关键是,下面的是要指定什么时间运行什么目录下的任务,run-parts命令是运行指定目录下的每个脚本 */
    # run-parts

    /* 这一句是在每天每小时过后一分钟运行/etc/cron.hourly目录中的每个脚本文件 */
    01 * * * * root run-parts /etc/cron.hourly

    /* 在每天凌晨4点2分运行/etc/cron.daily目录中的每个脚本文件 */
    02 4 * * * root run-parts /etc/cron.daily

    /* 在每个星期天凌晨4点22分运行/etc/cron.weekly目录中的每个脚本文件 */
    22 4 * * 0 root run-parts /etc/cron.weekly

    /* 在每个月的第一天凌晨4点42分运行/etc/cron.monthly目录中的每个脚本文件 */
    42 4 1 * * root run-parts /etc/cron.monthly

    大家看到里面的“*”一定觉得很奇怪,下面我们句稍微来了解一下cron的语法:
    上面脚本中的时间是从左到右的,分别列出了五个字段,我们看下面的表:

    ------------------------------------------------
    字段            取值范围
    ------------------------------------------------
    Minute          0 ~ 59
    Hour            0 ~ 23,其中0是午夜,20是晚上8点
    Day             1 ~ 31
    Month           1 ~ 12
    Day of week     0 ~ 7,其中0和7是表示星期天
    ------------------------------------------------

    任何字段中的星号是通配符,例如,如果第一个字段包括星号,则特定若无其事在可能的每一分钟运行。如果要指定时间范围,比如上午8点到

    下午4点,则可以见第二个字段设置为8~16。如果要隔一天运行任务,则可以将第三个字段设置为*/2。可以看出,如果五个字段(minute、hour

    、day、month、day of week) 之后,cron中的每个字段就没什么神秘之处了。


    2. 用户自己的cron
    用户也可以计划用户自己的cron任务,比如他想要在半夜整理他的文件,然后发送邮件给自己,只要这个用户他没有在/etc/cron.deny表中,

    就可以使用crontab -e命令来启动自己的cron文件。

    3. 对cron的访问控制
    默认情况下,所有用户都能访问cron工具,要对cron进行访问控制,则可以生成/etc/cron.allow与/etc/cron.deny文件。
    (1)这两个文件都不存在时,每个用户都可以访问cron工具]
    (2)存在/etc/cron.allow文件时,则只有cron.allow文件中允许的用户才能访问cron工具,如果也有/etc/cron.deny文件,则忽略cron.deny文

Open Toolbar