# 生产力工具:shell 与 Bash 脚本
作者:吴甜甜
个人博客网站: wutiantian.github.io
注意:本文只是我个人总结的学习笔记,不适合0基础人士观看。
----
参考内容:
王顶老师 linux bash 视频教程
http://billie66.github.io/TLCL/book
C语言编程网: http://c.biancheng.net/shell/
推荐书籍:《UNIX环境编程》,有内容,有远离,课后习题也很棒。
---
目录
<!-- TOC -->
- [生产力工具:shell 与 Bash 脚本](#生产力工具shell-与-bash-脚本)
- [我为什么学 shell](#我为什么学-shell)
- [什么是 shell 与 BASH](#什么是-shell-与-bash)
- [学 shell 与 BASH 立竿见影的好处](#学-shell-与-bash-立竿见影的好处)
- [三步编写执行一个 Shell 脚本](#三步编写执行一个-shell-脚本)
- [命令](#命令)
- [命令提示符与命令的概念简述](#命令提示符与命令的概念简述)
- [命令的详细](#命令的详细)
- [linux系统基础操作](#linux系统基础操作)
- [linux思想:一切皆文件](#linux思想一切皆文件)
- [探索操作系统状态](#探索操作系统状态)
- [linux文件系统跳转](#linux文件系统跳转)
- [操作文件和目录](#操作文件和目录)
- [文本处理](#文本处理)
- [停止](#停止)
- [权限](#权限)
- [软件安装管理](#软件安装管理)
- [编译程序make](#编译程序make)
- [shell眼中看世界——“展开”](#shell眼中看世界展开)
- [字符展开](#字符展开)
- [路径名展开](#路径名展开)
- [波浪线展开](#波浪线展开)
- [算术表达式展开](#算术表达式展开)
- [花括号展开](#花括号展开)
- [参数展开](#参数展开)
- [命令(展开)替换](#命令展开替换)
- [引用-控制展开](#引用-控制展开)
- [引用-双引号-限制部分展开](#引用-双引号-限制部分展开)
- [引用-单引号-禁止展开](#引用-单引号-禁止展开)
- [转义字符](#转义字符)
- [IO 重定向](#io-重定向)
- [IO](#io)
- [重定向](#重定向)
- [管道操作符\|提取数据](#管道操作符\提取数据)
- [正则表达式](#正则表达式)
- [用“元字符”实现复杂匹配](#用元字符实现复杂匹配)
- [元字符和原义字符](#元字符和原义字符)
- [grep](#grep)
- [专项专题(选看)](#专项专题选看)
- [显示与查找文件](#显示与查找文件)
- [归档 tar、解压、批量](#归档-tar解压批量)
- [内存与进程的性能](#内存与进程的性能)
- [存储媒介-设备挂载](#存储媒介-设备挂载)
- [网络](#网络)
- [定制 shell](#定制-shell)
- [shell环境](#shell环境)
- [定制 shell 提示符$PS1](#定制-shell-提示符ps1)
- [别名alias-创建你自己的命令](#别名alias-创建你自己的命令)
- [写脚本](#写脚本)
- [注释第一行](#注释第一行)
- [变量](#变量)
- [使用变量](#使用变量)
- [声明数组](#声明数组)
- [表达式](#表达式)
- [数学运算](#数学运算)
- [流程控制-if](#流程控制-if)
- [流程控制-循环](#流程控制-循环)
- [语句](#语句)
- [脚本习题](#脚本习题)
- [附录:如何查看 man 帮助手册](#附录如何查看-man-帮助手册)
- [附录:学习方法](#附录学习方法)
- [附录:鸣谢](#附录鸣谢)
<!-- /TOC -->
# 我为什么学 shell
我首先接触到 shell 是在深圳的一家fpga的方案公司参观交流时,看到工程师对fpga进行编程时,敲几个字符就插入了代码块,感觉很快,是生产力的决胜武器。工程师告诉我,每个 fpga 公司都有自己的核心技术专利,编写好的私有库就是通过几个字符的脚本插入到程序中,每家都不同,模块不对外公开。
**我意识到,成为具有核心价值的工程师必须掌握这项技能!**
我本科时学的是电子信息工程,对软件的态度并没有什么都要会的意识,只是用到再学。但对于 shell ,它并不能迫在眉睫能解决什么必须处理的问题,却成为人与人差距的重要一环之一。
写本内容时,是应用于图像机器学习中遇到实际问题写的个人笔记。当我准备用手头的《Linux程序设计》书时,很失望,看着块头挺大。内容可看的不多。网上的博客大多数内容比较浅,实战性不强。所以我自己写给自己复习。
*嵌入式的shell是精简过的,语法略有不同,这点要注意。比如说数组,部分命令的输出和PC尚的存在一定差异。*
## 什么是 shell 与 BASH
- shell:
一说到命令行,我们真正指的是 shell。
**shell 就是一个程序,它接受从键盘输入的命令, 然后把命令传递给操作系统去执行。**
- BASH
“bash” 是 “Bourne Again SHell” 的首字母缩写。
bash 是由 Steve Bourne 的人写成 **shell 程序的增强版**
因为基于“命令行”界面,而不是“图形”界面,所以 shell 与 bash 的适应性更强,能应用在**多种系统**中,是“**通杀**”的技能。
## 学 shell 与 BASH 立竿见影的好处
|常用功能例举|功能简述|优势|功能|
|---|---|---|---|
|1|自动运行命令行|自动执行多组操作|添加一条命令行,每次输入几个字符(打开bash)时都会自动运行|
|2|alias别名|简化单组操作字符数|
# 三步编写执行一个 Shell 脚本
|步骤|内容|详细|
|:---|:---:|:---|
|1|**编写一个脚本。**|shell 脚本就是普通的文本文件。所以我们需要一个文本编辑器来书写它们。最好的文本 编辑器都会支持语法高亮,这样我们就能够看到一个脚本关键字的彩色编码视图。语法高亮会帮助我们查看某种常见 错误。为了编写脚本文件,vim,gedit,kate,和许多其它编辑器都可以。|
|2|使脚本文件**可执行**。|系统会相当挑剔不允许任何旧的文本文件被看作是一个程序,并且有充分的理由! 所以我们需要设置脚本文件的权限来允许其可执行。|
|3|把脚本放置到 shell 能够找到**当前目录下**。|当没有指定可执行文件明确的路径名时,shell 会**自动地搜索某些目录**, 来查找此可执行文件。为了最大程度的方便,我们会把脚本放到这些目录当中。|
# 命令
## 命令提示符与命令的概念简述
- 命令提示符:说明 **shell已经准备好输入了**。
>[当前用户登录名@linux主机名 当前路径]$
例如: [Teenie@wutiantian.github.io ~]$
表示:当前用户Teenie在主机名为wutiantian.github.io的当前路径为家目录
注意,后续的“定制 shell 环境”章节 有具体更改为自己心中环境的设置过程。
- 命令行语法
>command -options arguments
>命令 一个或多个选项 一个或多个参数对象
以“空格”分隔,不管几个空格都算一个空格。
例如: ls -l /usr
- 如何选择命令行发挥更大优势
|界面|优势|
|---|---|
|图形|简单的任务更简单|
|命令行|复杂的任务成为可能|
## 命令的详细
选项 options 分为 短选项和长选项,**功能效果一样**。
|options|举例|优势|描述|
|---|---|---|:---|
|short|-a|效率高|格式为'-'**单横杠**。<br>短选项可**合并**。若'-'后不止一个字母则为合并选项。<br>例如:-a与-l合并为-al全部列出功能|
|long|--all|更直观|格式为'--'**双横杠**。<br>长选项没有合并说法。|
|命令|四种形式||
|---|:---:|:---:|
|execute binary<br>可执行二进制|就像我们所看到的位于目录/usr/bin 中的文件一样|用诸如 C 和 C++语言写成的**程序编译**的**二进制文件**, 也可以是由诸如shell,perl,python,ruby等等**脚本语言**写成的程序 |
|buildin bash<br>内嵌bash命令|bash 支持若干命令,内部叫做 shell 内部命令 (builtins)|例如,cd 命令,就是一个 shell 内部命令。|
|shell function 函数|这些是小规模的 shell 脚本|它们混合到环境变量中。|
|alias 命令别名|定义自己的命令|建立在其它命令之上|
|命令|检测命令的四种形式归属|举例|举例|
|---|---|---|---|
|type|Indicate how a command name is interpreted<br>说明怎样解释一个命令名|type command<br>**四种命令形式的哪一种**|#type type <br> type is a shell builtin <br> #type ls<br>ls is aliased to `ls --color=auto'<br>#type cp<br>cp is /bin/cp|
|which|To determine the exact location of a given executable, the which command is used:<br>显示可执行程序的**位置**|which command<br>一个操作系统中,不只安装了可执行程序的一个版本,为了确定所给定的执行程序的准确位置,使用 which 命令<br>**这个命令只对可执行程序有效**|#which cp<br>/bin/cp<br>#which cd<br>使用 shell 内建命令时,得不到回应。|
|help|得到**shell 内建命令的(简要)帮助文档**|command --help<br>help command<br>帮助文件可能是**中文**也可能是**英文**|help cd<br>cd --help|
|man|**详细**用户帮助|man command|man ls \| less|
|apropos|基于某个关键字的**搜索**匹配项,很粗糙但有时很有用|apropos command<br>等价于man -k|
|whatis|The whatis program displays the name and a one line description of a man page matching a specified<br>显示**匹配特定关键字**的**手册页**的名字和**一行命令说明**|whatis command|whatis ls<br>ls(1)- list directory contents|
|info|info 内容可通过 info 阅读器 程序读取。info 页是超级链接形式的,和**网页很相似,退出就消失了痕迹**。<br>info 文件包含超级链接,它可以让你从一个结点跳到另一个结点。一个**超链接**可通过 它开头的**星号来辨别**出来,把光标放在它上面并**按下 enter 键,就可以激活它**。|info command|info ls|
>help cd
长说明
```
cd: cd [-L|[-P [-e]] [-@]] [dir]
Change the shell working directory.
Change the current directory to DIR. The default DIR is the value of the
HOME shell variable.
The variable CDPATH defines the search path for the directory containing
DIR. Alternative directory names in CDPATH are separated by a colon (:).
A null directory name is the same as the current directory. If DIR begins
with a slash (/), then CDPATH is not used.
If the directory is not found, and the shell option `cdable_vars' is set,
the word is assumed to be a variable name. If that variable has a value,
its value is used for DIR.
Options:
-L force symbolic links to be followed: resolve symbolic links in
DIR after processing instances of `..'
-P use the physical directory structure without following symbolic
links: resolve symbolic links in DIR before processing instances
of `..'
-e if the -P option is supplied, and the current working directory
cannot be determined successfully, exit with a non-zero status
-@ on systems that support it, present a file with extended attributes
as a directory containing the file attributes
The default is to follow symbolic links, as if `-L' were specified.
`..' is processed by removing the immediately previous pathname component
back to a slash or the beginning of DIR.
Exit Status:
Returns 0 if the directory is changed, and if $PWD is set successfully when
-P is used; non-zero otherwise.
```
>cd --help
短说明
```
bash: cd: --: invalid option
cd: usage: cd [-L|[-P [-e]] [-@]] [dir]
```
>apropos ls
匹配关键字
等价于man -k ls
```
SSL (3ssl) - OpenSSL SSL/TLS library
_llseek (2) - reposition read/write file offset
aconnect (1) - ALSA sequencer connection manager
add-shell (8) - add shells to the list of valid login shells
afInitChannels (3) - initialize audio data format for a track in an audio f...
afOpenFile (3) - open an audio file and create a file handle structure ...
afs_syscall (2) - unimplemented system calls
afSetVirtualChannels (3) - set the virtual data format for a track in an audi...
afSetVirtualSampleFormat (3) - set the virtual data format for a track in an ...
alsabat (1) - command-line sound tester for ALSA sound card driver
alsactl (1) - advanced controls for ALSA soundcard driver
alsactl_init (7) - alsa control management - initialization
alsaloop (1) - command-line PCM loopback
alsamixer (1) - soundcard mixer for ALSA soundcard driver, with ncurse...
amidi (1) - read from and write to ALSA RawMIDI ports
amixer (1) - command-line mixer for ALSA soundcard driver
aplay (1) - command-line sound recorder and player for ALSA soundc...
...
```
# linux系统基础操作
## linux思想:一切皆文件
|颜色属性|白|蓝|浅蓝|绿|红|红色闪烁|黄|灰|
|---|---|---|---|---|---|---|---|---|---|
|文件类型|普通文件|目录|链接文件|可执行文件|压缩文件|链接有问题文件|设备文件|其他文件|
```
解析例如:
档案类型权限 连节数 档案拥有者 档案所属群组 文件大小 档案最后被修改时间 档名
-rw-r--r-- 1 Teenie Teenie 3803 6月 24 21:43 .bashrc
```
文件类型标记方法:
|首位|类型|举例|文件举例|
|---|---|---|---|
|-|普通文件|文本文件、二进制文件|a.c , 1.txt , a.out , test1.sh ,bbbb.txt-hard看不出类型的文本硬链接|
|d|文件夹||cache/|
|l|符号链接文件|后面会用->打印出它指向的文件|ln -s src.c linker.c<br>linker.c就是src.c的一个符号链接文件<br>lrwxrwxrwx 1 root root 3 .... linker.c -> src.c|
|s|socket文件||
|p|管道文件|||
|文件权限|含义|
|---|:---:|
|r|可读|
|w|可写|
|x|可执行|
|-|空权限,没有权限<br>不可执行Permission denied|
|文件目录结构|内容|
|---|---|
|bin|存储二进制**可执行命令文件**(绿色)|
|root|**root超级用户**,即根用户的主目录|
|home|**普通用户**的默认家目录,每个普通用户拥有一个以用户名命名的文件夹|
|mnt|**可移除设备挂载点**。例如:光驱。共享文件夹目录/mnt/ghfs/|
|media|可移除设备|
|etc|**配置文件和目录**<br>/etc/crontab写脚本或定时运行一些任务,有定时设置。<br>/etc/fstab系统挂载的磁盘ID<br>**/etc/passwd所有用户的账号密码**|
|proc|操作系统正在运行进程的文件列表。可用“file 文件名”去查看用途|
|lib|存储各种程序所需要的**共享库文件**|
|opt|optional可选的,第三方软件可安装至此|
|boot|存放ubuntu内核和**系统启动文件**<br>/boot/grub/grub.conf or menu.lst,被用来配置启动加载程序。<br>/boot/vmlinuz,Linux 内核|
|var|用于存放很多不断变化的文件,例如日志文件等。<br>/var/log 目录包含日志文件、各种系统活动的记录。<br>这些文件非常重要,并且 应该时时监测它们。|
|tmp|存储系统和用户的临时信息|
|user|包括与系统用户直接有关的文件和目录|
|sbin|系统命令的存储位置|
- linux文件存储
至少包括两部分,(1)文件数据本身(2)文件原数据
原数据包括:文件属性(创建时间、修改时间、所有者、权限、文件名)。
这些原数据链接到了数据块本身,所以**本身就是一个硬链接**。
当硬链接数量比1少时,文件就被删除了。
|类型|硬链接|软链接|
|------|---|---|
|局限性|**不能指向到目录**<br>有 ln file link无ln directory link<br>文件和链接文件不能位于不同设备|符号链接:链接、原文件。删除链接,原文件不受影响。<br>删除原文件则链接文件指向空,野指针,在操作系统有红色显示|
|外观|硬链接在ls命令下是看不出区别的。|符号链接课看出符号指向<br>sbin->usr/sbin|
## 探索操作系统状态
>date
显示系统当前时间和日期
This command displays the current time and date.
```
2019年 06月 30日 星期日 18:21:15 CST
```
>cal
显示当前月份的日历
A related command is cal which, by default, displays a **calendar** of the current month.
```
六月 2019
日 一 二 三 四 五 六
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
```
>exit
结束终端会话
We can end a terminal session by either closing the terminal emulator window, or by entering the exit command at the shell prompt:
>file filename
确定文件类型
>file ~/.bashrc
/home/Teenie/.bashrc: ASCII text
## linux文件系统跳转
|命令|全英文|用法|
|---|:---:|:---:|
|pwd|Print name of current working directory<br>打印出当前工作的绝对路径|pwd **我是谁?我在哪?**|
|ls|List directory contents<br>列出目录内容|ls<br>什么都不跟,查看当前目录资料<br>ls /dev<br>查看指定路径下资料<br>|
|cd|Change directory<br>更改目录|cd <br>什么都不跟,回到家目录<br>cd ~username<br>回到某用户家目录<br>cd -<br>切换到前一个操作目录<br>cd Teenie/<br>切换到指定路径下目录|
>[Teenie@wutiantian.github.io ~]$ pwd
/home/Teenie
普通用户根目录的工作目录名:在home目录下的该用户名地址下。
>ls
|常用选项|长选项|作用|举例|
|---|---|---|---|
|-a|--all|列出目录下的所有内容,包括隐藏的|
|-d|--directory|该目录本身的信息(单)行|ls -ld /usr<br>drwxr-xr-x. 13 root root 155 6月 30 03:28 /usr
|-F|--classify|文件或者目录名字后加一个字符的分类标识|/目录,例如opt/; @链接,例如 bin@|
|-h|--human-readable|可读模式|将**容量**4096转为4.0k,<br>避免太大数字不能直观看出多大|
|-l|long长格式输出||
|-r|--reverse|反序,字母**降序排列文件夹**|
|-t|--time|按修改日期排序|
>cd Teenie/
切换到当前路径下的Teenie文件夹目录路径下
在几乎所有的情况下,你**可以省略”./”。它是隐含的**。
To change your working directory (where we are standing in our tree-shaped maze) we use the cd command. To do this, type cd followed by the pathname of the desired working directory. A pathname is the route we take along the branches of the tree to get to the directory we want. Pathnames can be specified in one of two different ways; as absolute pathnames or as relative pathnames. Let’s deal with absolute pathnames first.
|路径的两种方式|特征|
|---|---|
|相对路径|用**一对特殊符号**来表示相对位置:符号 “.” 指的是工作目录,”..” 指的是工作目录的父目录|
|绝对路径|**根目录开头**的“/”开始,直到它的目的地|
>cd ..
切换到上一级目录
## 操作文件和目录
|命令|含义|示例|
|---|---|---|
|mkdir|make directory|mkdir dir1<br>mkdir dir1 dir2 dir3|
|cp|copy|cp item1 item2 把单个文件item1复制成item2<br>cp item... directory 复制多个item文件/文件夹到directory文件夹|
|mv|move|移动、重命名文件|
|rm|remove|-i交互咨询;<br>-r递归;<br>-f,--force ;<br>-v,--verbose,explain what is being done。<br>rm file1 <br> 默默地删除文件<br>rm -i file1 <br> 除了在删除文件之前,提示用户确认信息之外,和上面的命令作用一样。<br>rm -r file1 dir1 <br> 删除文件 file1, 目录 dir1,及 dir1 中的内容。<br>rm -rf file1 dir1 <br> 除了如果文件 file1,或目录 dir1 不存在的话,rm 仍会继续执行。||
|ln|link|ln file link创建硬链接;<br>ln bbb.txt bbb.txt-hard<br>ln -s item link创建符号链接<br>ln -s fun fun-sym|
附:**item 表示文件或目录**
>cp /etc/passwd .
将用户账户密码拷贝至当前目录
>cp -v /etc/passwd .
"/etc/passwd"->"./passwd"
显示操作过程
>cp -i /etc/passwd .
cp:是否覆盖"./passwd"?
>cp a passwd dir1
将a与passwd文件,复制到dir1文件夹中
|cp短选项|长选项|意义|
|---|:---:|:---:|
|-a|--archive|**复制文件和目录,以及它们的属性**,包括所有权和权限。 通常,副本具有用户所操作文件的默认属性。|
|-i|--interactive|在**重写已存在文件之前,提示用户确认**。如果这个选项不指定, cp 命令会默认重写文件。|
|-r|--recursive|**递归地复制目录及目录中的内容**。当复制目录时, 需要这个选项(或者-a 选项)。|
|-u|--update|当把文件从一个目录复制到另一个目录时,**仅复制**目标目录中不存在的文件,或者是文件内容新于目标目录中已经存在的文件。|
|-v|--verbose|显示翔实的**命令操作信息**|
|mv短选项|长选项| 意义|
|---|---|---|
|-i| --interactive | 在重写一个已经存在的文件之前,**提示用户确认信息**。 如果不指定这个选项,mv 命令会默认重写文件内容。|
|-u| --update| 当把文件从一个目录移动另一个目录时,只是移动不存在的文件, 或者文件内容新于目标目录相对应文件的内容。|
|-v| --verbose | 当操作 mv 命令时,显示翔实的操作信息。|
## 文本处理
文本处理用处:文档、网页、电子邮件、打印输出、程序源代码
- 排序
|排序命令|功能|
|---|---|
|cat|连接文件并且打印到标准输出|
|sort|给文本行排序,结果发送到标准输出|
|uniq|报告或者省略重复行|
|cat选项|功能|
|---|---|
|-A|打印文本文档中的非打印字符|
|-n|number增加行号在文本中|
|-s|合并多余空行。3个连续空行变为1个|
|非打印字符|名称|显示效果|
|---|---|---|
|enter|回车键|$|
|tab|制表键|^I|
|space|空格||
>cat -A hello.c
打印 hello.c 文本文档中的非打印字符,让人更明了程序排版
```
#include<stdio.h>$
int main(void)$
{$
printf("hello world");$
return 0;$
} $
```
sort 程序对标准输入的内容,或命令行中指定的一个或多个文件进行排序,然后把排序 结果发送到标准输出。
使用与 cat 命令相同的技巧,我们能够演示如何用 sort 程序来处理标准输入
```
sort >foo.txt
c
a
b
Ctrl-d 组合键来表示文件的结尾
cat foo.txt
a
b
c
看到文本行有序地显示
```
sort 程序能接受命令行中的多个文件作为参数,所以有可能把多个文件合并成一个有序的文件。
例如, 如果我们有三个文本文件,想要把它们合并为一个有序的文件。
>sort file1.txt file2.txt file3.txt > final_sorted_list.txt
|sort 程序选项|长选项 | 功能|
|---|---|---|
|-b|--ignore-leading-blanks|默认情况下,对整行进行排序,从每行的第一个字符开始。这个选项导致 sort 程序**忽略** 每行开头的**空格**,从第一个非空白字符开始排序。|
|-f|--ignore-case | 让排序不区分大小写。|
|-n | --numeric-sort | 基于字符串的数值来排序。使用此选项允许根据数字值执行排序,而不是字母值。
|-r | --reverse | 按相反顺序排序。结果按照**降序排列**,而不是升序。
|-k | --key=field1[,field2]<br>偏量| 根据**字段排序**|
|-m | --merge | 把每个参数看作是一个预先排好序的文件。把多个文件合并成一个排好序的文件,而没有执行额外的排序。
|-o | --output=file | 把排好序的输出结果发送到文件,而不是标准输出。
|-t| --field-separator=char| 定义域**分隔字符**。默认情况下,域由空格或制表符分隔。
>du -s /usr/share/* |sort -nr |head
查看磁盘中目录,哪个文件夹占用磁盘空间大,数字逆序排列前十个
```
245984 /usr/share/fonts
122532 /usr/share/icons
114424 /usr/share/doc
89328 /usr/share/help
82640 /usr/share/libreoffice
60556 /usr/share/pyzy
55588 /usr/share/app-install
42228 /usr/share/mythes
41496 /usr/share/fcitx-sogoupinyin
39692 /usr/share/man
```
|uniq 选项|功能|
|---|---|
|-c|输出所有的重复行,并且每行开头显示重复的次数。|
|-d|只输出重复行,而不是特有的文本行。|
|-f n|忽略每行开头的 n 个字段,字段之间由空格分隔,正如 sort 程序中的空格分隔符;然而, 不同于 sort 程序,uniq 没有选项来设置备用的字段分隔符。|
|-i|在比较文本行的时候忽略大小写。|
|-s n|跳过(忽略)每行开头的 n 个字符。|
|-u|只输出独有的文本行。这是默认的。|
- 切片
|命令|功能|例子|
|---|---|---|
|cut|裁剪,从文件里取东西|cut -f 2,2 linux-by-date.txt >linux-vernums.txt|
|paste|**合并**文件文本行<br>通过读取多个文件,然后把每个文件中的字段整合成单个文本流,输入到标准输出。|paste linux-dates.txt linux-names.txt >linux-key-names.txt|
|join|往文件里加东西|join linux-key-names.txt linux-key-vernums.txt|
- 比较
|查看差异命令|功能|例子|
|---|---|---|
|comm|逐行比较两个有序的文件<br>compare|
|diff|逐行比较文件或目录<br>different<br>**如何把文件1编程文件2**|
|patch|把更改应用到原始文档中去|diff -Naur old_file new_file >patchfile.txt<br>patch < patchfile.txt|
<br>
|diff三种模式|模式内容|示例|
|---|---|---|
|normal|描述要求更改的位置和类型|
|context|上下文模式。信息有冗余|-删除行<br>+增加行<br>!更改行|
|unin|统一模式|空格:两个文件都包含这一行<br>-:在第一个文件中删除这一行<br>+:添加这一行到第一个文件中|
```
cat file1.txt
a
b
c
d
cat file2.txt
b
c
d
e
comm file1.txt file2.txt
a
b
c
d
e
1特 2特 共有
comm -12 file1.txt file2.txt
b
c
d
隐藏12列
diff file1.txt file2.txt
1d0 如何把file1改成file2.txt?
< a 删除d第一行的a
4a4 把第2个文件的第4行
> e 加上e
diff -c file1.txt file2.txt
context模式
*** file1.txt
--- file2.txt
*************
*** 1,4 *****
-a
b
c
d
--- 1,4 -----
b
c
d
+e
diff -u file1.txt file2.txt
unin 统一模式
---file1.txt
+++file2.txt
@@-1,4,+1,4@@
-a
b
c
d
+e
```
- 运行时编辑
The tr program is used to transliterate characters.
tr 程序被用来更改字符。我们可以把它看作是一种基于字符的查找和替换操作。
|命令|功能|例子|
|---|---|---|
|tr|search/replace查找与替换|tr char_set1 char_set2<br>在第一个字符集里查找,替换成第2个字符集内容|
|charset三种模式|内容|
|---|---|
|list枚举|abcdefghijklmnop|
|field域|a-z or A-Z or 0-9|
|POSIX|[:lower:][:upper:]
## 停止
|停止的快捷键|功能|例子|
|---|---|---|
|ctrl+z|将任务中止(暂停的意思),但是此任务并没有结束。<br>他仍然在进程中他只是**维持挂起的状态**,<br>用户可以使用fg/bg操作继续前台或后台的任务,<br>fg命令重新启动前台被中断的任务,<br>bg命令把被中断的任务放在后台执行.|当你vi一个文件是,如果需要用shell执行别的操作,<br>但是你又不打算关闭vi,<br>因为你得存盘退出,<br>你可以简单的按下ctrl+z,<br>shell会将vi进程挂起,<br>当你结束了那个shell操作之后,<br>你可以用fg命令继续vi你的文件。|
|ctrl+c|强制中断程序的执行,**进程**已经**终止**。|
|ctrl+d| 不是发送信号,而是表示一个特殊的二进制值,表示 EOF。<br>在shell中,**ctrl-d表示退出当前shell**|
## 权限
Linux 系统有**多用户**性能。
为了使多用户特性付诸实践,那么必须发明一种方法来阻止用户彼此之间受到影响。
毕竟,**一个用户的行为不能导致计算机崩溃,也不能乱动属于另一个用户的文件。**
|命令|详解|示例|
|---|---|---|---|
|id |Display user identity<br>显示**当前用户身份**号|#id|
|chmod|Change a file’s mode<br>更改**已经存在的文件模式**|支持两种不同的方法来改变文件模式:八进制数字表示法或 符号表示法。|
|umask|Set the default file permissions<br>设置默认的**新创建文件权限**|umask 0002<br>默认权限减2|
|chown|Change a file’s owner<br>更改文件**所有者**|
|chgrp|Change a file’s group ownership<br>更改文件**组所有权**|
|su|Run a shell as another user<br>以另一个用户的**身份**来运行 shell|
|sudo|Execute a command as another user<br>以另一个用户的**身份**来执行命令|
|passwd|Change a user’s password<br>更改**用户密码**|passwd [user]
在 Unix 术语中,每个人 是指整个世界。可以**用 id 命令,来找到关于你自己身份的信息**
>id
uid=1000(teenie) gid=1000(teenie) groups=1000(teenie),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),113(lpadmin),128(sambashare)
|id组的字符|含义|||||
|---|---|---|---|---|---|
|u|g|o|a|||
|owner<br>user|group|other|all=user+group+other|||
uid 从1000开始变号
|属性|文件(直观)|目录(不直观,需记忆)|
|---|---|---|
|r|允许打开并读取文件内容|允许列出目录中的内容,<br>前提是目录必须设置了可执行属性(x)|
|w|允许写入文件内容或截断文件。<br>但不允许对文件进行重命名或删除,<br>重命名或删除是由目录的属性决定的|允许在目录下新建、删除或重命名文件,<br>前提是目录必须设置了可执行属性(x)|
|x|允许将文件作为程序来执行,使用脚本语言编写的程序必须设置为可读才能被执行|允许进入目录,例如:cd directory|
权限的基础组合值
|Octal|Binary|File Mode|
|---|---|---|---|
|1|001|--x|execute|
|2|010|-w-|write|
|4|100|r--|read|
八进制有8种组合,对以上三种进行组合相加赋值即可。
- 对于脚本文件,有两个常见的权限设置
|脚本权限值|功能|
|---|---|
|755|每个人都能执行|
|700|只有文件所有者能够执行|
注意:为了能够**执行脚本文件**,脚本必须是**可读的**。
>chmod
```
chmod gu=rw foo.txt
组权限赋值
chmod o-x foo.txt
减去other组的x可执行功能
chmod 755 foo.txt
把文件的权限设为755
```
## 软件安装管理
**软件包管理工具:系统中,一种安装和维护软件的方法**
如果我们花些时间在 Linux 社区里,我们会看到很多像Linux发行版中哪一个是“最佳”之类的观点。 这些讨论通常非常可笑,集中在一些像桌面背景的漂亮程度(一些人不使用 Ubuntu, 只是因为 Ubuntu 默认主题颜色是棕色的!)和其它的琐碎东西上。
Linux 发行版本质量最重要的决定因素是软件包管理系统和其支持社区的持久性。随着我们 花更多的时间在 Linux 上,我们会发现它的变化是非常快的。大多数一线 Linux 发行版每隔六个月发布一个新版本,并且许多独立的程序每天都会更新。为了能和这些 如暴风雪一般多的软件保持联系,我们需要一些好工具来进行软件包管理。
**选择 linux 发行版的重要指标:软件包管理**
|该发行版是否有|
|---|
|1.好用的软件包管理系统|
|2.丰富的软件包使用|
|3.持久的社区维护更新|
对于早期 linux 用户,人们需下载和编译源代码来安装软件。
**如果有预先编译好的软件包,使用起来相对容易和快速一些**
拥有对软件源代码的访问权限是linux的伟大之处,它赋予每个人定制和优化系统权利。
|包管理两大阵营|发行版(部分列表)|包管理底层工具|包管理上层工具|
|---|---|---|---|
|.deb|Debian , Ubuntu|dpkg|apt-get, aptitude|
|.rpm|Fedora , CentOS , Red Hat , OpenSUSE |rpm|rpm|
以 ubuntu16为例:
- 查找安装
命令 子命令 包名
apt install git
apt 命令首先分析 git 依赖关系,这就是包管理的好处.
如果程序发现缺少了一个依赖,则会报错并退出。
```
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following packages were automatically installed and are no longer required:
libllvm5.0 snapd-login-service
Use 'apt autoremove' to remove them.
Suggested packages:
git-daemon-run | git-daemon-sysvinit git-doc git-el git-email
git-gui gitk gitweb git-arch git-cvs git-mediawiki git-svn
The following NEW packages will be installed:
git
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 3,176 kB of archives.
After this operation, 24.1 MB of additional disk space will be used.
Get:1 http://mirrors.tuna.tsinghua.edu.cn/ubuntu xenial-updates/main amd64 git amd64 1:2.7.4-0ubuntu1.6 [3,176 kB]
Fetched 3,176 kB in 3s (878 kB/s)
Selecting previously unselected package git.
(Reading database ... 241828 files and directories currently installed.)
Preparing to unpack .../git_1%3a2.7.4-0ubuntu1.6_amd64.deb ...
Unpacking git (1:2.7.4-0ubuntu1.6) ...
Setting up git (1:2.7.4-0ubuntu1.6) ...
```
- 卸载
命令 子命令 包名
apt remove git
y
```
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following packages were automatically installed and are no longer required:
liberror-perl libllvm5.0 snapd-login-service
Use 'apt autoremove' to remove them.
The following packages will be REMOVED:
git git-core
0 upgraded, 0 newly installed, 2 to remove and 0 not upgraded.
After this operation, 24.1 MB disk space will be freed.
Do you want to continue? [Y/n] y
(Reading database ... 242467 files and directories currently installed.)
Removing git-core (1:2.7.4-0ubuntu1.6) ...
Removing git (1:2.7.4-0ubuntu1.6) ...
```
- 更新
apt update 更新源
更新已安装的包
命令 子命令 包名
apt upgrade git
```
Reading package lists... Done
Building dependency tree
Reading state information... Done
git is already the newest version (1:2.7.4-0ubuntu1.6).
Calculating upgrade... Done
The following packages were automatically installed and are no longer required:
libllvm5.0 snapd-login-service
Use 'apt autoremove' to remove them.
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
```
- 显示包信息
知道包名后,要显示软件包的详细信息,例如:版本号、大小、校验值和软件描述等信息时。
apt-cache show firefox
```
Package: firefox
Architecture: amd64
Version: 67.0.4+build1-0ubuntu0.16.04.1
Priority: optional
Section: web
Origin: Ubuntu
...
```
列出所有已经安装的软件包
apt list --installed
```
Listing... Done
a11y-profile-manager-indicator/xenial,xenial,xenial,now 0.1.10-0ubuntu3 amd64 [installed]
account-plugin-facebook/xenial,xenial,xenial,xenial,xenial,xenial,now 0.12+16.04.20160126-0ubuntu1 all [installed]
...
firefox/xenial-updates,xenial-security,xenial-updates,xenial-security,xenial-security,xenial-updates,now 67.0.4+build1-0ubuntu0.16.04.1 amd64 [installed]
...
```
PS:**aptitude**与 apt-get 一样,是 Debian 及其衍生系统中功能极其强大的包管理工具。
与 apt-get 不同的是,aptitude在处理依赖问题上更佳一些。
## 编译程序make
编译就是把源码(一个由程序员编写的人类可读的程序的说明)翻译成计算机处理器的语言的过程。
ubuntu16 下,编译一个叫做 diction 的程序,来自 GNU 项目。步骤:
(1)安装**编译器**
>sudo apt install ftp gcc
安装 ftp 与 gcc 两个文件。
(2)获取**源代码**
>ftp ftp.gnu.org
```
Connected to ftp.gnu.org.
220 GNU FTP server ready.
Name (ftp.gnu.org:root): anonymous
230-NOTICE (Updated October 13 2017):
...
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
...
-rw-r--r-- 1 0 0 2925 Apr 04 20:15 README
-rw-r--r-- 1 0 0 405121 Oct 23 2003 before-2003-08-01.md5sums.asc
-rw-rw-r-- 1 0 3003 262986 Jul 05 09:50 find.txt.gz
drwxrwxr-x 320 0 3003 12288 Jun 17 21:54 gnu
drwxrwxr-x 3 0 3003 4096 Mar 10 2011 gnu+linux-distros
-rw-rw-r-- 1 0 3003 483088 Jul 05 09:50 ls-lrRt.txt.gz
drwxr-xr-x 3 0 0 4096 Apr 20 2005 mirrors
lrwxrwxrwx 1 0 0 11 Apr 15 2004 non-gnu -> gnu/non-gnu
...
226 Directory send OK.
ftp> cd gnu/dicition
550 Failed to change directory.
ftp> cd gnu/diction
250 Directory successfully changed.
ftp> ls
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
-rw-r--r-- 1 3003 65534 68940 Aug 28 1998 diction-0.7.tar.gz
-rw-r--r-- 1 3003 65534 90957 Mar 04 2002 diction-1.02.tar.gz
-rw-r--r-- 1 3003 65534 141062 Sep 17 2007 diction-1.11.tar.gz
-rw-r--r-- 1 3003 65534 189 Sep 17 2007 diction-1.11.tar.gz.sig
226 Directory send OK.
ftp> get diction-1.11.tar.gz
local: diction-1.11.tar.gz remote: diction-1.11.tar.gz
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for diction-1.11.tar.gz (141062 bytes).
226 Transfer complete.
141062 bytes received in 1.99 secs (69.1985 kB/s)
ftp> bye
221 Goodbye.
此时根目录下多了个压缩包
diction-1.11.tar.gz
```
解压缩文件
>tar xzf diction-1.11.tar.gz
(3)查看代码
*.c与*.h文件
(4)编译**预处理**
执行 configure 预处理文件=>产生 makefile脚本文件
>./configure
(5)**编译**程序
>make
执行命令 make 会直接找 makefile=>创建很多 .o 文件
(6)**安装**程序
>sudo make install
(7)**查看**程序**是否安装好**
> which diction
/usr/local/bin/diction
|编译原因|内容|
|---|---|
|可用性|有些发行版不包含所有程序|
|即时性|获得最新版本程序|
# shell眼中看世界——“展开”
当按下 enter 键后,发生在命令行中的一些“魔法”,这种**魔法**就是**展开的过程**。
## 字符展开
>echo *
打印出当前目录下的所有文件夹名,不会显示隐藏文件。
当回车键被按下时,shell 在命令被执行前在命令行上自动展开任何符合条件的字符, 所以 echo 命令的实际参数并不是”*“,而是它展开后的结果。
## 路径名展开
>echo /usr/*/share
```
/usr/kerberos/share /usr/local/share
```
通配符所依赖的工作机制叫做路径名展开。
## 波浪线展开
波浪线字符(“~”)有特殊的含义。
>[Teenie@wutiantian.github.io ~]$ echo ~teenie
/home/teenie
当它用在 一个单词的开头时,它会展开成指定用户的家目录名,如果没有指定用户名,则展开成当前用户的家目录
## 算术表达式展开
shell 在展开中执行算数表达式。当作计算器来使用。
算术表达式展开使用这种格式:
>$((expression))
表达式是指算术表达式,它由数值和算术操作符组成。
**注意:美元符号不能丢掉!**
例如
>echo $((2+2))
4
算术表达式**只支持整数**(全部是数字,**不带小数点**),但是能执行很多不同的操作。
|操作符|说明|
|---|---|
|+| 加|
|-| 减|
|*| 乘|
|/| 除(但是记住,因为展开只是支持整数除法,所以结果是整数。)|
|%| 取余,只是简单的意味着,“余数”|
|**| 取幂|
在算术表达式中**空格并不重要**,并且**表达式可以嵌套**。例如,5的平方乘以3:
注意:嵌套的$与括号切不可少!否则报错!!!
```
echo $(($((5**2))*3))
75
echo with $((5%2)) left over.
with 1 left over.
```
## 花括号展开
这种模式不能 嵌入空白字符。
花括号展开可以嵌套。
```
花括号的模式中 创建多个文本字符串。
echo Front-{A,B,C}-Back
Front-A-Back Front-B-Back Front-C-Back
echo Number_{1..5}
Number_1 Number_2 Number_3 Number_4 Number_5
使用了一个整数区间
echo {Z..A}
Z Y X W V U T S R Q P O N M L K J I H G F E D C B A
倒序排列的字母区间
echo a{A{1,2},B{3,4}}b
aA1b aA2b aB3b aB4b
花括号展开可以嵌套
```
## 参数展开
**参数展开特性在 shell 脚本中比直接在命令行中更有用。**
存储小块数据,并给每块数据命名的能力有关系。许多像这样的小块数据, 更恰当的称呼应该是变量,可供你方便地检查它们。
```
"USER"的变量包含你的用户名。可以这样做来调用参数,并查看 USER 中的内容
echo $USER
teenie
查看有效的变量列表
printenv |less
```
**其它展开类型中,如果你误输入一个字符,展开就不会发生**。
这时 echo 命令只简单地显示误键入的模式。
但在参数展开中,如果你拼写错了一个变量名, 展开仍然会进行,只是展开的结果是一个空字符串。
## 命令(展开)替换
命令替换允许我们把一个命令的**输出作为一个展开模式来使用**
```
ls -l $(which cp)
-rwxr-xr-x 1 root root 151024 3月 3 2017 /bin/cp
把 which cp 的执行结果作为一个参数传递给 ls 命令,因此可以在不知道 cp 命令 完整路径名的情况下得到它的文件属性列表。
file $(ls /usr/bin/* | grep zip)
/usr/bin/funzip: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 2.6.32, BuildID[sha1]=06412c648a6927c4a14c751fe2412db3425ecd0f, stripped
/usr/bin/gpg-zip: POSIX shell script, ASCII text executable
...
管道线的输出结果成为 file 命令的参数列表
```
## 引用-控制展开
**shell 提供了一种叫做引用的机制,来有选择地禁止不需要的展开。**
```
echo this is a test
this is a test
shell 利用单词分割删除掉 echo 命令的参数列表中多余的空格
echo The total is $100.00
The total is nu00.00
echo The total is $00.00
The total is bash0.00
echo The total is$100.00
The total isnu00.00
因为 1 是没有定义的变量,参数展开把 $1 的值替换为 nu
echo the winner is $smith
the winner is
```
## 引用-双引号-限制部分展开
把文本放在双引号中, shell 使用的**特殊字符,都失去它们的特殊含义,被当作普通字符来看待**。
有几个例外: $,\ (反斜杠),和 `(倒引号)。
这意味着单词分割、路径名展开、 波浪线展开和花括号展开都将失效,然而**参数展开、算术展开和命令替换 仍然执行**。
使用双引号,我们可以**处理包含空格的文件名。**
```
比方说我们是不幸的 名为 two words.txt 文件的受害者。
如果我们试图在命令行中使用这个 文件,单词分割机制会导致这个文件名被看作两个独自的参数,而不是所期望 的单个参数:
ls -l two words.txt
ls: cannot access two: No such file or directory
ls: cannot access words.txt: No such file or directory
使用双引号,我们可以阻止单词分割,得到期望的结果;
进一步,我们甚至可以修复 破损的文件名。
ls -l "two words.txt"
-rw-rw-r-- 1 me me 18 2008-02-20 13:03 two words.txt
mv "two words.txt" two_words.txt
```
记住,在双引号中,参数展开、算术表达式展开和命令替换仍然有效:
```
echo "$USER$((2+2))"
teenie4
```
单词分割机制会在单词中寻找空格,制表符,和换行符,并把它们看作 单词之间的界定符。
这意味着无引用的空格,制表符和换行符都不是文本的一部分, 它们只作为分隔符使用。
```
echo "this is a test"
this is a test
```
单词分割被禁止,内嵌的空格也不会被当作界定符,它们成为参数的一部分。
一旦加上双引号,我们的命令行就包含一个带有一个参数的命令。
```
单词分割机制把换行符看作界定符,对命令替换产生了一个虽然微妙但有趣的影响
echo $(cal)
六月 2019 日 一 二 三 四 五 六 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
echo "$(cal)"
六月 2019
日 一 二 三 四 五 六
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
命令行只有一个参数,参数中包括嵌入的空格和换行符。
```
## 引用-单引号-禁止展开
如果需要禁止所有的展开,我们要使用单引号。以下例子是无引用,双引号,和单引号的比较结果
```
echo text ~/*.txt {a,b} $(echo foo) $((2+2)) $USER
text /home/teenie/*.txt a b foo 4 teenie
echo "text ~/*.txt {a,b} $(echo foo) $((2+2)) $USER"
text ~/*.txt {a,b} foo 4 teenie
echo 'text ~/*.txt {a,b} $(echo foo) $((2+2)) $USER'
text ~/*.txt {a,b} $(echo foo) $((2+2)) $USER
```
## 转义字符
**如果没有准确地理解展开模式,shell 总是神秘和混乱的源泉,并且 shell 潜在的能力也 浪费掉了。**
只想引用单个字符。
**在字符之前加上一个反斜杠,叫做转义字符。**
经常在双引号中使用转义字符,来**有选择地阻止展开**。
使用转义字符来*消除文件名中一个字符的特殊含义*,是很普遍的。
这些字符包括”$”, “!”, “ “等字符。
```
echo "The balance for user $USER is: \$5.00"
The balance for user teenie is: $5.00
防止美元符号展开
```