提取知识点 blt (signal ,Terminal shell 正则表达式)

1023


知识管理:网博士,有道笔记


学习方法:
枪挑一条线,滚扫一大片:
程序员分两类:一种是学过C语言的,一种是没有学过C语言的
读书由薄到厚,再由厚到薄
行业经典(Jolt), cheatsheet refcard
网络是最好的老师
八格亚路(baidu,google,yahoo,bing...)
blog,weibo,twitter,facebook
公开课
理论与实践:理论上理论都是正确的,实际上并不是
写代码,读代码
sourceforge,google code, github...


图书:
豆瓣:http://www.douban.com          rocflytosky
    http://book.douban.com/doulist/1345225/




1 分析实用程序
/bin, /usr/bin, /usr/local/bin
学习使用工具,分析工具,了解功能和原理
2 学习系统调用
函数和系统调用本质上都是函数。不同的库,不同的头文件
分析需要哪些系统调用,学习系统调用的使用方法:参数?返回值?
3 编程实现
利用上面的原理和一组协同工作的系统调用,自己编程实现使用程序的功能
或积极主动抄代码,学习那些系统调用是协同工作的

C语言的学习可以参考这个思路,实现标准库
伴随我们学习经常要问的三个问题:
能做什么?
如何实现?
自己如何编写?


  利用Linux学习Linux编程:
搜索ManPages
man -k
man -k XXX | grep -i YYY
阅读头文件
参阅see also


man who
man -k utmp
man 5 utmp
utmp.h
   grep -i XXX -nr /usr/include


链接控制:stty
文件 :磁盘文件和设备的抽象


stty:显示,设置终端属性
设备和文件
文件:数据,属性,目录中的名字
设备:文件名,i-node,文件所有者,权限,修改时间


设备:
ls -C /dev | head 
设备和系统调用
int fd;
fd = open("/dev/tape", O_RDONLY);
lseek(fd, (long)4096, SEEK_SET);
n = read(fd, buf, buflen);
close(fd);


终端设备就像文件
终端:键盘和显示单元。功能接收用户输入,并将输出信息显示给用户。
广义:串口,打印机,调制解调器,telnet窗口,ssh窗口等


tty(1)

cp /etc/motd /dev/pts/2


who > /dev/pts/2


ls -li /dev/pts/2


设备文件的属性
设备文件和文件大小
主设备号和从设备号
设备文件和权限
读获取数据
写发送数据

write(1)
实现:文件名是设备名




设备文件和i-node
目录不能区分磁盘文件和设备文件
磁盘文件和设备文件的区分在i-node
设备文件的i-node包含指向内核子程序表的指针,主设备号指向设备驱动程序


设备与文件的不同
文件:内核缓冲
设备属性:波特率,奇偶校验位,暂停位等
链接属性和控制
有哪些属性?
如何检测?
如何设置?


磁盘链接的属性
属性修改模式
获取设置
修改设置
存储设置
#include


int s;


s = fcntl(fd, F_GETFL);


s |= O_SYNC;


result = fcntl(fd, F_SETFL, s)
if( result == 1)
perror("setting SYNC");



属性1:缓冲
属性2:自动添加模式
wtmp


fcntrl 添加O_APPEND


write(fd, buf, size) 使得lseek和write成为一个原子操作


popen pwrite


open控制文件描述符号
fd = open (WTMP_FILE, O_WRONLY | O_APPEND | O_SYNC);


O_CREAT
O_TRUNC
O_EXEL


O_CREAT | O_EXEL:多进程同时创建文件

终端连接的属性
终端I/O: getchar/putchar


#inlcude


int main()
{
int c, n=0;


while( (c=getchar()) != 'q')
printf("char %3d is %c cod %d \n", n++, c , c);
}


./listchars
hello










在用户输入回车后才接收数据(行缓冲)
Return(ascii 13) 看作换行符(ascii 10)
进程发换行符,终端接受回车换行符



终端驱动程序
处理进程和外部设备间数据流的内核子程序的集合称为终端驱动程序或者tty驱动程序


与终端驱动交互:stty

stty 能干什么?
stty -a
如何实现stty ?
tty驱动:man stty
输入
输出
本地
控制
本地


编写终端驱动
man -k terminal | grep -i attribute

tcgetattr(3)/tcsetattr(3)
struct termios


                几个例子
显示echo状态
改变echo状态




自己编写stty:


其他:
ioctl
示例:获取终端屏幕大小

文件,设备和流


用户程序设计:终端控制和信号
实用工具:自动打开3个文件描述符(0标准输入,1标准输出,2标准错误),从标准输入读入字节,进行处理,结果字节流写到标准输出,错误信息发送到标准错误。
输入输出可以被重定向
sort > output
sort x > /dev/lp
who | tr '[a-z]''[A-Z]'
特定设备程序:为特定应用控制设备
用户程序:设备相关程序
vi, emacs, pine, more, lynx, hangman, robots, bsdgames

特点:
立即响应击键事件,不用回车
有限的输入集
输入的超时
屏蔽^+C

终端驱动程序的模式
rotate.c

stty -icanon;./rotate
stty icanno


stty -icanon -echo;./rotate
stty icanon echo
终端模式
规范模式:cooked模式
缓冲,回显,编辑,控制由驱动程序完成


非规范模式
关闭缓冲和编辑功能


raw 模式
每步处理都被一个独立的位控制


用户程序
play_again.c
问题:icanon  
需要回车
有缓冲




play_again1.c
tcgetattr(0, &ttystate);
ttystate.c_lflag &= ~ICANON;
ttystate.c_cc[VMIN] = 1;
tcsetattr(0, TCSANOW, &ttystate);


问题
非法提示太多


play_again2.c
tcgetattr(0, &ttystate);
ttystate.c_lflag &= ~ICANON;
ttystate.c_lflag &= ~ECHO;
ttystate.c_cc[VMIN] = 1;
tcsetattr(0, TCSANOW, &ttystate);


问题
超时无显示



play_again3.c
问题
^+C结束整个程序




信号
^+C能做什么?
信号是什么?异步消息,软中断


kill -l
man 7 signal
signal.h


产生信号:
用户:^+C, ^+D ^+\  (stty -a)
内核
进程:kill raise
信号处理
接受默认处理
忽略信号
信号处理程序
signal(2)
函数指针
typedef void (*SigFunc)(int);
SigFunc signal(int, SigFunc);

SIG_ERR
SIG_DFL
SIG_IGN
grep XXX -nr /usr/include

sigdemo1.c:捕捉信号
sigdemo2.c:忽略^+C, ^+\退出

SIGKILL SIGSTOP不能忽略
play_again4.c


10.25
事件驱动编程-视频游戏
视频游戏和操作系统
UNIX和星际旅行:Dennise Ritchie 和 Ken Thompson

视频游戏做什么

视频游戏怎么做
空间
时间
中断
并发
操作系统
内核如何管理进程?

屏幕管理,时间,信号,共享资源


单人桌球游戏

curses库

sudo apt-get install libncurses5-dev


#include


gcc xx.c -o xx -l ncurses

基本curses函数
initscr():初始化curses库和tty
endwin():关闭curses并重置tty
refresh():使屏幕按意图显示
mov(r,c):光标移动到(r,c)
addstr(s):在当前位置绘制字符串
addch(c):在当前位置绘制字符
clear():清屏
standout:启动standout模式,一般使得屏幕反色
standend:关闭standout模式


curses的常量
int  LINES; // 当前终端的行数 
int  COLS; // 当前终端的列数 
int  TABSIZE // 制表符长度 

代码模式:
fopen fread/fwrite fclose
open read/write close
opendir readdir closedir
initscr addstr  endwin


代码最常出现的问题是变量没有被初始化,特别是指针
代码结束不释放资源导致内存泄漏
open/close 模式值得总结学习,对应面向对象程序设计语言里面的构造函数,析构函数


示例:
hello1.c:基本操作
hello2.c:与循环变量和其他函数配合,进行复杂显示。
理解refresh:虚拟屏幕与实际屏幕
对比标准I/O中的流与文件


hello3.c:时钟编程
sleep(3)
hello4.c:动画
hello5.c:弹回

问题:
延时1s,时间太长
移动的同时如何处理用户输入?


时钟编程1:Alarms
alarm(2) 
pause(2):挂起一个进程,直到某个信号被处理


如何实现sleep?
为SIGALARM设置一个处理函数
调用alarm
调用pause

编程实现一个4s sleep:sleep1.c

计时器可以用来调度:
调用alarm设置计时器,然后做其他事情
计时器到零,发送信号,处理函数被调用

时钟编程2:间隔计时器
sleep和alarm提供的时间精度不够:秒


高精度计时:间隔计时器
usleep(3), 微妙做单位


进程的三种计时系统:time


ITIMER_REAL:进程实际时间计时,运行完发送SIGALARM消息
ITIMER_VIRTUAL:用户态,SIGVTALR
ITIMER_PROF:用户态,用户态到核心态陷入 SIGPROF
TIMER_REAL


高精度定时示例:ticker_demo.c
getitimer
setitimer


struct itimerval {
struct timeval it_interval; /* next value */
   struct timeval it_value;    /* current value */
};


struct timeval {
    long tv_sec;                /* seconds */
  long tv_usec;               /* microseconds */
            };


信号处理1:signal
signal(SIGALARM, SIG_DFL)
signal(SIGALARM, SIG_IGN)
signal(SIGALARM, handler)
老鼠夹问题:信号被捕获,信号处理函数就失效了,再次设置就有可能丢失信号,信号的不可靠性
sinal(SIGINT , inthandler);
            void inthandler(int signum){
signal(SIGINT, inthandler);
}


 
不知道信号被发送的原因
处理函数无法阻塞其他信号


如何处理多信号:


生活中的示例

进程的多信号处理:sigdemo3.c
处理函数每次使用完都会被禁用吗?
如果SigY在进程处理SigX时到达,会发生什么?
如果进程处理SigX时又有SigX到达,会发生什么?
如果信号到达时,进程被getchar,read之类输入阻塞,会发生什么?




^C^C^C^C
^\^C^\^C
hello^C CR
hello CR^C
^\^\hello^C


处理函数每次使用完都会被禁用吗?
Linux上不会禁止,不存在老鼠夹问题
如果两次^C杀死进程,说明不可靠
如果SigY在进程处理SigX时到达,会发生什么?
先处理Y再处理X
如果进程处理SigX时又有SigX到达,会发生什么?
递归调用同一个信号处理函数
忽略后者:Linux
阻塞第二个
如果信号到达时,进程被getchar,read之类输入阻塞,会发生什么?


信号处理2:sigaction(2)
  struct sigaction {
      void     (*sa_handler)(int);
  void     (*sa_sigaction)(int, siginfo_t *, void *);
  sigset_t   sa_mask;
  int        sa_flags;
  void     (*sa_restorer)(void);
      };
           
  在一些情况下,一个操作不应该被其他操作打断


  sa_mask:阻塞其他信号
  sigprocmask(2)
构造信号集合
sigemptyset(3)
sigfillset(3)
sigaddset(3)
sigdelset(3)
   sigismember(3)
  sa_flags
   小练习:暂时阻塞SIGINT SIGQUIT
 注意退出要恢复原来的系统状态






 sigset_t sigs, presigs;
 sigemptyset( &sigs );
 sigaddset( &sigs, SIGINT );
 sigaddset( &sigs, SIGQUIT );
 sigprocmask( SIG_BLOCK, &sigs, &presigs );
 //...
 sigprocmask( SIT_SET, *presigs, NULL );
 
 
 
 sigactiondemo.c


阻塞信号和忽略信号的区别:
忽略信号:信号还会被传递,只是不处理
阻塞信号:解除阻塞前,信号不传递








可重入代码:一个信号处理或者一个函数,如果在激活状态下能被调用而不引起任何问题
sa_flags:SA_NODEFER 允许处理函数的递归调用,清除可以阻塞信号
处理程序不可重入,必须阻塞信号
阻塞信号就会丢失信号
丢失重要信号怎么办?


        临界区:

进程发送信号:kill(1) kill(2)
SIGUSR1, SIGUSR2



视频游戏:
一条线上控制动画:bounce1d.c
空格反向
f加速
s减速


问题:用O代替hello
控制上下移动


两维动画:
不变的是
计时器驱动
等待键盘输入
状态变量


变化的是
如何让球斜着移动?
两个计时器

异步I/O
使用O_ASYNC: bounce_async.c
使用aio_read:bounce_aio.c


自己编写




GDB-SegFaut
工具
gdb -tui (^+X+A) 
cgdb 
ddd 
IDE-Eclipse
调试方法-三窗口法
VI:编辑源代码,之后w保存,修改完毕才wq退出
GCC:编译,运行测试用例,有问题则调试
GDB: 调试,但是重新编译程序不必退出GDB,这样不需要重新输入命令行参数,保留了原来设置的断点,省心,提高效率
调试原则
确认原则
逐个确认你自认为正确的事情对应的代码确实是正确的
从简单工作开始
错误往往发生在边界
等价划分测试用例
使用自顶向下法
单步调试优先使用next,出现错误再使用step
使用工具确定段错误的位置
   ulimit -c               check
ulimit -c n (KB)        set
backspace
frame n
up
down
corefile
通过中断信号确定死循环
^+c  continue
使用二分法提高确认效率


示例1, 插入排序,基本调试技巧:
ins.c
用例: 12 5
12 5 19 22 6 1


示例2,段错误的定位
string.c
Init_CString:
Delete_CString:
Chomp:删除并返回最后一个字符
Append_Chars_To_String:


gcc -g string.c
ulimit -c unlimited
./string
gdb string core





1026 
多线程


同一时刻完成多项任务
程序:函数
进程:线程


函数执行路线:
    单线程
hello_single.c
多线程
hello_multi.c


gcc .. -lpthread

pthread_create
pthread_join
pthread_exit


线程的种种退出:
return:pthread_join 中value_ptr指向线程函数的返回值
被pthread_cancel异常终止:value_ptr指向的位置存放PTHREAD_CANCELED(-1)
        调用pthread_exit,value_ptr指向的位置存放的是传给pthread_exit的参数


线程分工合作:
多线程wc:非字母或者非数字的字符跟在字母和数字后就算一个单词
两个线程,一个计数器:twordcount1.c
互斥锁:              twordcount2.c
互斥锁会影响程序效率,让程序变慢
两个线程,两个计算器,传递多参数:twordcount3.c
结构体传递多参数


总结:并发问题


1028
 线程与进程
线程共享:
数据空间
pid
文件描述符
信号处理方式
当前工作目录
用户ID,组ID
线程独享:
线程ID
上下文

errno
sa_mask
调度优先级

   共享数据空间:
    malloc free:返回静态局部变量的指针的函数会导致内存泄漏
共享fd
一个线程关闭,一个线程使用?
fork exec exit signals
fork:只有调用fork的线程出现在新进程
exec:新进程取代当前进程,所有执行中的线程都会消失
exit:退出进程,会导致内存异常,系统错误,线程崩溃
signals:


fork      pthread_create
exit      pthread_exit
waitpid   pthread_join
atexit    pthread_cleanup_push
getpid    pthread_self
abort     pthread_cancel


 并发:多线程?多进程?
容易设计,编码,调试
运行效率高
兼容性


生产者消费者问题
读者写者问题
哲学家问题




 线程通信:
  线程中没有父子概念,没有类wait机制,可以让A等待B,B结束后通知A
    邮箱机制与条件变量:
容器,旗帜,锁
pthread_cond_t flag
struct arg_set *msg
pthread_mutex_t lock


pthread_cond_wait等待旗帜升起,将原线程挂起
pthread_cond_signal 升旗


生产者消费者问题

     信号量(semaphore)
表示可用的资源数量,与mutex不同,可以表示多个资源,实现多资源的同步
man 7 sem_overview


sem_init
sem_wait:获得资源,使得semphore-1,如果semphore值为0,则挂起等待,如果不希望挂起,调用sem_trywait
sem_trywait
sem_post:释放资源,使得semphore+1,同时唤起等待的线程
sem_destroy


    多线程在Web服务器中的应用


线程和动画
定时器可以实现动画,通过SIGALRM
线程优点:
线程机制可以更好的匹配内部和外部结构,
 在外部,用户可以看到两个独立的活动:动画和键盘控制
 在内部:线程可以把动画和键盘输入代码分开,线程通过共享变量定义位置,动画速度
画面的移动需要隐藏的计时器完成
现代线程允许在多处理器并行处理
动画轨道,渲染,纹理,旋转等复杂计算可以通过并行提高速度


    基于多线程机制的多重动画
tanimate.c
互斥量:
初始化,控制移动消息,读取和处理用户输入的循环

  方向变量,屏幕冲突

1029




gdb-调试
GUI
tty /dev/pts/4  //开启执行终端,gdb 在不同终端执行程序,键盘输入和屏幕输出将位于执行终端
执行窗口输入:sleep 100000;//执行窗口的输入是控制程序而不是进入 shell
   完成调试输入^+C, 结束sleep
程序输入错误退出:
^+j reset ^+j


Threads
info threads
thread 3
break 88 thread 3
break 88 thread 3 if x==y


1029
 小项目:
多线程拷贝的实现
       mmap
  stat


Shell编程
应用示例---监视系统用户程序

伪代码:
获取现在的用户列表1
不停的做下面的事情
等待一会
获取现在的用户列表2
比较两个用户列表
如何列表1有,列表2没有
退出登录用户
如果列表1没有,列表2有
新登录用户

用列表2替换列表1的内容

shell:
who | sort > prev
while true; do
sleep 60
who | sort > curr
echo “logged out:"
comm -23 prev curr
echo "logged in:"
comm -13 prev curr
mv curr prev
done


Unix/Linux的脚本思维方式
通过进程组合完成复杂功能,而不是通过函数调用组成大应用程序


对比:计算机指令
对比函数调用:y = f1(f2(x));   x > f2 | f1 > y


shell脚本
脚本简单易用
工具灵活:每个工具完成一个特定,通用的功能(对比函数库,类库)
I/O重定向,管道的使用和作用



Shell是一种具备特殊功能的程序,提供了用户与内核进行交互操作的一种接口(系统调用,shell)
/ect/shells
default: /etc/passwd


三种登录Shell的方法
X Window
SSH Secure Shell
PuTTY:http://www.chiark.greenend.org.uk/~sgtatham/putty/


编译型语言
编写-编译-链接-运行(edit-compile-link-run)
C\C++、Ada、Java、C#...


脚本语言
解释器(interpreter)读入脚本程序代码,将其转换成内部的形式执行
解释器本身则是编译型程序
Python, Ruby, Javascript...


Shell脚本编程的优势
编译:语言效率
脚本:程序员效率


Shell脚本的执行方式
交互式命令行
which whereis
type -t 
man bash-builtins
cd alias umask exit
help cd
内建命令(! : . alias bg bind break builtin case cd command continue declare dirs disown do done echo elif else enable ecac eval exec exit export fc fg fi for funtion getops hash help history if in jobs kill let local logout popd pushd pwd read readonly return select set shift suspend test then time times trap type typeset ulimit umask unalias unset until wait while)
cd..;ls
子shell (cd..; ls)




脚本文件
#! /bin/sh-
cd .. 
ls

编写脚本的一般模式:
命令行下测试正确
编写脚本
chmod +x



用户和用户组管理
用户管理常用命令
用户账号添加命令useradd 或adduser
修改用户命令usermod
删除用户命令userdel
用户口令管理命令passwd
用户组管理常用命令
groupadd groupmod groupdel`

文件和目录操作
文件操作常用命令

目录操作常用命令


文件和目录权限管理常用命令
chmod chown

查找文件命令——find
find [路径] [选项] [操作]
路径是find命令所查找的目录路径,例如用.来表示当前目录,用/来表示系统根目录
选项用于指定查找条件,如:可以指定按照文件属主、更改时间、文件类型等条件来查找


-name


按照文件名查找文件。


-perm
按照文件权限来查找文件。


-prune
使用这一选项可以使find命令不在当前指定的目录中查找,如果同时使用-depth选项,那么-prune将被find命令忽略。


-user
按照文件属主来查找文件。


-group
按照文件所属的组来查找文件。


-mtime -n +n
按照文件的更改时间来查找文件, - n表示文件更改时间距现在n天以内,+ n表示文件更改时间距现在n天以前。find命令还有-atime和-ctime 选项,但它们都和-m time选项。


-nogroup
查找无有效所属组的文件,即该文件所属的组在/etc/groups中不存在。


-nouser
查找无有效属主的文件,即该文件的属主在/etc/passwd中不存在。
-newer file1 ! file2


查找更改时间比文件file1新但比文件file2旧的文件。
-type


查找某一类型的文件,诸如:


b - 块设备文件。
d - 目录。
c - 字符设备文件。
p - 管道文件。
l - 符号链接文件。
f - 普通文件。


-size n:[c] 查找文件长度为n块的文件,带有c时表示文件长度以字节计。
-depth:在查找文件时,首先查找当前目录中的文件,然后再在其子目录中查找。
-fstype:查找位于某一类型文件系统中的文件,这些文件系统类型通常可以在配置文件/etc/fstab中找到,该配置文件中包含了本系统中有关文件系统的信息。


-mount:在查找文件时不跨越文件系统mount点。
-follow:如果find命令遇到符号链接文件,就跟踪至链接所指向的文件。
-cpio:对匹配的文件使用cpio命令,将这些文件备份到磁带设备中。


另外,下面三个的区别:
  -amin n
    查找系统中最后N分钟访问的文件


    -atime n
    查找系统中最后n*24小时访问的文件


    -cmin n
    查找系统中最后N分钟被改变文件状态的文件


    -ctime n
    查找系统中最后n*24小时被改变文件状态的文件


      -mmin n
   查找系统中最后N分钟被改变文件数据的文件


   -mtime n
   查找系统中最后n*24小时被改变文件数据的文件
操作用于指定结果的输出方式:
print,exec,ok


find . -name 't*' -perm 744 -print
find . -mtime -90 -print
find /etc  -type f -name "rc*" -exec ls -l {} \;
find . -name "*.conf"  -mtime +5 -ok rm {} \;


查找当前用户主目录下的所有文件:


下面两种方法都可以使用


$ find $HOME -print
$ find ~ -print




当前目录中文件属主具有读、写权限,并且文件所属组的用户和其他用户具有读权限的文件;


$ find . -type f -perm 644 -exec ls -l {} \;




查找系统中所有文件长度为0的普通文件,并列出它们的完整路径;


$ find / -type f -size 0 -exec ls -l  {} \;




查找/var/logs目录中更改时间在7日以前的普通文件,并在删除之前询问它们;


$ find /var/logs -type f -mtime +7 -ok rm {  } \;




查找系统中所有属于root组的文件;


$find . -group root -exec ls -l {  } \;
-rw-r--r--    1 root     root          595 10月 31 01:09 ./fie1




将删除当目录中访问时间在7日以来、含有数字后缀的admin.log文件。
$ find . -name "admin.log[0-9][0-9][0-9]" -atime -7  -ok
rm {  } \;
< rm ... ./admin.log001 > ? n
< rm ... ./admin.log002 > ? n
< rm ... ./admin.log042 > ? n
< rm ... ./admin.log942 > ? n




查找当前文件系统中的所有目录并排序;
$ find . -type d | sort




文件处理
    sort命令
-t选项可用于设置分隔符
sort -t: CARGO.db
-k选项用于指定排序的域,sort默认按第1域进行排序
sort -t: -k3 CARGO.db
-n选项用于指定按数值大小进行排序
sort -t: -k3n CARGO.db
-r选项用于将排序结果逆向显示
sort -t: -k3nr CARGO.db
-u选项用于去除排序结果中的重复行
sort -t: -u CARGO.db
-o选项用于指定结果文件的名字
sort -t: -k3n -o SORT.txt CARGO.db
-c选项用于测试文件是否已经排好序
sort -t: -c CARGO.db
sort -t: -c SORT.txt
sort -t: -k3n -c SORT.txt
-m选项用于将两个排好序的文件合并成一个排好序的文件,在文件合并前,它们必须已经排好序,
-m选项对未排序的文件合并是没有任何意义
sort -t: -m CARGO2.db SORT.txt
uniq命令
sort -u
sort -u命令时,所有重复记录都被去掉
uniq命令去除的重复行必须是连续重复出现的行,中间不能夹杂任何其他文本行
-c:每行的重复次数
count_word.sh
-u:显示有重复的记录
-d:显示无重复的


uniq CARGO3.db
sort -u CARGO3.db


join命令:用于实现两个文件中记录的连接操作
       连接操作将两个文件中具有相同域的记录选择出来,再将这些记录所有的域放到一行
                 -a1或-a2
除了显示以共同域进行连接的结果外,-a1表示还显示第1个文件中没有共同域的记录,-a2则表示显示第2个文件中没有共同域的记录
-i
比较域内容时,忽略大小写差异
-o
设置结果显示的格式
-t
改变域分隔符
-v1或-v2
跟-a选项类似,但是,不显示以共同域进行连接的结果
-1和-2
-1用于设置文件1用于连接的域,-2用于设置文件2用于连接的域




当两个文件进行连接时,文件1中的记录可能在文件2中找不到共同域,反过来,文件2中也可能存在这样的记录,join命令的结果默认是不显示这些未进行连接的记录的
-a和-v选项就是用于显示这些未进行连接的记录,-a1和-v1指显示文件1中的未连接记录,而-a2和-v2指显示文件2中的未连接记录
-a和-v选项的区别在于:-a选项显示以共同域进行连接的结果,而-v选项则不显示这些记录


cat TEACHER.db
cat TEACHER_HOBBY.db
join -t: TEACHER.db TEACHER_HOBBY.db
join -t: -a1 TEACHER.db TEACHER_HOBBY.db
join -t: -a2 TEACHER.db TEACHER_HOBBY.db
join -t: -v1 TEACHER.db TEACHER_HOBBY.db
join -t: -v2 TEACHER.db TEACHER_HOBBY.db
join -t: -o1.1 2.2 1.2  TEACHER.db TEACHER_HOBBY.db

cat AREACODE.db
sort -t: -k3 -o TEACHER1.db TEACHER.db
join -t: -i -1 3 -2 1 TEACHER1.db AREACODE.db




cut命令:从标准输入或文本文件中按域或行提取文本
  -c:n n,m n-m
  指定提取的字符数,或字符范围
  -f
  指定提取的域数,或域范围
  -d
  改变域分隔符




cut -c3 TEACHER.db
cut -c1-5 TEACHER.db

cut -d: -f1,4 TEACHER.db
cut -d: -f1-3 TEACHER.db


paste命令:将文本文件或标准输出中的内容粘贴到新的文件,它可以将来自于不同文件的数据粘贴到一起,形成新的文件
-d
默认域分隔符是空格或Tab键,设置新的域分隔符
-s
将每个文件粘贴成一行
-
从标准输入中读取数据


cat FILE1
cat FILE2
paste FILE1 FILE2
paste -d: FILE1 FILE2
paste -d@ FILE1 FILE2
paste -d: -s  FILE1 FILE2

ls | paste -d" " - - - - - - 




split命令:split命令用于将大文件切割成小文件,split命令可以按照文件的行数、字节数切割文件,并能在输出的多个小文件中自动加上编号
-或-l
此两个选项等价,都用于指定切割成小文件的行数
-b
指定切割成小文件的字节
-C
与-b选项类似,但是,切割时尽量维持每行的完整性


split -2 TEACHER.db PEO.db
split -b100 TEACHER.db 
split -C100 TEACHER.db 


tr命令:tr命令实现字符转换功能
tr [选项] 字符串1 字符串2 <输入文件
tr命令要么将输入文件重定向到标准输入,要么从管道读入数据,记住tr命令的输入文件之前需要加上“<”符号
-c
选定字符串1中字符集的补集,即反选字符串1中的字符集
-d
删除字符串1中出现的所有字符
-s
删除所有重复出现的字符序列,只保留一个


tr -d A-Z tr -d 0-9 tr -d "[\n]" tr -s "[\n]"

tr "[a-z],[A-Z]" tr "[a-z]" "[A-Z]"



变量和引用
变量可分为三类:
本地变量是仅可以在用户当前Shell生命期的脚本中使用的变量
环境变量则适用于所有由登录进程所产生的子进程
环境变量在用户登录后到注销之前的所有编辑器、脚本、程序和应用中都有效
位置参数也属于变量,它用于向Shell脚本传递参数,是只读的


无类型,动态类型
integer.sh
null-undeclear.sh

变量替换
变量是某个值的名称,引用变量值就称为变量替换
$符号是变量替换符号,如variable是变量名,那么$variable就表示变量的值


变量赋值有两种格式:


variable=value 
${ variable=value } 
unset命令可以清除变量的值
readonly可将变量设置为只读,变量一旦设置为只读,任何用户不能对此变量进行重新赋值


环境变量
PWD
PATH
HOME
SHELL
PPID
PS1 PS2
\d
以“周 月 日”格式显示的日期
\H
主机名和域名
\h
主机名
\s
Shell的类型名称
\T
以12小时制显示时间,格式为:HH:MM:SS
\t
以24小时制显示时间,格式为:HH:MM:SS
\@
以12小时制显示时间,格式为:am/pm
\u
当前的用户名
\v
bash Shell的版本号
\V
bash Shell的版本号和补丁号
\w
当前工作目录的完整路径
\W
当前工作目录名字
\#
当前命令的序列号
\$
如果UID为0,打印#;否则,打印$


.bash_profile
/etc/profile
.bashrc
子shell
.bash_logout
退出


father.sh child.sh
位置参数
$1 ... ${10}...
$* $@




命令替换
  


退出状态
$?


    测试


if/else
case


运算符


循环与结构化命令


expr


管道与重定向

函数


调试
Shell选项,不修改代码
-n: 读一遍脚本中的命令但不执行,用于检查脚本中的语法错误

-v: 一边执行脚本,一边将执行过的脚本命令打印到标准错误输出


-x: 提供跟踪执行信息,将执行的每一条命令和结果依次打印出来 


   用法:
sh -x 
   修改脚本: #! /bin/sh -x
   修改脚本: set -x 开启 
          set +x 关闭
trap: 内建命令,用于捕捉信号
trap command sig1 sig2 sig3...sign
shell会产生三个伪信号:
EXIT
从函数中退出,或整个脚本执行完毕
ERR
当一条命令返回非零状态码,即命令执行不成功
DEBUG
脚本中的每一条命令执行之前


trapdebug.sh
trapexit.sh
traperr.sh
    调试钩子
if [ "$DEBUG" = "true" ]
then
echo "Debugging information:"
...
fi


debugblock.sh


export DEBUG=true
./debugblock.sh

    Regex
grep是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来,grep也是Linux中最广泛使用的命令之一


grep: BRE, Basic Regular Expression
        egrep: Extended Regular Expression
   fgrep:  并行,快速
        rgrep: recursive grep
   1992 POSIX,三个grep合并,grep -E =egrep;  grep -F =fgrep; grep -r =rgrep


grep [选项][模式][文件…]
 -c
  只输出匹配行的数量
 -i
 搜索时忽略大小写
 -h
 查询多文件时不显示文件名
 -l
 只列出符合匹配的文件名,而不列出具体匹配行
 -n
 列出所有匹配行,并显示行号
 -s
 不显示不存在或无匹配文本的错误信息
 -v
 显示不包含匹配文本的所有行
 -w
 匹配整词
 -r
 递归搜索,不仅搜索当前工作目录,而且搜索子目录
 -E
 支持扩展的正则表达式
 -F
 不支持正则表达式,按照字符串的字面意思进行匹


sed&awk


sed(stream editor)是流编辑器,可对文本文件和标准输入进行编辑。
sed只是对缓冲区中原始文件的副本进行编辑,并不编辑原始的文件
  如果需要保存改动内容,可以选择使用下面两种方法:
重定向
w编辑命令
sed 调用
在Shell命令行输入命令调用sed,格式为:
  sed [选项] ‘sed命令’ 输入文件
将sed命令插入脚本文件后,然后通过sed命令调用它,格式为:
   sed [选项] -f sed脚本文件 输入文件
将sed命令插入脚本文件后,最常用的方法是设置该脚本文件为可执行,然后直接执行该脚本文件,格式为:
./sed脚本文件 输入文件


 第二种方法脚本文件的首行不以#!/bin/sed –f开头;第三种方法脚本文件的首行是#!/bin/sed –f
   推荐使用第一种方法和第三种方法
sed 选项
-n
不打印所有行到标准输出
-e
表示将下一个字符串解析为sed编辑命令,如果只传递一个编辑命令给sed,-e选项可以省略
当向sed命令传递多个编辑命令时,在每个编辑命令前需要加上-e选项
-f
表示正在调用sed脚本文件


sed 文本定位
x: x为指定行号
x,y: 指定从x到y的行号范围
/pattern/: 查询包含模式的行
/pattern/pattern/: 查询包含两个模式的行
/pattern/,x: 从与pattern的匹配行到x号行之间的行
x,/pattern/: 从x号行到与pattern的匹配行之间的行
x,y!: 查询不包括x和y行号的行

sed -n '1p' input
sed  '1p' input
sed  '3,6p' input
sed  '/certificate/p' input
sed  -n '/certificate/=' input
sed  -n -e '/certificate/=' -e '/Certificate/=' input


sed编辑命令
p: 打印匹配行
=: 打印文件行号
a\: 在定位行号之后追加文本信息
i\: 在定位行号之前插入文本信息
d: 删除定位行
c\: 用新文本替换定位文本
s: 使用替换模式替换相应模式
r: 从另一个文件中读文本
w: 将文本写入到一个文件
y: 变换字符
q: 第一个模式匹配完成后退出
l: 显示与八进制ASCII代码等价的控制字符
{}: 在定位行执行的命令组
n: 读取下一个输入行,用下一个命令处理新的行
h: 将模式缓冲区文本拷贝到保持缓冲区
H: 将模式缓冲区文本追加到保持缓冲区
x: 互换模式缓冲区和保持缓冲区内容
g: 将保持缓冲区内容拷贝到模式缓冲区
G: 将保持缓冲区内容追加到模式缓冲区


查找到与模式匹配的文本行,这是sed命令经常使用的命令
经常需要结合正则表达式

追加文本:匹配行后面插入 
插入文本:匹配行前面插入 append.sed   
修改文本:将所匹配的文本行利用新文本替代 modify.sed
删除文本:将指定行或指定行范围进行删除: 指定地址 d

sed替换文本操作将所匹配的文本行利用新文本替换,替换文本与修改文本功能有相似之处,它们之间的区别在于:替换文本可以替换一个字符串,而修改文本是对整行进行修改
替换文本的格式为:
s/被替换的字符串/新字符串/[替换选项]
g
表示替换文本中所有出现被替换字符串之处
p
与-n选项结合,只打印替换行
w 文件名
表示将输出定向到一个文件


从文件中读入文本,r选项
cat otherfile
sed'/Certificate/r otherfile' input


退出命令: q选项表示完成指定地址的匹配后立即退出
sed '5 q' input
sed -n '/.r.*/p' input
sed  '/.r.*/q' input
变换命令: y选项表示字符变换,它将一系列的字符变换为相应的字符
sed ‘y/被变换的字符序列/变换的字符序列/’ 输入文件
sed y命令要求被变换的字符序列和变换的字符序列等长,否则sed y命令将报错
sed 'y/12345/ABCDE/' input 


命令组:{}
sed -n '/Certificate/{p;=} input
sed -n -e '/Certificate/p' -e '/Certificate/=' input


awk: Alfred V.Aho, Peter J. Weinberger, Brian W.Kernighan
语法类似C语言


调用awk有三种方法(与sed类似):
在Shell命令行输入命令调用awk,格式为:
   awk [-F 域分隔符] ‘awk程序段’ 输入文件
将awk程序段插入脚本文件后,然后通过awk命令调用它:
   awk -f awk脚本文件 输入文件
将awk命令插入脚本文件后,最常用的方法是设置该脚本文件为可执行,然后直接执行该脚本文件,格式为:
  ./awk脚本文件 输入文件
  第二种方法脚本文件的首行不以#!/bin/awk –f开头;第三种方法脚本文件的首行是#!/bin/awk –f
  推荐使用第一种方法和第三种方法


  BEGIN
循环进入每行
  END


  awk记录和域
  awk认为输入文件是结构化的,awk将每个输入文件行定义为记录,行中的每个字符串定义为域,域之间用空格、Tab键或其他符号进行分割,分割域的符号就叫分隔符

Aka EDU 1234567
roc EDU s234567
awk关系、布尔运算符、表达式:C
系统变量
$n
当前记录的第n个域,域间由FS分割
$0
记录的所有域
ARGC
命令行参数的数量
ARGIND
命令行中当前文件的位置(以0开始标号)
ARGV
命令行参数的数组
CONVFMT
数字转换格式
ENVIRON
环境变量关联数组
ERRNO
最后一个系统错误的描述
FIELDWIDTHS
字段宽度列表,以空格键分割
FILENAME
当前文件名
FNR
浏览文件的记录数
FS
字段分隔符,默认是空格键
IGNORECASE
布尔变量,如果为真,则进行忽略大小写的匹配
NF
当前记录中的域数量
NR
当前记录数
OFMT
数字的输出格式
OFS
输出域分隔符,默认是空格键
ORS
输出记录分隔符,默认是换行符
RLENGTH
由match函数所匹配的字符串长度
RS
记录分隔符,默认是空格键
RSTART
由match函数所匹配的字符串的第1个位置
SUBSEP
数组下标分隔符,默认值是\034


格式化输出:printf


内置字符串函数
gsub(r,s)
在输入文件中用s替换r
gsub(r,s,t)
在t中用s替换r
index(s,t)
返回s中字符串第一个t的位置
length(s)
返回s的长度
match(s,t)
测试s是否包含匹配t的字符串
split(r,s,t)
在t上将r分成序列s
sub(r,s,t)
将t中第1次出现的r替换为s
substr(r,s)
返回字符串r中从s开始的后缀部分
substr(r,s,t)
返回字符串r中从s开始长度为t的后缀部分


awk条件语句和循环语句


数组
ARGC ARGV ENVIRON




shell应用
文本-》HTML
topN
random








你可能感兴趣的:(知识要点)