shell工作原理

/etc/passwd决定了用户登录后执行的shell程序。有些特殊的用户,可以不是shell程序

shell解析用户命令

•创建子进程执行用户命令

•shell等待命令子进程退出

•命令子进程退出,发送SIGCHLD信号给shell

•shell在信号处理函数中处理子进程退出

shell进程退出

•发送SIGCHLD信号给login进程

•login进程处理SIGCHLD信号

•退出,发送SIGCHLD信号给init进程

•init进程处理SIGCHLD信号,重新fork/exec一个getty进程

shell进程退出

shell内建命令会比外部命令执行得更快,执行外部命令时不但会触发磁盘 I/O,还需要 fork 出一个单独的进程来执行,执行完成后再退出。而执行内建命令相当于调用当前 Shell 进程的一个函数。内置命令可以替换一些经常使用的命令,部分提升性能

Special building command → function → building command → export command

•内置命令区分出special,原因是某些内置命令允许function重载

echo命令输出字符串

•不同的Unix系统对echo的命令做了选项扩展

•如果是格式化输出,使用printf

shell语言

shell负责与用户交互,虽然简单,但仍然要看成一种语言

•变量

•命令

•循环与分支

命令的语法

命令+空格+[选项]+参数+(;|回车)

•echo hello; ls -al

•多行单条命令,一行的尾部以\结束

•ls \

-al

完整的命令解析过程

完整的命令解析过程

•tilde是~表达式展开

•变量替换

•命令展开是重音符的命令展开

•单词划分利用$IFS变量分割

•寻找命令

shell变量

set命令显示所有变量,export命令显示所有环境变量

shell内置一个变量表

•每个变量有环境变量或局部变量属性

•变量名 à 字符串

环境变量

•会将环境变量传递给子进程(fork)

•C语言getenv()函数

添加修改变量

•VAR=xxx

•等号两侧不能由空格

•export VAR=xxx添加环境变量

引用变量

•$VAR或者${VAR}

标准变量

HOME变量

记录用户主目录

•HOME=/usr

•cd

PATH变量

给出外部程序的搜索路径

•dash

•PATH=

•which pwd

•exit

IFS变量

定义扩展命令参数时的分隔符

命令参数展开

shell在解释命令时,有一个重要的步骤是展开变量得到命令参数

例:ls -al *

shell在解释这条命令时:

•ls是命令,special builtins → functions → builtins → export command去查找

•-al是一个参数

•*需要展开

shell内部将对参数的展开

•-开头当成选项

•双引号、单引号、重音符号开头作为字符串

•$开头作为变量

•<>作为重定向符号

•|作为管道符号

•其余字符串如果包含*?[]需要做路径匹配展开

shell路径元字符

!注意shell元字符并非正则表达式

元字符 功能
? 匹配路径名的单个字符
* 匹配路径名的任意长度的字符串
[list] 匹配list中任意一个字符
[!list] 匹配不在list中的任意一个字符

例:[abc];[a-z];[!a-z];[a-z!]

反斜杠\转义

消除shell元字符语义

•rm temp?

•rm temp?

•echo \< \> \” \’ \` \$ \* ? \& \| \\

双引号,单引号字符串

双引号字符串需要展开$VAR变量,单引号,重音符号

•echo “$HOME”

单引号字符串不展开变量

•echo ‘$HOME’

重音符号表示一个内嵌命令,要先执行,然后得到输出作为参数

•双引号内的重音符号要先执行

•echo “`ls -a``”

find与grep

find命令

在文件目录树中查找文件

find start-point tests action

•从start-point开始查找,start-point是一个路径

•tests做测试

•满足条件执行action

测试条件
选项 功能
-name filename 根据给定的filename做匹配查找
-size ±n 查找大小为n的文件
-type filetype 查找指定类型filetype的文件
-atime n 查找access访问时间的问题
-mtime n 查找修改时间的文件

使用命令 find ./ -name *.sh (本身已经在要查找的目录里了)

结果报错

解决方法一:find ./ -name \*.sh (将.sh转义)

解决方法二:find ./ -name “*.sh”

-type

•-type f 普通文件

•-type d 目录文件

Action选项
选项 功能
-print 打印输出
-exec command; 执行命令
-ok command; 在执行命令前要求确认
grep命令

打开文件,在文件中以RE方式搜索字符串

•grep [OPTION…] PATTERNS [FILE…]

短选项 长选项 功能
-c –count 只显示匹配的行数
-i –ignore-case 忽略大小写匹配
-G –basic-regexp BRE,grep缺省
-E –extended-regexp ERE,egrep缺省
-e PATTERNS –regexp=PATTERNS 指定一个或多个RE
-v –invert-match 显示不匹配的行
-n –line-number 输出行号
xargs

xargs [command [initial-arguments]]

•xargs从标准输入上读,将标准输入文件按照空格/TAB拆解成参数,作为command执行参数。

•查找epoll_wait函数在那个文件:find /usr/include –name “*.h” -type f | xargs grep “epoll_wait”

shell配置

用户登录,启动缺省shell

•man bash,查找INVOCATION

•/etc/profile → ~/.bash_profile → ~/.bash_login → ~/.profile

如果不是login启动的shell

•/etc/bash.bashrc → ~/.bashrc

用户退出

•~/.bashr_logout

进程管理

ps命令

显示进程

•ps -ejH以树型输出所有进程

选项 功能
-a 显示所有进程,但不包括会话leader,不包括无终端进程
-f 显示进程完整信息
-e 显示所有进程
-H 按照树型显示
-j 按照job形式输出

kill命令

向进程发送信号

•缺省发送SIGTERM信号,15

选项 功能
-l 列出所有信号
-1 除init进程,以及自己外的所有进程
-s 发送s标志的信号

•信号类似于硬件中断

•Ctrl-c快捷键 → 发送SIGINT信号

•Ctrl-d → 发送EOF,意思是输入关闭

trap命令

设置进程捕获信号后如何处理

trap “command” signal numbers

•trap ‘’ TERM 忽略SIGTERM信号

•trap - TERM 恢复SIGTERM信号缺省处理

前台后台

&命令

shell命令使用&表示后台执行

•ping www.baidu.com > /dev/null &

•nohup “command”&:后台执行命令,并且该命令在用户退出登录后仍然执行

jobs命令

是一个builtin命令,列举后台执行的作业

•man bash搜索SHELL BUILTIN COMMANDS

fg命令

fg jobspec 作业编号用jobs命令查询

History与fc

History

Bash在执行命令后,会在内存中记录所有使用的命令。

当用户退出登录,所有命令保存在~/.bash_history文件中

•history命令则列出到目前为止,执行的所有命令。

•~/.bash_history记录的是到上次退出前的所有命令,注意与history不同

fc

fc是一个builtin命令。man bash搜索SHELL BUILTIN COMMANDS

•fc first last :命令先编辑从first到last的命令,然后执行

•fc –s cmd :cmd是history的命令编号,执行该编号任务

alias

alias是一个builtin命令

•alias ll=‘ls –al’

tee命令

分离输出,同时输出到标准输出和文件

•ls -al | tee dir.list

选项 功能
-a 追加到文件
-i 忽略中断信号