GUI (Graphical User Interface) 图形用户界面。用户界面的所有元素图形化,主要使用鼠标作为输入工具,点击图标执行程序,使用按钮、菜单、对话等尽心个交互,追求医用,看起来比较美
CLI (Command Line Interface) 命令行界面。用户界面字符化,使用键盘作为输入工具,输入命令、选项、参数执行程序,追求高效,看起来比较酷
缩写习惯
1. 最常见的缩写,取每个单词的首字母
cdChange DirectoryddDisk DumpdfDisk FreeduDisk UsagepwdPrint Working DirectorypsProcesses StatusPSPrompt StringssuSubstitute UserrcRun CommandTclTool Command LanguagecupsCommon Unix Printing SystemaptAdvanced Package ToolbgBackGroundpingPacket InterNet Grouper
2. 如果首字母后为h,通常保留
chshCHange SHellchmodCHange MODechownCHange OWNerchgrpCHange GRouPbashBourne Again ShellzshZ SHellkshKorn SHellsshSecure SHell
3. 递归缩写类
GNUGUN's Not UnixPHPPHP; Hypertext PregrocessorRPMRPM Package ManagerWINEWINE Is Not an EmulatorPNGPNG's Not GIFnanoNano's ANOther editor
4. 如果只有一个单词,通常取每个音节的首字母
cpCoPylnLiNklsLiStmvMoVermReMove
5. 对于目录,通常使用前几个字母作为缩写
binBINariesdevDEVicesetcETCeteralibLIBraryvarVARiableprocPROCessessbinSuperuser BINariestmpTemPoraryusrUnix Shared ResourcesdiffDIFFerencescalCALendarcatCATenateedEDitorexecEXECutetabTABleregexpREGular EXPression
6. 如果某种缩写比较深入人心,例如"mesg"代表"message",在新的复合缩写中,将沿用这种缩写方式
dmesgDiagnostic MESsaGesedStream EDitorsttySet TTYfstabFileSystem TABlepasswdPASSWorD
7. 有些缩写中,第一个字母’g’,代表’GNU'
awkAho Weiberger and KernighangawkGNU AWKgpgGNU Privacy GuardgrepGNU Regular Expression PrintegrepExtended GREP
命令选项,从a到z
- a
- all: 全部,所有(ls, uname, lsattr)
- archive: 存储(cp, rsync)
- append: 附加 (tar -A , 7z)
- b
- blocksize: 块大小,带参数 (du , df)
- batch: 批处理模式 (交互模式的程序通常拥有此选项,如 top -b)
- c
- commands : 执行命令,带参数 (bash , ksh , python)
- create : 创建 (tar)
- d
- debug : 调试
- delete : 删除
- directory : 目录 (ls)
- e
- execute : 执行,带参数 (xterm , perl)
- edit : 编辑
- exclude : 排除
- f
- force : 强制,不经确认(cp , rm ,mv)
- file : 文件,带参数 (tar)
- configuration file : 指定配置文件(有些守护进程拥有此选项,如 ssh , lighttpd)
- g
- h
- –help : 帮助
- human readable : 人性化显示(ls , du , df)
- headers : 头部
- i
- interactive : 交互模式,提示(rm , mv)
- include : 包含
- k
- keep : 保留
- kill
- l
- long listing format : 长格式(ls)
- list : 列表
- load : 读取 (gcc , emacs)
- m
- message : 消息 (cvs)
- manual : 手册 (whereis)
- create home : 创建 home 目录 (usermod , useradd)
- n
- number : 行号、编号 (cat , head , tail , pstree , lspci)
- no : (useradd , make)
- o
- output : 输出 (cc , sort)
- options : 选项 (mount)
- p
- port : 端口,带参数 (很多网络工具拥有此选项,如 ssh , lftp )
- protocol : 协议,带参数
- passwd : 密码,带参数
- q
- quiet : 静默
- r
- reverse : 反转
- recursive : 递归 (cp , rm , chmod -R)
- s
- silent : 安静
- size : 大小,带参数
- subject
- t
- tag
- type: 类型(mount)
- u
- user:用户名、UID、带参数
- v
- verbose : 冗长
- version : 版本
- w
- width : 宽度
- warning : 警告
- x
- exclude : 排除 (tar , zip)
- y
- yes
- z
- zip : 启用压缩 (bzip , tar , zcat , zip , cvs)
学会使用man命令
下面以
man date为例进行说明![]()
man date- DATE(1) 1代表的是一般用户可以执行的命令
- Name 简短的命令,数据名称说明
- SYNOPSIS 简单的命令执行语法简介
- DESCRIPTION 命令较为完整的说明
- FORMAT 格式化输出的详细数据
- ENVIRONMENT 与这个命令相关的环境参数有如下说明
- AUTHOR 这个命令的作者
- REPORTING BUGS bugs 反馈地址
- COPYRIGHT 收到著作权法的保护!用的就是 GPL
- SEE ALSO 查看与 date 相关的说明
- 常见的数字的意义
| 数字 | 代表内容 |
|---|---|
| 1 | 用户在 shell 环境中可以操作的命令或可执行文件 |
| 2 | 系统内核可调用的函数与工具等 |
| 3 | 一些常用的函数(function)与函数库(library)大部分为 C 的函数库(libc) |
| 4 | 设备文件的说明,通常在 /dev 下的文件 |
| 5 | 配置文件或是某些文件的格式 |
| 6 | 游戏 games |
| 7 | 惯例与协议等,例如 Linux 文件系统、网络协议、ASCII code 等的说明 |
| 8 | 系统管理员可以执行的管理命令 |
| 9 | 跟 kernel 有关的文件 |
- Man page 大致分为下面几个部分
| 代号 | 内容说明 |
|---|---|
| NAME | 简短的命令,数据名称说明 |
| SYNOPTIONS | 简短的命令执行语法(syntax)简介 |
| DESCRIPTION | 较为完整的说明 |
| OPTIONS | 针对 SYNOPTIONS 部分中,有列举的所有可用的选项说明 |
| COMMANDS | 当这个程序(软件)在执行的时候,可以在此程序(软件)中执行的命令 |
| FILES | 这个程序或数据所使用或参考或连接到的某些文件 |
| SEE ALSO | 这个命令或数据相关的其他说明 |
| EXAMPLE | 一些参考的范例 |
| BUGS | 是否哟相关的错误 |
一些命令
- apropos 显示一系列适合的命令
- whatis 显示一个命令的简洁描述
- tee - 从标准输入读取数据,并同时写到标准输出和文件
- traceroute 显示从本地到指定主机 要经过的所有“跳数”的网络流量列表
- netstat 程序被用来检查各种各样的网络设置和统计数据
- gzip 压缩或文件
- -d 解压缩 和 gunzip 命令一样
- gunzip 解压 gzip 的压缩文件
- bzip2 块排序文件压缩器 -d 解压
- tar 打包工具
- zip 打包和压缩文件
- rsync 同步远端文件和目录
- paste 将给定输入文件相应行连接起来,用单个制表符替换除最后一个文件的换行符外的所有行符
- tr 基于字符的查找和替换
- -d 删除指定字符
tr -d '\r' < file - -s 挤压(删除)连续的重复字符
echo "aaabbbccc" | tr -s ab得到abccc
- -d 删除指定字符
- sed 命令 [[SED使用教程]]
- aspell 交互式的拼写检查器
由此产生的线路到标准输出
一些概念
文件描述符(File Descriptor, FD)
文件描述符是一个非父整数,用于标识进程在操作系统内核中打开的文件或其它输入/输出资源。文件描述符是操作系统管理文件和资源的一种抽象,几乎所有的输入/输出操作都依赖它们。
文件描述符用于以下几种常见的资源
- 文件: 当一个文件被打开时,操作系统返回一个文件描述符,以后对该文件的读写操作都通过这个文件描述符来进行
- 管道:管道是一种特殊的文件,用于在进程之间传递数据。管道的两端分别对应两个文件描述符,一个用于读,一个用于写
- 套字节:网络通信中的套接字也使用文件描述符来标识
- 设备文件:如终端、打印机等设备,操作系统将其视为文件,也使用文件描述符来标识
在 Unix 和 Linux 系统中,前三个文件描述符是标准的
- 0: 标准输入(stdin)默认情况下从键盘输入数据
- 1: 标准输出(stdout)默认情况下输出数据到屏幕
- 2: 标准错误(stderr)默认情况下输出错误信息到屏幕
文件描述符的工作原理 当一个进程启动时,操作系统为其分配一组文件描述符,用于管理文件和设备的输入输出。文件描述符是进程级的,这意味着每个进程都有自己独立的文件描述符表。
标出输出,错误输出重定向问题
- 标准输出重定向
mako@ubuntu:~$ ls -l /bin/users > ls-output.txt - 标准输出重定向
mako@ubuntu:~$ > ls-output.txt- 表示直接清空 ls-output.txt 的内容或创建这个空文件
- 标准错误输出重定向
mako@ubuntu:~$ ls -l /bin/users 2> ls-error.txt- 在重定向符号前面添加上
2(标准错误的文件描述符)
- 在重定向符号前面添加上
- 标准输出和错误输出重定向到一个文件
mako@ubuntu:~$ ls -l /bin/users > output.txt 2>&1- 另外一种写法
mako@ubuntu:~$ ls -l /bin/users &> output.txt
- 另外一种写法
- 输入不做处理
mako@ubuntu:~$ ls -l /bin/users > /dev/null/dev/null文件是系统设备,叫做位存储桶,它可以接受输入,并且对输入不做 任何处理
shell 中算术表达式
$((expression))
特殊的权限位
setuidchmod u+s program- 当应用到一个可执行文件时,它把有效用户ID从真正的用户(实际运行程序的用户)设置成程序所有者的ID
- 如
-rwsr-xr-x 1 root root 59976 Feb 6 20:54 /usr/bin/passwd
setgidchmod g+s dir- 把有效用户组 ID 从 真正的用户组 ID 更改为文件所有者的组 ID
- 当
setgid位设置在一个目录上时,该目录中创建的新文件和子目录将继承其父目录的组,而不是创建它们的用户的主组 - 一版用于 共享工作目录,开发环境目录及临时目录设置使用
stickychmod +t dir- 如果一个目录设置了 sticky 位,那么它能阻止用户删除或重命名文件,除非用户是 这个目录的所有者,或者是文件所有者,或是超级用户
- 常用来控制访问共享目录,如
/tmp drwxrwxrwt. 46 root root 126976 Jun 17 09:23 tmp
进程状态描述
| 状态 | 含义 |
|---|---|
| R | 运行中。这意味着,进程正在运行或准备运行。 |
| S | 正在睡眠。进程没有运行,而是,正在等待一个事件,比如 说,一个按键或者网络分组。 |
| D | 不可中断睡眠。进程正在等待 I/O,比方说,一个磁盘驱动 器的 I/O。 |
| T | 已停止. 已经指示进程停止运行。 |
| Z | 一个死进程或“僵尸”进程。这是一个已经终止的子进程, 但是它的父进程还没有清空它。(父进程没有把子进程从进程表中删除) |
| < | 一个高优先级进程 |
| N | 低优先级进程 |
sudo 和 su
sudo 命令
- 执行单个命令:
sudo命令用于以另一个用户(通常是超级用户 root)的身份执行单个命令。 - 身份验证:
sudo命令要求用户输入自己的密码,而不是 root 的密码。这意味着用户需要被授予使用sudo的权限(配置在/etc/sudoers文件中)。 - 权限控制:系统管理员可以在
/etc/sudoers文件中配置特定用户或用户组对某些命令的执行权限。这提供了更细粒度的权限控制。 - 日志记录:
sudo命令的使用会被记录在日志文件中(通常在/var/log/auth.log),这便于审计和追踪。
su 命令
- 切换用户身份:
su命令用于切换到另一个用户的身份。默认情况下,su切换到 root 用户,但也可以切换到其他用户。 - 身份验证:
su命令要求输入目标用户(通常是 root)的密码。这意味着用户需要知道 root 的密码或其他目标用户的密码。 - 新 shell 环境:
su命令切换用户身份后,会启动一个新的 shell 环境。加上-或-l参数时,su将会模拟一个完整的登录,会加载目标用户的环境变量和配置文件。 - 持续权限:
su切换用户后,所有后续命令都会以新的用户身份执行,直到退出当前 shell 环境。
read 从标准输入读取数值
| 选项 | 说明 |
|---|---|
| -a array | 把输入赋值到数组 array 中,从索引号零开始 |
| -d delimiter | 用字符串 delimiter 中的第一个字符指示输入结束,而不是 一个换行符 |
| -e | 使用 Readline 来处理输入 |
| -n num | 读取 num 个输入字符, 而不是整行 |
| -p prompt | 为输入显示提示信息,使用字符串 prompt |
| -r | Raw mode. 不把反斜杠字符解释为转义字符 |
| -s | Silent mode. 不会在屏幕上显示输入的字符。当输入密码和其它确认信息的时候有帮助 |
| -t seconds | 超时。几秒钟后终止输入。若输入超时,read会返回一个非零退出状态 |
| -u fd | 使用文件描述符 fd 中的输入,而部署标准输入 |
#!/bin/bash
# read-ifs: read fields from a file
FILE=/etc/passwd
read -p "Enter a user name > " user_name
file_info=$(grep "^$user_name:" $FILE)
if [ -n "$file_info" ]; then
OLD_IFS="$IFS"
IFS=":"
read user pw uid gid name home shell <<< "$file_info"
# <<< 操作符指示一个 here 字符串。一个 here 字符串就像一个 here 文档,只是比较简短,由单个字符串组成
IFS="$OLD_IFS"
fi
注意 上面采用 here 字符串 <<< 的模式来使用,不能把管道用在 read 上
如 echo "foo" | read 这个命令将显示成功,但是 REPLY 变量总是为空。为什么会这样?
在 bash 中管道线会创建子 shell。这个子 shell 是为了执行执行管线中的命令而创建的 shell 和 它的环境的副本。上面的示例中 read 命令将在子 shell 中执行。
在类 Unix 的系统中,子 shell 执行的时候,会为进程创建父环境的副本。当进 程结束之后,该副本就会被破坏掉。这意味着一个子 shell 永远不能改变父进程的 环境。read 赋值变量,然后会变为环境的一部分。在上面的例子中,read 在它的子 shell 环境中,把 foo 赋值给变量 REPLY,但是当命令退出后,子 shell 和它的环境 将被破坏掉,这样赋值的影响就会消失。
使用 here 字符串是解决此问题的一种方法。
一些点
单词分割问题
单词分割机制把换行符看作界定符,对命令替换产生了一个虽然微妙但有趣的影响。
# 没有引用的命令替换导致命令行包含 39 个参数
mako@ubuntu:~/books$ echo $(cal)
June 2024 Su Mo Tu We Th Fr Sa 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
# 命令 行只有一个参数,参数中包括嵌入的空格和换行符
mako@ubuntu:~/books$ echo "$(cal)"
June 2024
Su Mo Tu We Th Fr Sa
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30
正则表达式 (POSIX标准)
- 正则表达式元字符
^ $ . [ ] { } - ? * + ( ) | \ ^$行首和行尾之间没有字符,会匹配空行
shell 中使用 case 的时候默认不匹配多个测试条件,现在的 bash 版本中,添加 “;;&” 表达式来终止每个行动
shell 中特殊的参数
| 参数 | 描述 |
|---|---|
| $* | 展开成一个从 1 开始的位置参数列表。当它被用双引号引 起来的时候,展开成一个由双引号引起来的字符串,包含了 所有的位置参数,每个位置参数由 shell 变量 IFS 的第一个字符(默认为一个空格)分隔开。如果 IFS 为 null,则连接参数时不插入分隔符 |
| $@ | 展开成一个从 1 开始的位置参数列表。当它被用双引号引 起来的时候,它把每一个位置参数展开成一个由双引号引起来的分开的字符串 |
| $# | 扩展为十进制位置参数的数量 |
| $- | 扩展为调用时指定的当前选项标志,由 set 内置命令或 shell 本身设置的选项标志(例如 -i 选项) ) |
组命令和子shell
组命令: { command1; command2; [command3; ...]}
- 花括号与命令之间必须有一个空格,并且最后一个命令必须用一个分号或者一个换行符终止
- 组命令中的命令则直接在当前Shell进程中执行,因此对于环境的修改会影响到后续的命令执行。
子shell: (command1; command2; [command3; ...])
- 子shell会创建一个新的子进程来执行其中的命令,子进程会继承父进程的环境变量和文件描述符等信息
- 因此在子shell中执行的命令对于父进程来说是独立的,不会影响到父进程的环境
注意: 任何通过子shell给变量赋值的命令会导致变量为空。如
echo "foo" | read ; echo $REPLY的值一直为空
shell 提供了一种叫做进程替换的方式来解决这类问题。进程替换有两种表达方式
- 适用于产生标准输出的进程
<(list) - 适用于接受标准输入的进程
>(list)
如解决上面 read 的问题,可以使用下面的形式
read < <(echo "foo")
echo $REPLY
trap 陷阱
当 shell 脚本接收到一些信号量(如 ctl+c)的时候,执行一些动作。可以使用 trap
trap 的语法 trap argument signal [signal...] 这里的 argument 是一个字符串,它被读取并当作一个命令,signal是一个信号的说明,它会触发执行所要解释的命令。
字符串和数字
管理空变量的展开
| 形式 | 说明 |
|---|---|
${parameter:-word} | parameter有值使用自己,未设置或为空使用 word 的值 |
${parameter:=word} | parameter有值使用自己,未设置或为空使用 word 的值,且会把 word的值赋值给 parameter |
${parameter:?word} | 若 parameter 没有设置或为空,这种展开导致脚本带有错误退出,并且 word 的内容会发送 到标准错误。若 parameter 不为空,展开结果是 parameter 的值。 |
${parameter:+word} | 若 parameter 没有设置或为空,展开结果为空。若 parameter 不为空,展开结果是 word 的 值会替换掉 parameter 的值;然而,parameter 的值不会改变。 |
#!/bin/bash
# ${parameter:-word}
foo=
echo ${foo:-substitute value if unset} # 输出 substitute value if unset
echo $foo # 输出空
foo=bar
echo ${foo:-substitute value if unset} # 输出 bar
echo $foo # 输出 bar
# ${parameter:=word}
foo=
echo ${foo:="default value if unset"} # 输出 default value if unset
echo $foo # 输出 default value if unset
foo=bar
echo ${foo:="default value if unset"} # 输出 bar
echo $foo # 输出 bar
# ${parameter:?word}
foo=
echo ${foo:?"parameter is empty"} # 输出 bash: foo: parameter is empty
echo $? # 输出 1
foo=bar
echo ${foo:?"parameter is empty"} # 输出 bar
echo $foo # 输出空
# ${parameter:+word}
foo=
echo ${foo:+"substitute value if set"} # 输出空
foo=bar
echo ${foo:+"substitute value if set"} # 输出 substitute value if set
返回变量名的参数展开
${!prefix*} 和 ${!prefix@} 都会返回以 prefix 开头的已有变量名。两种形式的执行结果形同。
字符串展开
字符串操作展开可以用来替换其它常见命令比方说 sed 和 cut。通过减少使用外部程序,展开提高了脚本的效率。
| 形式 | 说明 |
|---|---|
${#parameter} | 返回parameter所包含的字符串长度。如果 parameter为 @ 或 * 则结果为位置参数的个数 |
${parameter:offset} | 获取 从第offset 个字符到字符串结尾的内容 |
${parameter:offset:length} | 获取 从第offset 个字符开始数 length 个长度的字符 |
${parameter#pattern} | #清除模式 foo=file.txt.zip; echo ${foo#*.} 输出结果 txt.zip |
${parameter##pattern} | foo=file.txt.zip; echo ${foo##*.} 输出结果 zip |
${parameter%pattern} | 从尾部开始最小匹配删除字符串 echo ${foo%.*} # file.txt |
${parameter%%pattern} | 从尾部开始最大匹配删除字符串 echo ${foo%%.*} # file |
${parameter/pattern/string} | 查找替换匹配的第一个 `echo ${foo/./ |
${parmeter//pattern/string} | 查找替换全部 `echo ${foo//./ |
${parameter/#pattern/string} | /# 要求匹配项出现在字符串的开头 foo=JPG.JPG;echo ${foo/#JPG/jgp} 输出 jpg.JPG |
${parameter/%pattern/string} | 而 /% 要求匹 配项出现在字符串的末尾 echo ${foo/%JPG/jpg} JPG.jpg |
大小写转换
| 格式 | 说明 |
|---|---|
${parameter,,} | 把 parameter 的值全部展开为小写字母 |
${parameter,} | 仅把第一个字符串展开为小写 |
${parameter^^} | 把 parameter 的值全部转换成大写字母 |
${parameter^} | 仅把 parameter 的首字母大写 |
数基
| 表示法 | 描述 |
|---|---|
number | 默认情况下,没有任何表示法的数字被看做是十进制数(以 10 为底) |
0number | 八进制 |
0xnumber | 十六进制 |
base#number | number以base为底 |
如何在 shell 进行高级的数学运算或使用浮点数
不能直接使用shell完成此类运行。可以使用外部程序如嵌入Perl 、AWK 等。或者使用 bc 命令。
/* foo.bc A very simple bc script */
2 + 2
bc -q foo.bcbc < foo.bc
找到数组元素的下标
${!array[*]} 和 ${!array[@]}
#!/bin/bash
foo=([2]=a [4]=b [6]=c)
for i in "${!foo[@]}"; do
echo $i
done
# 输出: 2 4 6
临时文件
mktemp 程序接受一个用于创建文件名的模板作为参 数。这个模板应该包含一系列的“X”字符,随后这些字符会被相应数量的随机字 母和数字替换掉。一连串的“X”字符越长,则一连串的随机字符也就越长。
tempfile=$(mktemp /tmp/foobar.$$.XXXXXXXXXX) # 文件名如 /tmp/foobar.844890.NGOzxtorFx
异步执行
在 bash 中可以使用 wait 命令来管理异步执行的任务,该命令会导致一个父脚本暂停运行,直到一个特定的进程运行结束。
#!/bin/bash
# async-parent: Asynchronous execution demo (parent)
echo "Parent: starting..."
echo "Parent: launching child script..."
aynsc-child &
pid=$!
echo "Parent: child (PID= $pid) launched."
echo "Parent: continuing..."
sleep 2
echo "Parent: pausing to wait for child to finish..."
wait $pid # 这里会等到子脚本执行完成后后续的才会执行
echo "Parent: child is finished. Continuing..."
echo "Parent: parent is done. Exiting."
#!/bin/bash
# async-child : Asynchronous execution demo (child)
echo "Child: child is running..."
sleep 5
echo "Child: child is done. Exiting."
