Linux入门笔记(4/1/2016修改)

本文笔记源自这里——[实验楼]
欢迎大家在下面交流其中有问题的地方喜欢请点收藏,每日更新(全部已亲自实践).

一. linux终端

1. 终端(Terminal)和控制台(Console)是有区别的:

终端本质上是对应着Linux上的/dev/tty设备,linux的多用户登陆就是通过不同的/dev/tty设备完成的,Linux默认提供了6个纯命令行界面的"terminal"(准确的说这里应该是6个virtual consoles)来让用户登录,你可以通过使用[Ctrl]+[Alt]+[F1]~[F6]进行切换,不过在在线实验环境中可能无法切换,因为特殊功能按键会被你主机系统劫持。当你切换到其中一个终端后想要切换回图形界面,你可以按下[Ctrl]+[Alt]+[F7]来完成

2. Shell

Shell是指“提供给使用者使用界面”的软件(命令解析器),类似于DOS下的command(命令行)和后来的cmd.exe。之所以被称作shell是因为它隐藏了操作系统底层的细节。就像是个Shell(壳),有壳就有核,这里的核就是指的UNIX/Linux内核。同样的Unix/Linux下的图形用户界面GNOME和KDE,有时也被叫做“虚拟shell”或“图形shell”(这里我查了下 Ubuntu下默认是bash,Deepin下默认是zsh)

3. 重要快捷键(只列举我感觉常用的)

按键 作用
Tab 进行命令补全
Ctrl+c 强行终止当前程序(最常用,你可以放心它并不会使终端退出)
Ctrl+d 这个才是强制退出终端的(不用敲exit了)
Ctrl+s 暂定当前程序,暂停后按下任意键恢复运行(网络交互有用)
Ctrl+z 将当前程序放到后台运行,恢复到前台为命令fg
Ctrl+u 删除光标所在的整行
Ctrl+q 删除光标所在的整行(保留当前输入)
Ctrl+k 删除从光标所在位置到行末
Alt+Backspace 向前删除一个单词
Shift+PgUp 将终端显示向上滚动
Shift+PgDn 将终端显示向下滚动(知道了以上这些命令几乎可以放弃鼠标了

4. 使用通配符

举例:

$ touch love_{1..10}_linux.txt

__1.一次性创建一些这样的文件“love_1_linux.txt, love_2_linux.txt,... love_10_linux.txt”2.模糊匹配(通配)__

shell常用通配符:

通配符 含义
* 匹配 0 或多个字符
? 匹配任意一个字符
[list] 匹配 list 中的任意单一字符
[!list] 匹配 除list 中的任意单一字符以外的字符
[c1-c2] 匹配 c1-c2 中的任意单一字符 如:[0-9] [a-z]
{string1,string2,...} 匹配 sring1 或 string2 (或更多)其一字符串
{c1..c2} 匹配 c1-c2 中全部字符 如{1..10}

二. Linux用户管理

1.关于我是谁?(即查看当前用户)

看好了哈,请打开终端,输入命令:

$ who am i // deepin 中输入who即可

__ubuntu__

第一列表示打开当前伪终端的用户的用户名(要查看当前登录用户的用户名,去掉空格直接使用whoami即可),第二列的pts/0中pts表示伪终端,所谓伪是相对于/dev/tty设备而言的,还记得上一节讲终端时的那七个使用[Ctrl]+[Alt]+[F1]~[F7]进行切换的/dev/tty设备么,这是“真终端”,伪终端就是当你在图形用户界面使用/dev/tty7时每打开一个终端就会产生一个伪终端,pts/0后面那个数字就表示打开的伪终端序号,你可以尝试再打开一个终端,然后在里面输入who am i,看第二列是不是就变成pts/1了,第三列则表示当前伪终端的启动时间

2.关于我从哪里来?(新建、切换用户)

新建一个叫lilei的用户:

$ sudo adduser lilei

__按照提示输入密码然后一直回车即可__

现在你创建好一个用户,你可以使用你 创建的用户登录了,使用如下命令切换登录用户( -l 即 login)

$ su -l lilei

3. 将其它用户加入sudo用户组

使用usermod命令可以为用户添加用户组,同样使用该命令你必需有root权限,你可以直接使用root用户为其它用户添加用户组,或者用其它已经在sudo用户组的用户使用sudo命令获取权限来执行该命令
这里我用shiyanlou用户执行sudo命令将lilei添加到sudo用户组,让它也可以使用sudo命令获得root权限

$ su shiyanlou
$ groups lilei
$ sudo usermod -G sudo lilei
$ groups lilei

然后你再切换回lilei用户,现在就可以使用sudo获取root权限了。

三、linux文件权限

1. 查看文件权限

使用较长格式列出文件

$ ls -l

__ls -l命令__


文件类型

关于文件类型,这里有一点你必需时刻牢记linux里面一切皆文件,正因为这一点才有了设备文件( /dev目录下有各种设备文件,大都跟具体的硬件设备相关)这一说,还有socket(网络套接字),和pipe(管道,这个东西很重要)

2.变更文件所有者

前面提到过,如果你的兄弟姐妹想把你的艾派德据为己有,要是这种事真的发生了,那么我也告诉你如何把他们的爱疯嗯6抢过来
不信的话我们可以来做个小测试,首先打开终端
假设目前是lilei登录,他用他存了半年零花钱买了个爱疯嗯6

$ touch iphone6

瞧你嘚瑟,居然还打上了自己专属标签


__ll命令等同于ls -l命令__

好了他出门,忘记带走他的手机了,先去他房间,准备好下手

$ cd /home/lilei
$ ls iphone6
$ sudo chown shiyanlou iphone6
$ cp iphone6 /home/shiyanlou

然后再来看看爱疯恩6是不是就变成你的了


哈哈,就这么简单,关键就在于那个chown命令。不过,你要干这个的大前提是你得得到你爸妈也就是你家里的上帝(root权限)的同意啊,不然你可干不了这种事.

3.修改文件权限

假设你已经抢过来那部爱疯恩了,正所谓辛苦得来的就倍感珍惜,你想好好保护它,也不想让别人玩它,那么你可以去掉它的读权限,如果你还想让它变成一件收藏品不再开机,那么你可以去掉它的执行权限。下面来告诉你怎么做,这里也还有两种方式:

方式一:加减赋值操作(推荐)

$ chmod go-rw iphone

__'g''o'还有'u',分别表示group,others,user,'+','-'就分别表示增加和去掉相应的权限__
方式二:二进制数字表示(本人不推荐)

二进制懂吧,二进制转十进制懂吧,好吧,不懂也没关系


每个文件的三组权限(拥有者,所属用户组,其他用户,记住这个顺序是一定的哈)就对应这一个"rwx",也就是一个'7',所以如果我要将爱疯恩的权限改为只有我自己可以用那么就这样:
为了演示,我先在文件里加点东西

$ echo "echo "hello shiyanlou"" > iphone6

然后修改权限

$ chmod 600 iphone6
这个“600“分别表示各个位置上00表示组用户和访客用户无权限,6表示没有执行权限(4+2 +0)

正好这时候李雷回来了,他发现爱疯恩已经不属于他了,而且你还不允许他使用,他只有独自郁闷了


四.linux目录结构(快速入门可跳过FHS这部分)

介绍: linux的目录与windows的目录实现机制来说是完全不同的.

  • windows一直是以存储介质为主的,主要以盘符(C盘,D盘...)及分区的来实现文件管理,然后之下才是目录.
  • UNIX是以目录为主的,linux也继承了这一优良特性。linux是以树形目录结构的形式来构建整个系统的,可以理解为一个用户可操作系统的骨架。虽然本质上无论是目录结构还是操作系统内核都是存储在磁盘上的,但从逻辑上来说linux的磁盘是“挂在”(挂载在)目录上的,每一个目录不仅能使用本地磁盘分区的文件系统,也可以使用网络上的文件系统。举例来说,可以利用网络文件系统(Network File System,NFS)服务器载入某特定目录等。这里不能理解的话你可以脑补一下,“一颗挂满各种程序猿的树”的画面,呵呵,我只能说,那画面太美...
1.FPS

Linux目录结构理解起来也简单,因为它其中大部分目录结构是规定好了(FHS标准)

FHS(英文:Filesystem Hierarchy Standard 中文:文件系统层次结构标准)

重要内容:FHS是根据以往无数linux用户和开发者的经验总结出来的,并且会维持更新,FHS依据文件系统使用的频繁与否以及是否允许用户随意改动(注意,不是不能,学习过程中,不要怕这些),将目录定义为四种交互作用的形态,如下表所示:
FHS说了这么多,我也累了,相信我,讲更多你一次也记不住,反正这FHS也是从实际经验中总结出来的,让我们实践从中学习吧

2.路径

使用 cd 命令可以切换目录,在linux里面使用 . 表示当前目录, ..表示上一级目录(**注意,还记得我们上一节介绍过的,以 . 开头的文件都是隐藏文件,所以这两个目录必然也是隐藏的,你可以使用ls -a命令查看隐藏文件), -表示上一次所在目录, 通常表示当前用户的"home"目录。使用 pwd 命令可以获取当前所在路径(绝对路径)
进入你的“home”目录

$ cd ~ //不管现在在哪个目录下 运行这个命令就会回到当前用户的home目录
或者cd /home/<你的用户名>
cd - 返回刚才的目录

绝对路径
关于绝对路径,简单地说就是以根"/"目录为起点的完整路径,以你所要到的目录为终点
相对路径
相对路径,也就是相对于你当前的目录的路径,相对路径是以当前目录为起点(即 . ),以你所要到的目录为终点
提示: 在进行目录切换的过程中请多使用Tab键自动补全,可避免输入错误,连续按两次Tab可以显示全部候选结果

五.linux文件的基本操作(很重要且很常用)

1.新建

  • 新建空白文件(相当于windows中记事本)touch
    举例:
    $ touch test
  • 新建目录(相当于windows中的文件) mkdir
    创建名为"mydir"的空目录:
    $ mkdir mydir
    如下我们同时创建一个多级目录(这在有时候安装软件,配置安装路径时非常有用)
    $ mkdir -p father/son/grandson
__使用`-p`参数,同时创建父目录(若不存在该父目录)
注意相反的删除目录是`rmdir`用法同`mkdir` 递归创建只有这俩命令是`-p`剩下的命令参数一般都是`-r`(recursion)__
__使用`-p`参数,同时创建父目录(若不存在该父目录) 注意相反的删除目录是`rmdir`用法同`mkdir` 递归创建只有这俩命令是`-p`剩下的命令参数一般都是`-r`(recursion)__

2. 复制

  • __ 复制文件__
    cp(copy) 命令复制一个文件或目录到指定目录
    将之前创建的"test"文件复制到"/home/shiyanlou/father/son/grandson"目录中
    $ cp test father/son/grandson
  • __ 复制目录__
    直接使用cp命令复制一个目录的话,会出现错误
    成功复制目录需要加上-r或者-R参数,表示递归复制(Recursion copy),即“株连九族”的意思
    $ cp -r father family

3.删除

  • 删除文件
    rm(remove files or directories)命令,删除一个文件或目录
    $ rm test
    使用-f参数强制删除,忽略有只读权限文件的提示
    $ rm -f test
  • 删除目录(rm或者rmdir)
    类似复制目录,要删除目录,也需要加上-r-R参数
    $ rm -r family

4.移动文件与文件重命名

  • 移动文件(mv移动命令是不需要递归移动的!!!)
    将文件"file1"移动到"Documents"目录:
    $ mv file1 Documents
__ mv 源目录文件 目的目录__
  • 重命名文件rm
    将文件"file1"重命名为"myfile"
    $ mv file1 myfile // mv 旧的文件名 新的文件名
  • 批量重命名 (一般只要掌握mv即可,下面用到了正则表达式)
    更专业的命令rename
    // 先用通配符批量创建5个文件
    $ touch file{1..5}.txt
    //批量将这5个后缀为.txt的文本文件重命名为以.c为后缀的文件
    $ rename 's/.txt/.c/' *.txt
    //批量将这5个文件,文件名改为大写
    $ rename 'y/a-z/A-Z/' *.c

rename先使用第二个参数的通配符匹配所有后缀为.txt的文件,然后使用第一个参数提供的正则表达式将匹配的这些文件的.txt后缀替换为.c,这一点在我们后面学习了sed命令后,相信你会更好的理解。

5.查看文件

  • cat(正序)、tac(倒序)和nl命令查看文件(适用于快速查看文件)
    都是用来打印文件内容到标准输出(终端)

$ cat passwd

可以加上-n参数显示行号

$ cat -n passwd

  • nl命令,添加行号并打印,这是个比cat -n更专业的行号打印砖家
    常用的几个参数

-b : 指定添加行号的方式,主要有两种:
-b a:表示无论是否为空行,同样列出行号("cat -n"就是这种方式)
-b t:只列出非空行的编号并列出(默认为这种方式)
-n : 设置行号的样式,主要有三种:
-n ln:在行号字段最左端显示

-n rn:在行号字段最右边显示,且不加0
-n rz:在行号字段最右边显示,且加0

-w : 行号字段占用的位数(默认为6位)

__你会发现一屏显示不完文本的内容,得用鼠标拖动滚动条或者滑动滚轮才能继续往下翻页,要是可以直接使用键盘操作翻页就好了,那么你就可以使用下面要介绍的命令__
  • 使用more和less命令分页查看文件(阅读大文件)
    打开后默认只显示一屏内容,终端底部显示当前阅读的进度(百分比)。说明:可以单独使用,也可以配合其他命令和管道符使用。按空格键下翻一页,按B键上翻一页,按Q键退出。less命令与more命令类似,但是用pageup键和pagedown键上下箭头实现上下翻页。

6.查看文件类型

在linux下面文件的类型不是根据文件后缀来判断的,我们通常使用file命令可以查看文件的类型

$ file /bin/ls

__这表示这是一个可执行文件,运行在64位平台,并使用了动态链接文件(共享库)__

9.编辑文件

在linux下面编辑文件通常我们会直接使用专门的命令行编辑器比如(emacs,vim,nano)
如果想更加快速的入门,你可以直接使用linux内部的vim学习教程,输入如下命令即可开始

$ vimtutor

五.搜索文件

  • whereis(直接从数据库中查询简单快速)

$whereis who

**whereis只能搜索二进制文件(-b),man帮助文件(-m)和源代码文件(-s)。更全面的搜索结果可以使用locate命令**
  • locate(快而全)
    通过"/var/lib/mlocate/mlocate.db"数据库查找,不过这个数据库也不是实时更新的,系统会使用定时任务每天自动执行updatedb命令更新一次,所以有时候你刚添加的文件,它可能会找不到,你就得自己执行一次updatedb命令(在我们的环境中必须先执行一次该命令)。它可以用来查找指定目录下的不同文件类型,如:

查找/etc下所有以sh开头的文件

$ locate /etc/sh

注意,它不只是在etc目录下查找并会自动递归子目录进行查找
查找/usr/share/下所有jpg文件

$ locate /usr/share/*.jpg

注意要添加*号前面的反斜杠转义,否则会无法找到
只统计数目可以加上-c参数,-i参数忽略大小写进行查找,whereis的-b,-m,-s同样适用

  • which(避免了进入程序进行测试,很有用)
    which本身是shell内建的一个命令,我们通常使用which来确定是否安装了某个指定的软件,因为它只从PATH环境变量指定的路径中去搜索命令

$ which man

  • find(太精和太细,知道前面的命令就已经足够了)
    find应该是这几个命令中最强大的了,它不但可以通过文件类型、文件名进行查找而且可以根据文件的属性(如文件的时间戳,文件的权限等)进行搜索
    举个栗子:在指定目录下搜索指定文件名的文件

$ find /etc/ -name interfaces

注意find命令的路径是作为第一个参数的, 基本命令格式为 find [path] [option] [action]

六.文件打包与解压(这部分内容多,只讲最常用的吧)

tar打包工具(常用的可直接看压缩和解压的命令就行)

tar的解压和压缩都是同一个命令,只需参数不同而已

  • 创建一个tar包(没进行压缩,-c参数创建一个tar包文件,-f参数指定创建的文件名-f参数一定要在最后)

$ tar -cf shiyanlou.tar ~

__ 还可加上-v参数以可视方式输出打包的文件。上面会自动去掉表示绝对路径的/,使用-P保留绝对路径符__
  • 解包一个文件(-x参数)到指定路径的已存在目录(-C参数)

$ mkdir tardir
$ tar -xf shiyanlou.tar -C tardir

  • 只查看不解包文件-t参数

$ tar -tf shiyanlou.tar

  • 保留文件属性和跟随链接(符号链接或软链接)
    有时候我们使用tar备份文件当你在其他主机还原时希望保留文件的属性(-p参数)和备份链接指向的源文件而不是链接本身(-h参数)

$ tar -cphf etc.tar /etc

  • 压缩
    对于创建不同的压缩格式的文件,对于tar来说是相当简单的,你需要的也只是换一个参数而已,这里我就以使用gzip工具创建*.tar.gz文件为例来说明,我们只需在创建tar文件的基础上添加-z参数,使用gzip来压缩文件

$ tar -czf shiyanlou.tar.gz ~ //顺序理解:“创建”一个“gizp”格式的“文件

  • 解压

$ tar -xzf shiyanlou.tar.gz //理解同上

__*.tar.gz文件__

现在我们要使用其他的压缩工具创建或解压相应文件只需要更改一个参数即可:

压缩文件 格式参数
*.tar.gz -z
*.tar.xz -J
*tar.bz2 -j

总结一下常用的两个命令:

  • 压缩:tar -vczf shiyanlou.tar.gz
  • 解压: tar -vxzf shiyanlou.tar.gz

七、简单文件系统操作

1.查看磁盘和目录的容量

  • 使用df命令查看磁盘的容量(对磁盘)

$ df

在实际的物理主机上会像这样


__一般使用情况下,我们更多只是关心第一行的内容也就是我主机上的/dev/sda2__

我主机上的/dev/sda2是对应着我主机硬盘的分区,后面的数字表示分区号,数字前面的字母a表示第几块硬盘(也可能是你的可移动磁盘),你如果主机上有多块硬盘则可能还会出现/dev/sdb,/dev/sdc,这些磁盘设备都会在/dev目录下以文件的存在形式。

接着你还会看到"1k-blocks"这个陌生的东西,它表示以磁盘块大小的方式显示容量,后面为相应的以块大小表示的已用和可用容量,在你了解linxu的文件系统之前这个就先不管吧,我们以一种你应该看得懂的方式展示

$ df -h

df -h 命令

现在你就可以使用命令查看你主机磁盘的使用情况了。至于挂载点如果你还记得前面章节节讲linux目录树结构的内容,那么你就应该能很好的理解挂载的概念,这里就不再赘述。

  • 使用du命令查看目录的容量(对目录)
    这个命令前面其实已经用了很多次了

# 默认同样以blocks的大小展示
$ du
# 加上-h参数,以更易读的方式展示
$ du -h

-d参数指定查看目录的深度

# 只查看1级目录的信息
$ du -h -d 0 ~
# 查看2级$ du -h -d 1 ~


du(estimate file space usage)命令与df(report file system disk space usage)只一字只差,首先注意不要弄混淆了,从man手册中获取命令的完整描述,记全称就不会搞混了。

八、简单的磁盘管理(本章节操作具有一定的危险性,实验楼里也并没有提供磁盘,要用自己的电脑搞一些危险实验,所以我在这里先把这部分跳过去。以后再补充)

通常情况下,这一小节应该直接讲

  1. 如何挂载卸载磁盘
  2. 如何格式化磁盘
  3. 如何分区

但如你所见,我们的环境中没东西给你挂,也没东西给你格和分,所以首先我们会先创建一个虚拟磁盘来进行后续的练习操作

九.命令执行顺序的控制

1.顺序执行多条命令

你可能会想要是我可以一次性输入完所以命令,让它自己去一次执行各命令就好了,简单的顺序执行你可以使用;来完成,你可以

$ sudo apt-get update;sudo apt-get install some-tool;some-tool
# ~~~~~它运行它的,你可以去干其它事了~~~~~~~

2.有选择的执行命令

如果我们在让它自动顺序执行命令时,前面的命令执行不成功,而后面的命令又依赖与上一条命令的结果,那么就会造成花了时间,最终却得到一个错误的结果,而且有时候直观的看你还无法判断结果是否正确。那么我们需要能够有选择性的来执行命令(比如上一条命令执行成功才继续下一条,或者不成功又该做出其它什么处理)
比如我们使用which来查找是否安装某个命令,如果找到就执行该命令,否则什么也不做

$ which cowsay>/dev/null && cowsay -f head-in ohch~

你如果没有安装cowsay,你可以先执行一次上述命令,你会发现什么也没发生,你再安装好之后你再执行一次上述命令,你也会发现一些惊喜(出现奇怪生物)
上面的&&就是用来实现选择性执行的,它表示如果前面的命令执行结果(不是表示终端输出的内容,而是表示命令执行状态的结果)返回0 ,则执行后面的,否则,不执行.
你可以从$?环境变量获取上一次命令的返回结果

__注意which命令中如果命令存在则返回'0'的奇葩设定__

学习过C语言的用户应该知道在C语言里面&&表示逻辑与,而且还有一个||表示逻辑或,同样shell也有一个||,它们的区别就在于,shell中的这两个符号除了也可用于表示逻辑与和或之外,就是可以实现这里的命令执行顺序的简单控制。||在这里就是与&&
相反的控制效果,当上一条命令执行结果为≠0($?≠0)时则执行它后面的命令

$ which cowsay>/dev/null || echo "cowsay has not been install, please run 'sudo apt-get install cowsay' to install"

除了上述基本的使用之外,我们还可以结合这&&和||来实现一些操作,比如

$ which cowsay>/dev/null && echo "exist" || echo "not exist"


画个流程图来解释一下流程

思考一下(本人这个还没进行操作)
上面我们讲到将&&||结合起来使用,那么是否以任意顺序都行了,比如上面我们是&&在前||在后,反过来可以么,会不会有问题.

十、管道

1. 举个例子

$ ls -al /etc | less

通过管道将前一个命令(ls)的输出作为下一个命令(less)的输入,然后你就可以慢慢的悠哉悠哉的一行一行看了。

2.cut命令,打印每一行的某一字段

打印/etc/passwd文件中以:为分隔符的第1个字段和第6个字段分别表示用户名和其家目录

$ cut /etc/passwd -d ':' -f 1,6

打印/etc/passwd文件中每一行的前N个字符

# 前五个(包含第五个)
$ cut /etc/passwd -c -5
# 前五个之后的(包含第五个)
$ cut /etc/passwd -c 5-
# 第五个
$ cut /etc/passwd -c 5
# 2到5之间的(包含第五个)
$ cut /etc/passwd -c 2-5

3.grep命令,在文本中或stdin中查找匹配字符串

grep命令是很强大的,也是相当常用的一个命令,它结合正则表达式可以实现很复杂却很高效的匹配和查找,不过在学习正则表达式之前,这里介绍它简单的使用,而关于正则表达式后面将会有单独一小节介绍到时会再继续学习grep命令和其他一些命令
grep命令的一般形式为:

grep [命令选项]... 用于匹配的表达式 [文件]...

还是先体验一下,我们搜索/home/shiyanlou
目录下所有包含"shiyanlou"的所有文本文件,并显示出现在文本中的行号

$ grep -rnI "shiyanlou" ~

__`-r`参数表示递归搜索子目录中的文件,`-n`表示打印匹配项行号,`-I`表示忽略二进制文件__

当然你可以在匹配字段中使用正则表达式,简单的演示:

# 查看环境变量中以"yanlou"结尾的字符串
$ export | grep ".*yanlou$ "

__`$`就表示一行的末尾__

4.wc命令,简单小巧的计数工具

wc命令用于统计并输出一个文件中行、单词和字节的数目比如输出/etc/passwd文件的统计信息

$ wc /etc/passwd

分别只输出行数、单词数、字节数、字符数和输入文本中最长一行的字节数

# 行数
$ wc -l /etc/passwd
# 单词数
$ wc -w /etc/passwd
# 字节数
$ wc -c /etc/passwd

# 字符数
$ wc -m /etc/passwd
# 最长行字节数
$ wc -L /etc/passwd

注意:对于西文字符来说,一个字符就是一个字节,但对于中文字符一个汉子是大于2个字节的,具体数目是由字符编码决定的


再结合管道操作一下。统计/etc下面所有目录数

$ ls -dl /etc/*/ | wc -l

5.sort排序命令

这个命令前面用过多次了,功能就是将输入按照一定方式排序,然后再输出,它支持的排序有按字典排序,数字排序,按月份排序,随机排序,反转排序,指定特定字段进行排序等等

  • __ 默认为字典排序__

$ cat /etc/passswd | sort

  • 反转排序

$ cat /etc/passwd | sort -r

  • 按特定字段排序

$ cat /etc/passwd | sort -t':' -k 3

上面-t参数用于指定字段的分隔符,这里是":"为分隔符;-k 字段号用于指定对哪一个字段进行排序。这里/etc/passwd文件的第三个字段为数字,默认情况下是一字典序排序的,如果要按照数字排序就要加上-n参数

$ cat /etc/passwd | sort -t':' -k 3 -n

排序命令比较简单,这里就介绍这么多了

6.uniq去重命令

uniq命令:可以用于过滤或者输出重复行

  • 过滤重复行
    我们可以使用history命令查看最近执行过的命令(实际为读取${SHELL}_history文件,如我们环境中的~/.zsh_history文件),不过你可能只想查看使用了那个命令而不需要知道具体干了什么,那么你可能就会要想去掉命令后面的参数然后去掉重复的命令

$ history | cut -c 8- | cut -d ' ' -f 1 | uniq

然后经过层层过滤,你会发现确是只输出了执行的命令那一列,不过去重效果好像不明显,仔细看你会发现它趋势去重了,只是不那么明显,之所以不明显是因为uniq命令只能去连续重复的行,不是全文去重,所以要达到预期效果,我们只能先排个序了

$ history | cut -c 8- | cut -d ' ' -f 1 | sort | uniq
# 或者
$ history | cut -c 8- | cut -d ' ' -f 1 | sort -u

然后就对了,你接着可能会惊叹,哇才这么几个命令啊,可怎么感觉自己干了好多好厉害的事情了呢,哈哈,这就是Linux/Unix哲学吸引人的地方了,大繁至简,一个命令只干一件事却能干到最好(虽然不全是这样,但也差不多)。

  • 输出重复行

# 输出重复过的行(重复的只输出一个)及重复次数
$ history | cut -c 8- | cut -d ' ' -f 1 | sort | uniq -dc
# 输出所有重复的行
$ history | cut -c 8- | cut -d ' ' -f 1 | sort | uniq -D

十一、常用的文本处理命令

1.tr命令

tr命令可以用来删除一段文本信息中的某些文字。或者将其进行转换
使用方式:

tr [option]...SET1 [SET2]

常用选项:

选项 说明
-d 删除和set1匹配的字符,注意不是全词匹配也不是按字符顺序匹配
-s 去除set1指定的在输入文本中连续并重复的字符

操作举例:

# 删除 "hello shiyanlou" 中所有的'o','l','h'
$ echo 'hello shiyanlou' | tr -d 'olh'
# 将"hello" 中的ll,去重为一个l
$ echo 'hello' | tr -s 'l'
# 将输入文本,全部转换为大写或小写输出
$ cat /etc/passwd | tr '[:lower:]' '[:upper:]'
# 上面的'[:lower:]' '[:upper:]'你也可以简单的写作'[a-z]' '[A-Z]',当然反过来将大写变小写也是可以的

可以使用--help或者man tr获得更多tr的使用

思考练习

还记得我们在讲打包压缩那一节提到windows/dos与linux/unix文本文件一些特殊字符不一致的问题,如断行符windows为CR+LF(\r\n),unix/linux为LF(\n),你使用cat -A 文本 你可以看到文本中包含的不可见特殊字符。linux的\n表现出来就是一个$,而windows/dos的表现为^M$,你可以直接使用dos2unixunix2dos工具在两种格式之间进行转换,使用file命令可以查看文件的具体类型。不过现在希望你在不使用上述两个转换工具的情况下,使用前面学过的命令手动完成dos文本格式到unix文本格式的转换。

2.col命令

col命令可以将Tab换成对等数量的空格建,或反转这个操作.用来格式化代码超爽
使用方式:

col [option]

常用的选项有:

选项 说明
-x 将Tab转换为空格
-h 将空格转换为Tab(默认选项)

操作举例:

# 查看/etc/protocols中的不可见字符,可以看到很多^I,这其实就是Tab键转义成可见字符的符号
$ cat -A /etc/protocols
# 使用col -x将/etc/protocols中的Tab转换为空格,然后再使用cat查看,你发现^I不见了
$ cat /etc/protocols | col -x | cat -A

3.join命令(数据库用处多多的)

这个命令用于将两个文件中包含相同内容的那一行合并在一起
"Talk is cheep, show me the code":
使用方式:

join [option]... file1 file2

常用的选项有:

选项 说明
-t 指定分隔符,默认为空格
-i 忽略大小写的差异
-1 指明第一个文件要用哪个字段来对比,,默认对比第一个字段
-2 指明第二个文件要用哪个字段来对比,,默认对比第一个字段

操作举例:

# 创建两个文件
$ echo '1 hello' > file1
$ echo '1 shiyanlou' > file2
$ join file1 file2
# 将/etc/passwd与/etc/shadow两个文件合并,指定以':'作为分隔符
$ sudo join -t':' /etc/passwd /etc/shadow
# 将/etc/passwd与/etc/group两个文件合并,指定以':'作为分隔符, 分别比对第4和第3个字段
$ sudo join -t':' -1 4 /etc/passwd -2 3 /etc/group

__后面的head是输出前两行否则输出很多__

4.paste命令

paste这个命令实际就是上面join的懒人版,它是在不对比数据的情况下,简单粗暴的将多个文件合并一起,以Tab隔开
使用方式:

paste [option] file...

常用选项:

选项 说明
-d 指定合并的分隔符,默认为Tab
-s 不合并到一行,每个文件为一行

操作举例:

$ echo hello > file1
$ echo shiyanlou > file2
$ echo www.shiyanlou.com > file3
$ paste -d ':' file1 file2 file3
$ paste -s file1 file2 file3

__`paste`使用例子__

三、小结

这些命令不是所有你都会经常用到,不过你不得不承认的是它们确实很实用,熟练掌握之后,可以为你减轻很多工作量,试想你不停的用鼠标操作在gedit里面复制粘贴赋值粘贴,将两个文件的内容合并为一个文件,这原本只需要一个命名就能完成的事情。

十一、数据流重定向

其实重定向,就是将原本输出到标准输出的数据重定向到一个文件中,因为标准输出(/dev/stdout)本身也是一个文件,我们将命令输出导向另一个文件自然也是没有任何问题的。

简单的回顾前面经常用到的两个重定向操作:

$ echo 'hello shiyanlou' > redirect
$ echo 'www.shiyanlou.com' >> redirect
$ cat redirect

当然前面没有用到的<<<操作也是没有问题的,如你理解的一样,它们的区别在于重定向的方向不一致而已,>表示是从左到右,<从右到左

1.简单的重定向

我们需要先知道一些基本的东西,前面我们已经提到过linux默认提供了三个特殊设备,用于终端的显示和输出,分别为stdin(标准输入,对应于你在终端的输入),stdout(标准输出,对应于终端的输出),stderr(标准错误输出,对应于终端的输出)。

文件描述符 设备文件 说明
0 /dev/stdin 标准输入
1 /dev/stdout 标准输出
2 /dev/stderr 标准错误

文件描述符:文件描述符在形式上是一个非负整数。实际上,它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。

另外还有一个符号-,它可以同时作为前一个命令的
我们可以这样使用这些文件描述符

# 默认使用终端的标准输入作为命令的输入和标准输出作为命令的输出
$ cat
# 将一个文件作为命令的输入,标准输出作为命令的输出
$ cat Documents/test.c~
# 将echo命令通过管道传过来的数据作为cat命令的输入,将标准输出作为命令的输出
$ echo 'hi' | cat
# 将echo命令的输出从默认的标准输出重定向到一个普通文件
$ echo 'hello shiyanlou' > redirect$ cat redirect


初学者这里要注意不要将管道和重定向混淆,管道默认是连接前一个命令的输出到下一个命令的输入,但是重定向通常是需要一个文件来建立两个命令的连接,你可以仔细体会一下上述第三个操作和最后两个操作的异同点。

2.标准错误重定向

重定向标准输出到文件,这是一个很实用的操作,另一个很实用的操作是将标准错误重定向,标准输出和标准错误都被指向伪终端的屏幕显示,所以我们经常看到的一个命令的输出通常是同时包含了标准输出和标准错误的结果的。比如下面的操作:

# 使用cat 命令同时读取两个文件,其中一个存在,另一个不存在
$ cat Documents/test.c\~ hello.c
# 你可以看到除了正确输出了前一个文件的内容,还在末尾出现了一条错误信息
# 下面我们将输出重定向到一个文件,根据我们前面的经验,这里将在看不到任何输出了
$ cat Documents/test.c\~ hello.c > somefile


遗憾的是,这里依然出现了那条错误信息,这正是因为如上面说的那样,标准输出和标准错误虽然都指向终端屏幕,实际它们并不一样。那有的时候我们就是要可以隐藏某些错误或者警告,那又该怎么做呢。这就需要用到我们前面讲的文件描述符了

# 将标准错误重定向到标准输出,再将标准输出重定向到文件,注意要将重定向到文件写到前面
$ cat Documents/test.c\~ hello.c >somefile 2>&1
# 或者只用bash提供的特殊的重定向符号"&"将标准错误和标准输出同时重定向到文件
$ cat Documents/test.c\~ hello.c &>somefilehell

注意你应该在输出重定向文件描述符前加上&,否则shell会当做重定向到一个文件名为1的文件中

3.使用tee命令同时重定向到多个文件

经常你可能还有这样的需求,除了将需要将输出重定向到文件之外也需要将信息打印在终端,那么你可以使用tee命令来实现

$ echo 'hello shiyanlou' | tee hello

4.永久重定向

你应该可以看出我们前面的重定向操作都只是临时性的,即只对当前命令有效,那如何做到“永久”有效呢,比如在一个脚本中,你需要某一部分的命令的输出全部进行重定向,难道要让你在每个命令上面加上临时重定向的操作嘛,当然不需要,我们可以使用exec命令实现“永久”重定向。exec命令的作用是使用指定的命令替换当前的shell,及使用一个进程换当前进程,或者指定新的重定向

# 先开启一个子shell
$ zsh
# 使用exec替换当前进程的重定向,将标准输出重定向到一个文件
$ exec 1>somefile
# 后面你执行的命令的输出都将被重定向到文件中,直到你退出当前子shell,或取消exec的重定向(后面将告诉你怎么做)
$ ls
$ exit

$ cat somefile

5.创建输出文件描述符

默认在shell中可以有9个打开的文件描述符,上面我们使用了也是它默认提供的0,1,2号文件描述符,另外我们还可以使用3-8的文件描述符,只是它们默认没有打开而已,你可以使用下面命令查看当前shell进程中打开的文件描述符

$ cd /dev/fd/;ls -Al

同样使用exec命令可以创建新的文件描述符

$ zsh
$ exec 3>somefile
# 先进入目录,再查看,否则你可能不能得到正确的结果,然后再回到上一次的目录
$ cd /dev/fd/;ls -Al;cd -
# 注意下面的命令>与&之间不应该有空格,如果有空格则会出错
$ echo "this is test" >&3
$ cat somefile$ exit

6.关闭文件描述符

如上面我们打开的3号文件描述符,可以使用如下操作将它关闭

$ exec 3>&-$ cd /dev/fd;ls -Al;cd -

7.完全屏蔽命令的输出

在linux中有一个被成为“黑洞”的设备文件,所以导入它的数据都将被“吞噬”.

 在类Unix系统中,/dev/null,或称空设备,是一个特殊的设备文件,它通常被用于丢弃不需要的输出流,或作为用于输入流的空文件,这些操作通常由重定向完成。读取它则会立即得到一个EOF。

我们可以利用这个/dev/null屏蔽命令的输出

$ cat Documents/test.c~ nefile 1>/dev/null 2>&1

类似上面这样的操作将使你得不到任何输出结果

8.使用xargs分割参数列表

xargs它的作用是将参数列表转换成小块分段传递给其他命令,以避免参数列表过长的问题。
这个命令在有些时候十分有用,特别是当用来处理产生大量输出结果的命令如find,locategrep的结果,详细用法请参看man文档

$ cut -d: -f1 < /etc/passwd | sort | xargs echo

上面这个命令用于将/etc/passwd文件按:分割取第一个字段排序后,使用echo命令生成一个列表
9.思考题
理解下面这段代码的的作用,实际这段代码不会正常工作,请结合这一小节的知识分析这段代码没有正确工作的原因,并设法解决这个问题(如果你还没有shell脚本编程的基础,你可以选择跳过或者到这里高级shell编程指南学习)

while read filename; do 
    rm -iv$filename
done <<(ls)

十二、正则表达式

简单的说形式和功能上正则表达式和我们前面讲的通配符很像,不过它们之间又有很大差别,特别在于一些特殊的匹配字符的含义上,希望初学者注意不要将两者弄混淆。

1.先举个栗子( 区别通配符和正则表达式)

__感觉这个兔子萌萌哒__
__感觉这个兔子萌萌哒__

假设我们有这样一个文本文件,包含"shiyanlou",和"shilouyan"这两个字符串
同样一个式子

shi*

如果这作为一个正则表达式,它将只能匹配shi,而如果不是作为正则表达式*作为一个通配符,则将同时匹配这两个字符串。这是为什么呢。因为在正则表达式中*表示匹配前面的子表达式(这里就是它前面一个字符)零次或多次,比如它可以匹配"sh","shii","shish","shiishi"等等,而*作为通配符表示匹配通配符后面任意多个任意字符,所以它可以匹配"shiyanlou",和"shilouyan"两个字符。

2.基本语法:

一个正则表达式通常被称为一个模式(pattern),为用来描述或者匹配一系列符合某个句法规则的字符串。

选择

|竖直分隔符表示选择,例如"boy|girl"可以匹配"boy"或者"girl"

数量限定

数量限定除了我们举例用的*,还有+加号,?问号,.点号,如果在一个模式中不加数量限定符则表示出现一次且仅出现一次

  • +表示前面的字符必须出现至少一次(1次或多次),例如,"goo+gle",可以匹配"gooogle","goooogle"等;
  • ?表示前面的字符最多出现一次(0次或1次),例如,"colou?r",可以匹配"color"或者"colour";
  • *星号代表前面的字符可以不出现,也可以出现一次或者多次(0次、或1次、或多次),例如,“0*42”可以匹配42、042、0042、00042等。
范围和优先级

()圆括号可以用来定义模式字符串的范围和优先级,这可以简单的理解为是否将括号内的模式串作为一个整体。例如,"gr(a|e)y"等价于"gray|grey",(这里体现了优先级,竖直分隔符用于选择a或者e而不是gra和ey),"(grand)?father"匹配father和grandfather(这里体现了范围,`?将圆括号内容作为一个整体匹配)。

语法(部分)

正则表达式有多种不同的风格,下面列举一些常用的作为PCRE子集的适用于perl
python编程语言及grepegrep的正则表达式匹配规则:(由于markdown表格解析的问题,下面的竖直分隔符用全角字符代替,实际使用时请换回半角字符)

PCRE(Perl Compatible Regular Expressions中文含义:perl语言兼容正则表达式)是一个用C语言编写的正则表达式函数库,由菲利普.海泽(Philip Hazel)编写。PCRE是一个轻量级的函数库,比Boost之类的正则表达式库小得多。PCRE十分易用,同时功能也很强大,性能超过了POSIX正则表达式库和一些经典的正则表达式库.

字符 描述
将下一个字符标记为一个特殊字符、或一个原义字符。例如,“n”匹配字符“n”。“\n”匹配一个换行符。序列“\\”匹配“\”而“\(”则匹配“(”。
^ 匹配输入字符串的开始位置。
$ 匹配输入字符串的结束位置。
{n} n是一个非负整数。匹配确定的n次。例如,“o{2}”不能匹配“Bob”中的“o”,但是能匹配“food”中的两个o。
{n,} n是一个非负整数。至少匹配n次。例如,“o{2,}”不能匹配“Bob”中的“o”,但能匹配“foooood”中的所有o。“o{1,}”等价于“o+”。“o{0,}”则等价于“o*”。
{n,m} m和n均为非负整数,其中n<=m。最少匹配n次且最多匹配m次。例如,“o{1,3}”将匹配“fooooood”中的前三个o。“o{0,1}”等价于“o?”。请注意在逗号和两个数之间不能有空格。
* 匹配前面的子表达式零次或多次。例如,zo能匹配“z”、“zo”以及“zoo”。等价于{0,}。
+ 匹配前面的子表达式一次或多次。例如,“zo+”能匹配“zo”以及“zoo”,但不能匹配“z”。+等价于{1,}。
? 匹配前面的子表达式零次或一次。例如,“do(es)?”可以匹配“do”或“does”中的“do”。?等价于{0,1}。
? 当该字符紧跟在任何一个其他限制符(*,+,?,{n},{n,},{n,m})后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串“oooo”,“o+?”将匹配单个“o”,而“o+”将匹配所有“o”。
. 匹配除“\n”之外的任何单个字符。要匹配包括“\n”在内的任何字符,请使用像“(.|\n)”的模式。
(pattern) 匹配pattern并获取这一匹配的子字符串。该子字符串用于向后引用。要匹配圆括号字符,请使用“(”或“)”。
x|y 匹配x或y。例如,“z|food”能匹配“z”或“food”。“(z|f)ood”则匹配“zood”或“food”。
[xyz] 字符集合(character class)。匹配所包含的任意一个字符。例如,“[abc]”可以匹配“plain”中的“a”。其中特殊字符仅有反斜线\保持特殊含义,用于转义字符。其它特殊字符如星号、加号、各种括号等均作为普通字符。脱字符^如果出现在首位则表示负值字符集合;如果出现在字符串中间就仅作为普通字符。连字符-如果出现在字符串中间表示字符范围描述;如果如果出现在首位则仅作为普通字符。
[^xyz] 排除型(negate)字符集合。匹配未列出的任意字符。例如,“[^abc]”可以匹配“plain”中的“plin”。
[a-z] 字符范围。匹配指定范围内的任意字符。例如,“[a-z]”可以匹配“a”到“z”范围内的任意小写字母字符。
[^a-z] 排除型的字符范围。匹配任何不在指定范围内的任意字符。例如,“[^a-z]”可以匹配任何不在“a”到“z”范围内的任意字符。

优先级

优先级为从上到下从左到右,依次降低

运算符 说明
转义符
(), (?:), (?=), [] 括号和中括号
*、+、?、{n}、{n,}、{n,m} 限定符
^、$、\任何元字符 定位点和序列
选择

更多正则表达式的内容可以参考以下链接:
正则表达式wiki
几种正则表达式引擎的语法差异
各语言各平台对正则表达式的支持

最后再来一张regex的思导图


二、grep模式匹配命令

若正则表达式只能算得上一些口诀招式,要把它真正练起来还得需要一些兵器在手才行,这里我们要介绍的grep命令以及后面要讲的sed,awk这些就该算作是这样的兵器了。

  • 1.基本操作
    grep命令用于打印输出文本中匹配的模式串,它使用正则表达式作为模式匹配的条件。支持三种正则表达式引擎,分别用三个参数指定:
参数 说明
-E POSIX扩展正则表达式,ERE
-G POSIX基本正则表达式,BRE
-P Perl正则表达式,PCRE

不过在你没学过perl语言的大多数情况下你将只会使用到EREBRE
grep命令,先介绍一下它的常用参数

参数 说明
-b 将二进制文件作为文本来进行匹配
-c 统计以模式匹配的数目
-i 忽略大小写
-n 显示匹配文本所在行的行号
-v 反选,输出不匹配行的内容
-r 递归匹配查找
-A n n为正整数,表示after的意思,除了列出匹配行之外,还列出后面的n行
-B n n为正整数,表示before的意思,除了列出匹配行之外,还列出前面的n行
--color=auto 将输出中的匹配项设置为自动颜色显示

注:在大多数发行版中是默认设置了grep的颜色的,你可以通过参数指定或修改GREP_COLOR环境变量

  • 2.使用正则表达式
    使用基本正则表达式,BRE
    位置
    查找/etc/group文件中以"shiyanlou"为开头的行

$ grep 'shiyanlou' /etc/group
$ grep '^shiyanlou' /etc/group

  • 数量

# 将匹配以'z'开头以'o'结尾的所有字符串
$ echo 'zero\nzo\nzoo' | grep 'z.o'
# 将匹配以'z'开头以'o'结尾,中间包含一个任意字符的字符串
$ echo 'zero\nzo\nzoo' | grep 'z.o'
# 将匹配以'z'开头,以任意多个'o'结尾的字符串
$ echo 'zero\nzo\nzoo' | grep 'zo
'

__注意:其中`\n`为换行符__
__注意:其中`\n`为换行符__
  • 选择

# grep默认是区分大小写的,这里将匹配所有的小写字母
$ echo '1234\nabcd' | grep '[a-z]'
# 将匹配所有的数字
$ echo '1234\nabcd' | grep '[0-9]'
# 将匹配所有的数字
$ echo '1234\nabcd' | grep '[[:digit:]]'
# 将匹配所有的小写字母
$ echo '1234\nabcd' | grep '[[:lower:]]'
# 将匹配所有的大写字母
$ echo '1234\nabcd' | grep '[[:upper:]]'
# 将匹配所有的字母和数字,包括0-9,a-z,A-Z
$ echo '1234\nabcd' | grep '[[:alnum:]]'
# 将匹配所有的字母
$ echo '1234\nabcd' | grep '[[:alpha:]]'


下面包含完整的特殊符号及说明:

特殊符号 说明
[:alnum:] 代表英文大小写字节及数字,亦即 0-9, A-Z, a-z
[:alpha:] 代表任何英文大小写字节,亦即 A-Z, a-z
[:blank:] 代表空白键与 [Tab] 按键两者
[:cntrl:] 代表键盘上面的控制按键,亦即包括 CR, LF, Tab, Del.. 等等
[:digit:] 代表数字而已,亦即 0-9
[:graph:] 除了空白字节 (空白键与 [Tab] 按键) 外的其他所有按键
[:lower:] 代表小写字节,亦即 a-z
[:print:] 代表任何可以被列印出来的字节
[:punct:] 代表标点符号 (punctuation symbol),亦即:" ' ? ! ; : # $...
[:upper:] 代表大写字节,亦即 A-Z
[:space:] 任何会产生空白的字节,包括空白键, [Tab], CR 等等
[:xdigit:] 代表 16 进位的数字类型,因此包括: 0-9, A-F, a-f 的数字与字节

注意:之所以要使用特殊符号,是因为上面的[a-z]不是在所有情况下都管用,这还与主机当前的语系有关,即设置在LANG环境变量的值,zh_CN.UTF-8的话[a-z],即为所有小写字母,其它语系可能是大小写交替的如,"a A b B...z Z",[a-z]中就可能包含大写字母。所以在使用[a-z]时请确保当前语系的影响,使用[:lower:]则不会有这个问题。

# 排除字符
$ echo 'geek|good' | grep '[^o]'

注意:^放到中括号内为排除字符,否则表示行首


使用扩展正则表达式,ERE要通过grep使用扩展正则表达式需要加上-E参数,或使用egrep

  • 数量

# 只匹配"zo"
$ echo 'zero\nzo\nzoo' | grep -E 'zo{1}'
# 匹配以"zo"开头的所有单词
$ echo 'zero\nzo\nzoo' | grep -E 'zo{1,}'

注意:推荐掌握{n,m}即可,+,?,*,这几个不太直观,且容易弄混淆

  • 选择

# 匹配"www.shiyanlou.com"和"www.google.com"
$ echo 'www.shiyanlou.com\nwww.baidu.com\nwww.google.com' | grep -E 'www.(shiyanlou|google).com'
# 或者匹配不包含"baidu"的内容
$ echo 'www.shiyanlou.com\nwww.baidu.com\nwww.google.com' | grep -E 'www.[^baidu].*.com'

注意:因为.号有特殊含义,所以需要转义


关于正则表达式和grep命令的内容就介绍这么多,下面会介绍两个更强大的工具sedawk(太强大可以出一本书了,将只对基本内容作介绍)

三、sed流编辑器

sed工具在man手册里面的全名为"sed - stream editor for filtering and transforming text",意即,用于过滤和转换文本的流编辑器。你要相信,在unix/linux的世界里敢称为编辑器的工具,大都非等闲之辈,比如前面的"vi/vim(编辑器之神)","emacs(神的编辑器)","gedit"这些个编辑器。sed与上述的最大不同之处大于它是一个非交互式的编辑器,下面我们就开始介绍sed这个编辑器。

  • sed常用参数介绍
    sed 命令基本格式

sed [参数]... [执行命令] [输入文件]...
# 形如:
$ sed -i '1s/sad/happy/' test
# 表示将test文件中第一行的"sad"替换为"happy"

参数 说明
-n 安静模式,只打印受影响的行,默认打印输入数据的全部内容
-e 用于在脚本中添加多个执行命令一次执行,在命令行中执行多个命令通常不需要加该参数
-f filename 指定执行filename文件中的命令
-r 使用扩展正则表达式,默认为标准正则表达式
-i 将直接修改输入文件内容,而不是打印到标准输出设备
  • sed编辑器的执行命令(这里”执行“解释为名词)
    sed执行命令格式:

[n1][,n2]command[n1][~step]command
# 其中一些命令可以在后面加上作用范围,形如:
$ sed -i 's/sad/happy/g' test
# g表示全局范围
$ sed -i 's/sad/happy/4' test
# 4表示指定行中的第四个匹配字符串

其中n1,n2表示输入内容的行号,它们之间为,逗号则表示从n1到n2行,如果为波浪号则表示从n1开始以step为步进的所有行;command为执行动作,下面为一些常用动作指令

命令 说明
s 行内替换
c 整行替换
a 插入到指定行的后面
i 插入到指定行的前面
p 打印指定行,通常与-n参数配合使用
d 删除指定行
sed操作举例

先找一个用于练习的文本文件

$ cp /etc/passwd ~

打印指定行

# 打印2-5行
$ nl passwd | sed -n '2,5p'
# 打印奇数行
$ nl passwd | sed -n '1~2p'


行内替换

# 将输入文本中"shiyanlou" 全局替换为"hehe",并只打印替换的那一行,注意这里不能省略最后的"p"命令
$ sed -n 's/shiyanlou/hehe/gp' passwd

注意: 行内替换可以结合正则表达式使用
行间替换

$ nl passwd | grep "shiyanlou"
# 删除第21行
$ sed -n '21c\www.shiyanlou.com' passwd

推荐阅读更多精彩内容