探索shell
shell工作原理
/etc/passwd决定了用户登录后执行的shell程序。有些特殊的用户,可以不是shell程序
shell解析用户命令
•创建子进程执行用户命令
•shell等待命令子进程退出
•命令子进程退出,发送SIGCHLD信号给shell
•shell在信号处理函数中处理子进程退出
shell进程退出
•发送SIGCHLD信号给login进程
•login进程处理SIGCHLD信号
•退出,发送SIGCHLD信号给init进程
•init进程处理SIGCHLD信号,重新fork/exec一个getty进程
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选项
选项 | 功能 |
---|---|
打印输出 | |
-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 | 忽略中断信号 |