抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

靖待的技术博客

小清新IT旅程 | 为中华之崛起而读书


笔记整理。

  


基本概念及操作

Linux 桌面环境介绍

相对于现在的 Windows 系统,UNIX/Linux 本身是没有图形界面的,我们通常在 Unix/Linux 发行版上看到的图形界面实际都只是运行在 Linux 系统之上的一套软件,类似 Windows95 之前的Windows 的图形界面实则也只是运行在 DOS 环境的一套软件。而 Linux 上的这套软件以前是XFree86,现在则是 xorg(X.Org),而这套软件又是通过 X 窗口系统(X Window System,也常被称为X11或X)实现的,X 本身只是工具包及架构协议,而 xorg 便是 X 架构规范的一个实现体,也就是说它是实现了 X 协议规范的一个提供图形用户界面服务的服务器,就像实现了 http 协议提供 web 服务的 Apache。如果只有服务器也是不能实现一个完整的桌面环境的,当然还需要一个客户端,我们称为 X Client,像如下几个大家熟知也最流行的实现了客户端功能的桌面环境KDE,GNOME,XFCE,LXDE。这也意味着在 Linux 上你可以自己选择安装不同的桌面环境,甚至可以定制自己的专属桌面。

Linux终端

Terminal(终端)

通常在我们使用 Linux 时,我们并不是直接与系统打交道,而是通过一个叫做 Shell 的中间程序来完成的,在图形界面下为了实现让我们在一个窗口中完成接受用户输入和显示输出,Linux 系统还提供了一个叫做终端模拟器的程序(Terminal),下面几个比较常见的终端模拟器,例如 gnome-terminal,kconsole,xterm,rxvt,kvt,nxterm 和 eterm。
终端本质上是对应着 Linux 上的 /dev/tty 设备,Linux 的多用户登陆就是通过不同的 /dev/tty 设备完成的,Linux 默认提供了 6 个纯命令行界面的 “terminal”(准确的说这里应该是 6 个 virtual consoles)来让用户登录,在物理机系统上你可以通过使用[Ctrl]+[Alt]+[F1]~[F6]进行切换,不过在我们的在线实验环境中可能无法切换,因为特殊功能按键会被你主机系统劫持。当你切换到其中一个终端后想要切换回图形界面,你可以按下[Ctrl]+[Alt]+[F7]来完成。

Shell

通常在图形界面中对实际体验带来差异的不是上述的不同发行版的各种终端模拟器,而大都是这个 Shell(壳),有壳就有核,这里的核就是指的 UNIX/Linux 内核,Shell 是指“提供给使用者使用界面”的软件(命令解析器),类似于 DOS 下的 command(命令行)和后来的 cmd.exe。普通意义上的 Shell 就是可以接受用户输入命令的程序。它之所以被称作 Shell 是因为它隐藏了操作系统底层的细节。同样的 Unix/Linux 下的图形用户界面 GNOME 和 KDE,有时也被叫做“虚拟 shell”或“图形 shell”。

Unix/Linux 操作系统下的 Shell 既是用户交互的界面,也是控制系统的脚本语言。当然在这点也有别于 Windows 下的命令行,虽然也提供了很简单的控制语句。在Windows 操作系统下,可能有些用户从来都不会直接的使用 Shell,然而在 UNIX 系列操作系统下,Shell 仍然是控制系统启动、X11 启动和很多其他实用工具的脚本解释程序。

在 UNIX/Linux 中比较流行的常见的 Shell 有 bash,zsh,ksh,csh 等等,Ubuntu 终端默认使用的是 bash,默认的桌面环境是 GNOME 或者 Unity(基于 GNOME)。

命令行操作

重要快捷键

Tab 补全命令、目录、参数
Ctrl+c 强行终止当前程序(不会使终端退出)
Ctrl+d 键盘输入结束或退出终端
Ctrl+s 暂停当前程序,暂停后按下任意键恢复运行
Ctrl+z 将当前程序放到后台运行,恢复到前台为命令fg
Ctrl+a 将光标移至输入行头,相当于Home键
Ctrl+e 将光标移至输入行末,相当于End键
Ctrl+k 删除从光标所在位置到行末
Alt+Backspace 向前删除一个单词
Shift+PgUp 将终端显示向上滚动
Shift+PgDn 将终端显示向下滚动

历史输入命令: 方向键 上

通配符:星号(*)和问号(?),用来对对字符串进行模糊匹配(比如文件名,参数名)。当查找文件夹时,可以使用它来代替一个或多个真正字符;当不知道真正字符或者懒得输入完整名字时,常常使用通配符代替一个或多个真正的字符。

一次性创建多个文件

在创建文件的时候,如果需要一次性创建多个文件,比如:“love_1_linux.txt,love_2_linux.txt,… love_10_linux.txt”。在 Linux 中十分方便:

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

Shell 常用通配符

字符 含义

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

在命令行中获取帮助

man 命令
Manual pages 是在 UNIX 或类 UNIX 操作系统在线软件文档的一种普遍的形式。 内容包括计算机程序(包括库和系统调用),正式的标准和惯例,甚至是抽象的概念。用户可以通过执行 man 命令调用手册页。

你可以使用如下方式来获得某个命令的说明和使用方式的详细介绍:

$ man <command_name>

比如你想查看 man 命令本身的使用方式,你可以输入:

man man

通常情况下,man 手册里面的内容都是英文的,这就要求你有一定的英文基础。man 手册的内容很多,涉及了 Linux 使用过程中的方方面面,为了便于查找,是做了分册(分区段)处理的,在Research UNIX、BSD、OS X 和 Linux 中,手册通常被分为8个区段,安排如下:
区段 说明
1 一般命令
2 系统调用
3 库函数,涵盖了C标准函数库
4 特殊文件(通常是/dev中的设备)和驱动程序
5 文件格式和约定
6 游戏和屏保
7 杂项
8 系统管理命令和守护进程

要查看相应区段的内容,就在 man 后面加上相应区段的数字即可,如:

1
$ man 1 ls

会显示第一区段中的ls命令man页面。

所有的手册页遵循一个常见的布局,其为通过简单的 ASCII 文本展示而优化,而这种情况下可能没有任何形式的高亮或字体控制。一般包括以下部分内容:

NAME(名称)

该命令或函数的名称,接着是一行简介。

SYNOPSIS(概要)

对于命令,正式的描述它如何运行,以及需要什么样的命令行参数。对于函数,介绍函数所需的参数,以及哪个头文件包含该函数的定义。

DESCRIPTION(说明)

命令或函数功能的文本描述。

EXAMPLES(示例)

常用的一些示例。

SEE ALSO(参见)

相关命令或函数的列表。

也可能存在其他部分内容,但这些部分没有得到跨手册页的标准化。常见的例子包括:OPTIONS(选项),EXIT STATUS(退出状态),ENVIRONMENT(环境),BUGS(程序漏洞),FILES(文件),AUTHOR(作者),REPORTING BUGS(已知漏洞),HISTORY(历史)和COPYRIGHT(版权)。

通常 man 手册中的内容很多,不容易找到想要的结果,可以在 man 中使用搜索,/<要搜索的关键字>,查找到后使用n键切换到下一个关键字所在处,shift+n为上一个关键字所在处。使用Space(空格键)翻页,Enter(回车键)向下滚动一行,或者使用j,k(vim编辑器的移动键)进行向前向后滚动一行。按下h键为显示使用帮助(因为man使用less作为阅读器,实为less工具的帮助),按下q退出。

想要获得更详细的帮助,使用info命令,不过通常使用man足够。如果知道某个命令的作用,只是想快速查看一些它的某个具体参数的作用,使用–help参数,大部分命令都会带有这个参数,如:

1
$ ls --help

用户及文件权限管理

Linux 用户管理

Linux 是一个可以实现多用户登陆的操作系统。

查看用户

1
2
3
4
5
$ who am i

或者

$ who mom likes

who 命令其它常用参数

参数 说明
-a 打印能打印的全部
-d 打印死掉的进程
-m 同am i,mom likes
-q 打印当前登录用户数及用户名
-u 打印当前登录用户登录信息
-r 打印运行等级

创建用户

在 Linux 系统里, root 账户拥有整个系统至高无上的权利,比如 新建/添加 用户。
su,su- 与 sudo

su 可以切换到用户user,执行时需要输入目标用户的密码,sudo 可以以特权级别运行cmd命令,需要当前用户属于sudo组,且需要输入当前用户密码。su - 命令也是切换用户,同时环境变量也会跟着改变成目标用户的环境变量。

新建一个叫 lilei 的用户:

1
$ sudo adduser lilei

这个命令不但可以添加用户到系统,同时也会默认为新用户创建 home 目录:

$ ls /home

现在你已经创建好一个用户,并且你可以使用你创建的用户登录了,使用如下命令切换登录用户:

$ su -l lilei

输入刚刚设置的 lilei 的密码。退出当前用户跟退出终端一样可以使用 exit 命令或者使用快捷键 Ctrl+d。

用户组

每个用户都有一个归属(用户组),用户组简单地理解就是一组用户的集合,它们共享一些资源和权限,同时拥有私有资源,就跟家的形式差不多,你的兄弟姐妹(不同的用户)属于同一个家(用户组),你们可以共同拥有这个家(共享资源),爸妈对待你们都一样(共享权限),你偶尔写写日记,其他人未经允许不能查看(私有资源和权限)。当然一个用户是可以属于多个用户组的,正如你既属于家庭,又属于学校或公司。

知道自己属于哪些用户组的方法

方法一:使用groups命令

1
$ groups nancy

每次新建用户如果不指定用户组的话,默认会自动创建一个与用户名相同的用户组(差不多就相当于家长的意思,或者说是老总)。默认情况下在sudo用户组里的可以使用sudo命令获得root权限。

方法二:查看/etc/group文件

1
$ cat /etc/group | sort

cat 命令用于读取指定文件的内容并打印到终端输出。| sort 表示将读取的文本进行一个字典排序再输出。使用命令过滤掉一些你不想看到的结果:
1
$ cat /etc/group | grep -E "nancy"

etc/group 文件格式说明

/etc/group 的内容包括用户组(Group)、用户组口令、GID 及该用户组所包含的用户(User),每个用户组一条记录。格式如下:

group_name:password:GID:user_list

你看到上面的 password 字段为一个 ‘x’ 并不是说密码就是它,只是表示密码不可见而已。

将其它用户加入 sudo 用户组

默认情况下新创建的用户是不具有 root 权限的,也不在 sudo 用户组,可以让其加入sudo用户组从而获取 root 权限。

1
2
$ su -l lilei
$ sudo ls

使用 usermod 命令可以为用户添加用户组,同样使用该命令你必需有 root 权限,你可以直接使用 root 用户为其它用户添加用户组,或者用其它已经在 sudo 用户组的用户使用 sudo 命令获取权限来执行该命令。

用 nancy 用户执行 sudo 命令将 lilei 添加到 sudo 用户组,让它也可以使用 sudo 命令获得 root 权限

$ su nancy # 此处需要输入nancy用户密码,可以点击右侧工具栏中的“SSH直连”查看
$ groups lilei
$ sudo usermod -G sudo lilei
$ groups lilei

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

删除用户

1
$ sudo deluser lilei --remove-home

Linux 文件权限

查看文件权限

使用较长格式列出文件:

1
$ ls -l

Linux 里面一切皆文件。

ls 命令的一些其它常用的用法:

显示除了 '.'(当前目录),'..' 上一级目录之外的所有包含隐藏文件(Linux 下以 '.' 开头的文件为隐藏文件)
1
$ ls -A

可以同时使用 ‘-A’ 和 ‘-l’ 参数:

1
$ ls -Al

查看某一个目录的完整属性,而不是显示目录里面的文件属性:
1
$ ls -dl <目录名>

显示所有文件大小,并以普通人类能看懂的方式呈现:
1
$ ls -AsSh

其中小 s 为显示文件大小,大 S 为按文件大小排序,若需要知道如何按其它方式排序,使用“man”命令查询。

变更文件所有者

假设目前是 lilei 用户登录,新建一个文件,命名为 “iphone6”:

$ touch iphone6

可见文件所有者是 lilei 。
现在,换回到nancy用户身份,使用以下命令变更文件所有者为 nancy :

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

现在查看,发现 文件所有者成功修改为 nancy 。

修改文件权限

方式一:二进制数字表示
每个文件的三组权限(拥有者,所属用户组,其他用户,记住这个顺序是一定的)就对应这一个 “rwx”,也就是一个 ‘7’。

1
$ echo "echo \"hello nancy\"" > iphone6

然后修改权限:
1
$ chmod 700 iphone6

现在,其他用户已经不能读这个“iphone6”文件了

方式二:加减赋值操作
完成上述相同的效果:

1
$ chmod go-rw iphone6

‘g’’o’还有’u’,分别表示group,others,user,’+’,’-‘ 就分别表示增加和去掉相应的权限。

Linux 目录结构及文件基本操作

Linux 目录结构

Linux 是以树形目录结构的形式来构建整个系统的,可以理解为一个用户可操作系统的骨架。虽然本质上无论是目录结构还是操作系统内核都是存储在磁盘上的,但从逻辑上来说 Linux 的磁盘是“挂在”(挂载在)目录上的,每一个目录不仅能使用本地磁盘分区的文件系统,也可以使用网络上的文件系统。举例来说,可以利用网络文件系统(Network File System,NFS)服务器载入某特定目录等。

FHS 标准

FHS 定义了两层规范,第一层是, / 下面的各个目录应该要放什么文件数据,例如 /etc 应该要放置设置文件,/bin 与 /sbin 则应该要放置可执行文件等等。

第二层则是针对 /usr 及 /var 这两个目录的子目录来定义。例如 /var/log 放置系统登录文件、/usr/share 放置共享数据等等。

目录路径

cd 切换目录, . 表示当前目录,.. 表示上一级目录(以 . 开头的文件都是隐藏文件,所以这两个目录必然也是隐藏的, ls -a 命令查看隐藏文件), - 表示上一次所在目录,~ 通常表示当前用户的”home”目录。使用 pwd 命令可以获取当前所在路径(绝对路径)。

进入上一级目录:

1
$ cd ..

进入你的“home”目录:
1
2
$ cd ~ 
# 或者 cd /home/<你的用户名>

使用 pwd 获取当前路径:
1
$ pwd

绝对路径
以根”/“目录为起点的完整路径,以你所要到的目录为终点,表现形式如: /usr/local/bin,表示根目录下的 usr 目录中的 local 目录中的 bin 目录。

相对路径
相对于当前的目录的路径,相对路径是以当前目录 . 为起点,以所要到的目录为终点,表现形式如: usr/local/bin (这里假设当前目录为根目录)。表示相对路径实际并没有加上表示当前目录的那个 . ,而是直接以目录名开头,因为这个 usr 目录为 / 目录下的子目录,是可以省略 . 的(也有类似不能省略的情况);如果是当前目录的上一级目录,则需要使用 .. ,比如当前目录为“home”目录,根目录就应该表示为 ../../ ,表示上一级目录(”home”目录)的上一级目录(”/“目录)。

以”home”目录为起点,分别以绝对路径和相对路径的方式进入 /usr/local/bin 目录:

1
2
3
4
# 绝对路径
$ cd /usr/local/bin
# 相对路径
$ cd ../../usr/local/bin

在进行目录切换的过程中请多使用 Tab 键自动补全,可避免输入错误,连续按两次Tab可以显示全部候选结果。

Linux 文件的基本操作

新建

新建空白文件
使用 touch 命令创建空白文件,关于 touch 命令,其主要是来更改已有文件的时间戳的(比如,最近访问时间,最近修改时间),但其在不加任何参数的情况下,只指定一个文件名,则可以创建一个为指定文件名的空白文件(不会覆盖已有同名文件),当然你也可以同时指定该文件的时间戳。
创建名为 test 的空白文件,因为在其他目录没有权限,所以需要先 cd ~ 切换回用户的 /home/nancy 目录:

1
2
$ cd ~
$ touch test

新建目录
使用 mkdir(make directories)命令可以创建一个空目录,也可同时指定创建目录的权限属性

创建名为”mydir”的空目录:

1
$ mkdir mydir

使用 -p 参数,同时创建父目录(如果不存在该父目录),如下同时创建一个多级目录(这在有时候安装软件,配置安装路径时非常有用):
1
$ mkdir -p father/son/grandson

后面的目录路径,以绝对路径的方式表示也是可以的。

复制

使用cp(copy)命令复制一个文件或目录到指定目录。将之前创建的”test”文件复制到”/home/nancy/father/son/grandson”目录中:

1
$ cp test father/son/grandson

复制目录
要成功复制目录需要加上-r或者-R参数,表示递归复制,就是说有点“株连九族”的意思:
1
$ cp -r father family

删除

删除文件
使用rm(remove files or directories)命令,删除一个文件或目录:

1
$ rm test

有时候你会遇到想要删除一些为只读权限的文件,直接使用rm删除会显示一个提示,你如果想忽略这提示,直接删除文件,可以使用-f参数强制删除:
1
$ rm -f test

删除目录
跟复制目录一样,要删除一个目录,也需要加上-r或-R参数:

1
$ rm -r family

移动文件与文件重命名

移动文件
使用mv(move or rename files)命令,移动文件(剪切)。将文件”file1”移动到”Documents”目录mv 源目录文件 目的目录:

1
2
$ mkdir Documents
$ mv file1 Documents

重命名文件
将文件”file1”重命名为”myfile” mv 旧的文件名 新的文件名:
1
$ mv file1 myfile

批量重命名
1
2
3
4
5
6
7
8
# 使用通配符批量创建 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 。

查看文件

使用cat,tac和nl命令查看文件
打印文件内容到标准输出(终端),其中cat为正序显示,tac倒序显示。
查看之前从”/etc”目录下拷贝来的passwd文件:

1
$ cat passwd

可以加上-n参数显示行号:
1
$ cat -n passwd

nl命令,添加行号并打印,这是个比cat -n更专业的行号打印命令。

它的常用的几个参数:

1
2
3
4
5
6
7
8
-b : 指定添加行号的方式,主要有两种:
-b a:表示无论是否为空行,同样列出行号("cat -n"就是这种方式)
-b t:只列出非空行的编号并列出(默认为这种方式)
-n : 设置行号的样式,主要有三种:
-n ln:在行号字段最左端显示
-n rn:在行号字段最右边显示,且不加 0
-n rz:在行号字段最右边显示,且加 0
-w : 行号字段占用的位数(默认为 6 位)

使用more和less命令分页查看文件
其中more命令比较简单,只能向一个方向滚动,而”less”为基于”more”和”vi”(编辑器)开发,功能更强大。less 的使用基本和 more 一致。
使用more工具打开passwd文件:
1
$ more passwd

打开后默认只显示一屏内容,终端底部显示当前阅读的进度(百分比)。可以使用Enter键向下滚动一行,使用Space键向下滚动一屏,按下h显示帮助,q退出。
使用head和tail命令查看文件
head是只查看的头几行(默认为10行,不足10行则显示全部),tail是查看尾几行。
1
$ tail /etc/passwd

甚至更直接的只看一行, 加上-n参数,后面紧跟行数:
1
$ tail -n 1 /etc/passwd

参数-f,这个参数可以实现不停地读取某个文件的内容并显示。这可让我们动态查看日志起到实时监视的作用。

查看文件类型

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

1
$ file /bin/ls

编辑文件

Linux 内部的 vim 学习教程,输入如下命令即可开始:

1
$ vimtutor

环境变量与文件查找

环境变量

变量

准确的说应该是 Shell 变量,所谓变量就是计算机中用于记录一个值(不一定是数值,也可以是字符或字符串)的符号,而这些符号将用于不同的运算处理中。
在 Shell 中如何创建一个变量,如何给变量赋值和如何读取变量的值呢?
使用declare命令创建一个变量名为 tmp 的变量:

1
$ declare tmp

使用=号赋值运算符为变量 tmp 赋值为 nancy:
1
$ tmp=nancy

读取变量的值,使用echo命令和$符号($符号用于表示引用一个变量的值,初学易忘):
1
$ echo $tmp

注意:关于变量名,并不是任何形式的变量名都是可用的,变量名只能是英文字母,数字或者下划线,且不能以数字作为开头。

环境变量

环境变量就是作用域比自定义变量要大,如Shell 的环境变量作用于自身和它的子进程。在所有的 UNIX 和类 UNIX 系统中,每个进程都有其各自的环境变量设置,且默认情况下,当一个进程被创建时,处理创建过程中明确指定的话,它将继承其父进程的绝大部分环境设置。Shell 程序也作为一个进程运行在操作系统之上,而在 Shell中运行的大部分命令都将以 Shell 的子进程的方式运行。

通常会涉及到的环境变量有三种:

  • 当前 Shell 进程私有用户自定义变量,如上面我们创建的 temp 变量,只在当前 Shell 中有效。
  • Shell 本身内建的变量。
  • 从自定义变量导出的环境变量。

也有三个与上述三种环境变量相关的命令,set,env,export。这三个命令都可用于打印相关环境变量,区别在于涉及的是不同范围的环境变量,详见下表:
命令 说明
set 显示当前 Shell 所有环境变量,包括其内建环境变量(与 Shell 外观等相关),用户自定义变量及导出的环境变量
env 显示与当前用户相关的环境变量,还可以让命令在指定环境中运行
export 显示从 Shell 中导出成环境变量的变量,也能通过它将自定义变量导出为环境变量

关于环境变量,可以简单的理解成在当前进程的子进程是否有效,有效则为环境变量,否则不是(有人也将所有变量统称为环境变量,只是以全局环境变量和局部环境变量进行区分,只要理解它们的实质区别即可)。

注意:为了与普通变量区分,通常我们习惯将环境变量名设为大写。

命令的查找路径与顺序

Shell 中输入一个命令,Shell 是通过环境变量PATH来进行搜索去找到这个命令然后执行的。Windows 中的也是有这么一个 PATH 环境变量。这个PATH里面就保存了Shell中执行的命令的搜索路径。
查看PATH环境变量的内容:

1
$ echo $PATH

默认情况下有输出:
1
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games

通常这一类目录下放的都是可执行文件,当我们在 Shell 中执行一个命令时,系统就会按照 PATH 中设定的路径按照顺序依次到目录中去查找,如果存在同名的命令,则执行先找到的那个。

练习创建一个最简单的可执行 Shell 脚本和一个使用 C 语言创建的”hello world”程序。
创建一个 Shell 脚本文件:

1
$ vim hello_shell.sh

在脚本中添加如下内容,保存并退出(注意不要省掉第一行):
1
2
3
4
5
6
7
#!/bin/zsh

for ((i=0; i<10; i++));do
echo "hello shell"
done

exit 0

为文件添加可执行权限:

1
$ chmod 755 hello_shell.sh

执行脚本
1
$ ./hello_shell.sh

创建一个 C 语言”hello world”程序:
1
$ vim hello_world.c

1
2
3
4
5
6
7
#include <stdio.h>

int main(void)
{
printf("hello world!\n");
return 0;
}

使用 gcc 生成可执行文件:
1
$ gcc -o hello_world hello_world.c

gcc 生成二进制文件默认具有可执行权限,不需要修改

在 nancy 家目录创建一个mybin目录,并将上述 hello_shell.sh 和 hello_world 文件移动到其中:

1
2
$ mkdir mybin
$ mv hello_shell.sh hello_world mybin/

在mybin目录中分别运行刚刚创建的两个程序:
1
2
3
$ cd mybin
$ ./hello_shell.sh
$ ./hello_world

回到上一级目录,也就是nancy家目录,当再想运行那两个程序时,会发现提示命令找不到,除非加上命令的完整路径,但那样很不方便,要做到想使用系统命令一样执行自己创建的脚本文件或者程序,那就要将命令所在路径添加到PATH环境变量了。

添加自定义路径到“PATH”环境变量

PATH里面的路径是以:作为分割符,可这样添加自定义路径:

1
$ PATH=$PATH:/home/shiyanlou/mybin

注意这里一定要使用绝对路径。

可以在其他任意目录执行那两个命令了(注意需要去掉前面的./)。这给 PATH 环境变量追加了一个路径,它也只是在当前 Shell 有效,一旦退出终端,再打开就会发现又失效了。
让添加的环境变量全局有效或者每次启动 Shell 时自动执行上面添加自定义路径到 PATH 的命令——后一种方式——让它自动执行。

在每个用户的 home 目录中有一个 Shell 每次启动时会默认执行一个配置脚本,以初始化环境,包括添加一些用户自定义环境变量等等。zsh 的配置文件是.zshrc,相应 Bash 的配置文件为.bashrc。它们在etc下还都有一个或多个全局的配置文件,不过一般只修改用户目录下的配置文件。

简单的使用下面命令直接添加内容到.zshrc中:

1
$ echo "PATH=$PATH:/home/shiyanlou/mybin" >> .zshrc

上述命令中>>表示将标准输出以追加的方式重定向到一个文件中,注意前面用到的>是以覆盖的方式重定向到一个文件中,使用的时候一定要注意分辨。在指定文件不存在的情况下都会创建新的文件。

修改和删除已有变量

变量修改

变量的修改有以下几种方式:
变量设置方式 说明
${变量名#匹配字串} 从头向后开始匹配,删除符合匹配字串的最短数据
${变量名##匹配字串} 从头向后开始匹配,删除符合匹配字串的最长数据
${变量名%匹配字串} 从尾向前开始匹配,删除符合匹配字串的最短数据
${变量名%%匹配字串} 从尾向前开始匹配,删除符合匹配字串的最长数据
${变量名/旧的字串/新的字串} 将符合旧字串的第一个字串替换为新的字串
${变量名//旧的字串/新的字串} 将符合旧字串的全部字串替换为新的字串

比如要修改前面添加到 PATH 的环境变量。为了避免操作失误导致命令找不到,先将 PATH 赋值给一个新的自定义变量 path:

1
2
3
4
5
$ path=$PATH
$ echo $path
$ path=${path%/home/shiyanlou/mybin}
# 或使用通配符,*表示任意多个任意字符
$ path=${path%*/mybin}

变量删除
可以使用unset命令删除一个环境变量:
1
$ unset temp

如何让环境变量立即生效

上面在Shell 中修改了一个配置脚本文件之后(比如 zsh 的配置文件 home 目录下的.zshrc),每次都要退出终端重新打开甚至重启主机之后其才能生效,很麻烦,使用source命令来让其立即生效,如:

1
$ source .zshrc

source命令还有一个别名就是.,注意与表示当前路径的那个点区分开,虽然形式一样,但作用和使用方式一样,上面的命令如果替换成.的方式就该是
1
$ . ./.zshrc

注意第一个点后面有一个空格,而且后面的文件必须指定完整的绝对或相对路径名,source 则不需要。

搜索文件

与搜索相关的命令常用的有如下几个whereis,which,find,locate。

  • whereis简单快速
    1
    $whereis who
    whereis只能搜索二进制文件(-b),man帮助文件(-m)和源代码文件(-s)。如果想要获得更全面的搜索结果可用locate命令。
  • locate快而全
    通过”/var/lib/mlocate/mlocate.db”数据库查找,不过这个数据库也不是实时更新的,系统会使用定时任务每天自动执行updatedb命令更新一次,所以有时刚添加的文件,它可能会找不到,需要手动执行一次updatedb命令(在我们的环境中必须先执行一次该命令)。它可以用来查找指定目录下的不同文件类型,如查找 /etc 下所有以 sh 开头的文件:
    1
    $ locate /etc/sh
    注意,它不只是在 etc 目录下查找并会自动递归子目录进行查找。
    查找 /usr/share/ 下所有 jpg 文件:
    1
    $ locate /usr/share/\*.jpg
    注意要添加*号前面的反斜杠转义,否则会无法找到。

如果想只统计数目可以加上-c参数,-i参数可以忽略大小写进行查找,whereis 的-b,-m,-s同样可以是使用。

  • which小而精

which本身是 Shell 内建的一个命令,通常使用which来确定是否安装了某个指定的软件,因为它只从PATH环境变量指定的路径中去搜索命令:

1
$ which man

  • find精而细

find应该是这几个命令中最强大的了,它不但可以通过文件类型、文件名进行查找而且可以根据文件的属性(如文件的时间戳,文件的权限等)进行搜索。
在指定目录下搜索指定文件名的文件:

1
$ find /etc/ -name interfaces

注意 find 命令的路径是作为第一个参数的, 基本命令格式为 find [path] [option] [action]
与时间相关的命令参数:
参数 说明
-atime 最后访问时间
-ctime 创建时间
-mtime 最后修改时间

下面以-mtime参数举例:

  • -mtime n: n 为数字,表示为在n天之前的”一天之内“修改过的文件
  • -mtime +n: 列出在n天之前(不包含n天本身)被修改过的文件
  • -mtime -n: 列出在n天之内(包含n天本身)被修改过的文件
  • newer file: file为一个已存在的文件,列出比file还要新的文件名

列出 home 目录中,当天(24 小时之内)有改动的文件:

1
$ find ~ -mtime 0

列出用户家目录下比Code文件夹新的文件:
1
$ find ~ -newer /home/shiyanlou/Code

《黑客帝国》电影里满屏幕代码的“数字雨”,在 Linux 里面也可以轻松实现这样的效果,只需要一个命令cmatrix。
需要先安装,因为 Ubuntu 没有预装:

1
$ sudo apt-get update;sudo apt-get install cmatrix

文件打包与解压缩

文件打包和解压缩

在 Windows 上最常见的不外乎这三种.zip,.rar,.7z后缀的压缩文件,而在 Linux 上面常见常用的除了以上这三种外,还有.gz,.xz,.bz2,.tar,.tar.gz,.tar.xz,tar.bz2,简单介绍如下:
文件后缀名 说明
.zip zip程序打包压缩的文件 .rar rar程序压缩的文件
.7z 7zip程序压缩的文件 .tar tar程序打包,未压缩的文件
.gz gzip程序(GNU zip)压缩的文件 .xz xz程序压缩的文件
.bz2 bzip2程序压缩的文件 .tar.gz tar打包,gzip程序压缩的文件
.tar.xz tar打包,xz程序压缩的文件 tar.bz2 tar打包,bzip2程序压缩的文件
*.tar.7z tar打包,7z程序压缩的文件

zip压缩打包程序

使用zip打包文件夹:
1
2
3
$ zip -r -q -o nancy.zip /home/nancy
$ du -h nancy.zip
$ file nancy.zip

上面命令将 nancy 的 home 目录打包成一个文件,并查看了打包后文件的大小和类型。-r参数表示递归打包包含子目录的全部内容,-q参数表示为安静模式,即不向屏幕输出信息,-o,表示输出文件,需在其后紧跟打包输出文件名。后面使用du命令查看打包后文件的大小。

设置压缩级别为9和1(9最大,1最小),重新打包:
1
2
$ zip -r -9 -q -o nancy_9.zip /home/nancy -x ~/*.zip
$ zip -r -1 -q -o nancy_1.zip /home/nancy -x ~/*.zip

这里添加了一个参数用于设置压缩级别-[1-9],1表示最快压缩但体积大,9表示体积最小但耗时最久。最后那个-x是为了排除我们上一次创建的 zip 文件,否则又会被打包进这一次的压缩文件中,注意:这里只能使用绝对路径,否则不起作用。

我们再用du命令分别查看默认压缩级别、最低、最高压缩级别及未压缩的文件的大小:

1
$ du -h -d 0 *.zip ~ | sort

通过man 手册可知:

h, --human-readable(顾名思义,你可以试试不加的情况)

d, --max-depth(所查看文件的深度)

在环境中操作之后看到的大小可能跟图上的有些不同,因为在使用过程中,会随时还生成一些缓存文件在当前用户的家目录中,这对于学习命令使用来说,是无关紧要的,可以忽略这些不同。

创建加密zip包

使用-e参数可以创建加密压缩包:

1
$ zip -r -e -o nancy_encryption.zip /home/nancy

注意: 关于zip命令,因为 Windows 系统与 Linux/Unix 在文本文件格式上的一些兼容问题,比如换行符(为不可见字符),在 Windows 为 CR+LF(Carriage-Return+Line-Feed:回车加换行),而在 Linux/Unix 上为 LF(换行),所以如果在不加处理的情况下,在 Linux 上编辑的文本,在 Windows 系统上打开可能看起来是没有换行的。如果你想让你在 Linux 创建的 zip 压缩文件在 Windows 上解压后没有任何问题,那么你还需要对命令做一些修改:
1
$ zip -r -l -o nancy.zip /home/nancy

需要加上-l参数将LF转换为CR+LF来达到以上目的。

使用unzip命令解压缩zip文件

将shiyanlou.zip解压到当前目录:

1
$ unzip shiyanlou.zip

使用安静模式,将文件解压到指定目录:
1
$ unzip -q shiyanlou.zip -d ziptest

上述指定目录不存在,将会自动创建。如果不想解压只想查看压缩包的内容可以使用-l参数:
1
$ unzip -l shiyanlou.zip

注意: 使用unzip解压文件时我们同样应该注意兼容问题,不过这里我们关心的不再是上面的问题,而是中文编码的问题,通常 Windows 系统上面创建的压缩文件,如果有有包含中文的文档或以中文作为文件名的文件时默认会采用 GBK 或其它编码,而 Linux 上面默认使用的是 UTF-8 编码,如果不加任何处理,直接解压的话可能会出现中文乱码的问题(有时候它会自动帮你处理),为了解决这个问题,我们可以在解压时指定编码类型。

使用-O(英文字母,大写o)参数指定编码类型:

1
unzip -O GBK 中文压缩文件.zip

rar打包压缩命令

rar也是 Windows 上常用的一种压缩文件格式,在 Linux 上可以使用rar和unrar工具分别创建和解压 rar 压缩包。

安装rar和unrar工具:
1
2
$ sudo apt-get update
$ sudo apt-get install rar unrar
从指定文件或目录创建压缩包或添加文件到压缩包:
1
2
$ rm *.zip
$ rar a nancy.rar .

上面的命令使用a参数添加一个目录~到一个归档文件中,如果该文件不存在就会自动创建。
注意:rar 的命令参数没有-,如果加上会报错。

从指定压缩包文件中删除某个文件:
1
$ rar d nancy.rar .zshrc
查看不解压文件:
1
$ rar l nancy.rar
使用unrar解压rar文件

全路径解压:

1
$ unrar x nancy.rar

去掉路径解压:
1
2
$ mkdir tmp
$ unrar e nancy.rar tmp/

rar命令参数非常多,上面只涉及了一些基本操作。

tar打包工具

创建一个 tar 包:
1
$ tar -cf nancy.tar ~

-c表示创建一个 tar 包文件,-f用于指定创建的文件名,注意文件名必须紧跟在-f参数之后,比如不能写成tar -fc nancy.tar,可以写成tar -f nancy.tar -c ~。你还可以加上-v参数以可视的的方式输出打包的文件。上面会自动去掉表示绝对路径的/,你也可以使用-P保留绝对路径符。

解包一个文件(-x参数)到指定路径的已存在目录(-C参数):
1
2
$ mkdir tardir
$ tar -xf nancy.tar -C tardir
只查看不解包文件-t参数:
1
$ tar -tf nancy.tar
保留文件属性和跟随链接(符号链接或软链接),有时候我们使用tar备份文件当你在其他主机还原时希望保留文件的属性(-p参数)和备份链接指向的源文件而不是链接本身(-h参数):
1
$ tar -cphf etc.tar /etc

对于创建不同的压缩格式的文件,对于tar来说是相当简单的,需要的只是换一个参数,这里我们就以使用gzip工具创建*.tar.gz文件为例来说明。

我们只需要在创建 tar 文件的基础上添加-z参数,使用gzip来压缩文件:
1
$ tar -czf nancy.tar.gz ~
解压*.tar.gz文件:
1
$ tar -xzf nancy.tar.gz

要使用其他的压缩工具创建或解压相应文件只需要更改一个参数即可:
压缩文件格式 参数
.tar.gz -z .tar.xz -J
*tar.bz2 -j

趣味程序(火炉):

1
2
$ sudo apt-get install libaa-bin 
$ aafire

文件系统操作与磁盘管理

简单文件系统操作

使用 df 命令查看磁盘的容量

1
$ df

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

还会看到”1k-blocks”,它表示以磁盘块大小的方式显示容量,后面为相应的以块大小表示的已用和可用容量。
使用 du 命令查看目录的容量

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

-d参数指定查看目录的深度
1
2
3
4
# 只查看1级目录的信息
$ du -h -d 0 ~
# 查看2级
$ du -h -d 1 ~

简单的磁盘管理

下面涉及的命令具有一定的危险性,操作不当可能会丢失你的个人数据,初学者建议在虚拟环境中进行操作

创建虚拟磁盘

dd 命令简介
dd命令用于转换和复制文件,不过它的复制不同于cp。之前提到过关于 Linux 的很重要的一点,一切即文件,在 Linux 上,硬件的设备驱动(如硬盘)和特殊设备文件(如/dev/zero和/dev/random)都像普通文件一样,只要在各自的驱动程序中实现了对应的功能,dd 也可以读取自和/或写入到这些文件。这样,dd也可以用在备份硬件的引导扇区、获取一定数量的随机数据或者空数据等任务中。dd程序也可以在复制时处理数据,例如转换字节序、或在 ASCII 与 EBCDIC 编码间互换。

dd的命令行语句与其他的 Linux 程序不同,因为它的命令行选项格式为选项=值,而不是更标准的–选项 值或-选项=值。dd默认从标准输入中读取,并写入到标准输出中,但可以用选项if(input file,输入文件)和of(output file,输出文件)改变。

我们先来试试用dd命令从标准输入读入用户输入到标准输出或者一个文件:

1
2
3
4
5
6
7
8
# 输出到文件
$ dd of=test bs=10 count=1 # 或者 dd if=/dev/stdin of=test bs=10 count=1
hello
$ cat test
# 输出到标准输出
$ dd if=/dev/stdin of=/dev/stdout bs=10 count=1
world
$ cat test

上述命令从标准输入设备读入用户输入(缺省值,所以可省略)然后输出到 test 文件,bs(block size)用于指定块大小(缺省单位为 Byte,也可为其指定如’K’,’M’,’G’等单位),count用于指定块数量。

dd在拷贝的同时还可以实现数据转换。
例,将输出的英文字符转换为大写再写入文件:

1
2
3
$ dd if=/dev/stdin of=test bs=10 count=1 conv=ucase
hello
$ cat test

结果将是HELLO。
可在man文档查看其它所以转换参数。

使用dd命令创建寻镜像文件

从/dev/zero设备创建一个容量为 256M 的空文件:

1
2
$ dd if=/dev/zero of=virtual.img bs=1M count=256
$ du -h virtual.img

使用 mkfs 命令格式化磁盘(这里是自己创建的虚拟磁盘镜像)

在命令行输入 sudo mkfs 然后按下Tab键,有多个以 mkfs 为前缀的命令,这些不同的后缀是表示不同的文件系统,可以用 mkfs 格式化成的文件系统。
例,将虚拟磁盘镜像格式化为ext4文件系统:

1
$ sudo mkfs.ext4 virtual.img

实际 mkfs.ext4 是使用 mke2fs 来完成格式化工作的。
想知道 Linux 支持哪些文件系统可输入ls -l /lib/modules/$(uname -r)/kernel/fs查看。

使用mount命令挂载磁盘到目录树

该指令通常是使用在 USB 或其他可移除存储设备上,而根目录则需要始终保持挂载的状态。
使用mount查看主机已挂载的文件系统:

1
$ sudo mount

mount命令的一般格式如下:
1
mount [options] [source] [directory]

一些常用操作:
1
mount [-o [操作选项]] [-t 文件系统类型] [-w|--rw|--ro] [文件系统源] [挂载点]

例,挂载创建的虚拟磁盘镜像到/mnt目录:

1
2
3
4
5
$mount -o loop -t ext4 virtual.img /mnt
# 挂载类型可省,会自动识别
#以只读方式挂载
$ mount -o loop --ro virtual.img /mnt
#或者mount -o loop,ro virtual.img /mnt

使用umount命令卸载已挂载磁盘

1
2
# 命令格式 sudo umount 已挂载设备或挂载点
$ sudo umount /mnt

使用fdisk为磁盘分区

1
2
3
4
5
# 查看银盘分区表信息
$ sudo fdisk -l

# 进入磁盘分区模式
$ sudo fdisk virtual.img

然后分区。

使用loseup命令建立镜像与回环设备的关联

1
2
3
4
5
$ sudo losetup /dev/loop0 virtual.img
# 若提示设备忙可使用其它回环设备,"ls /dev/loop*"查看所有回环设备

# 解除设备关联
$ sudo losetup -d /dev/loop0

然后再使用mkfs格式化各分区,格式化之前需为各分区建立虚拟设备的映射,用到kpartx工具,需安装:

1
2
3
4
5
$ sudo apt-get install kpartx
$ sudo kpartx -av /dev/loop0

#取消映射
$ sudo kpartx -dv /dev/loop0

接着是格式化:
1
2
3
$ sudo mkfs.ext4 -q /dev/mapper/loop0p1
$ sudo mkfs.ext4 -q /dev/mapper/loop0p5
$ sudo mkfs.ext4 -q /dev/mapper/loop0p6

格式化完成后在/media目录下新建四个空目录用于挂载虚拟磁盘:
1
2
3
4
5
6
7
8
9
10
11
12
13
$ mkdir -p /media/virtualdisk_{1..3}

# 挂载磁盘分区
$ sudo mount /dev/mapper/loop0p1 /media/virtualdisk_1
$ sudo mount /dev/mapper/loop0p5 /media/virtualdisk_2
$ sudo mount /dev/mapper/loop0p6 /media/virtualdisk_3

# 卸载磁盘分区
$ sudo umount /dev/mapper/loop0p1
$ sudo umount /dev/mapper/loop0p5
$ sudo umount /dev/mapper/loop0p6

$ df -h

趣味程序
cowsay命令,可在终端里以动物说话的形式打印一段话。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 安装
$ sudo apt-get install cowsay

# 默认是一只牛
$ cowsay hello shiyanlou

# 加上'-l'参数打印所有支持的动物种类
$ cowsay -l

# 使用'-f'参数选择动物种类
$ cowsay -f elephant hello shiyanlou

# 此外它还可以结合fortune命令一起使用
$ fortune | cowsay -f daemon

Linux下的帮助命令

内建命令与外部命令

内建命令:shell程序的一部分,通常在系统加载时shell就被加载并驻留在系统内存中。如history、cd、exit等。
外部命令:系统加载时不随系统一起被加载到内存中,需要时再调用内存。是在Bash之外额外安装的,通常放在/bin,/usr/bin,/sbin,/usr/sbin等等。如ls
vi等。
可使用type区分是内建命令还是外部命令。

1
2
type exit
type service

1
2
3
4
5
6
# 内建命令,内建命令都是在 bash 源码中的 builtins 的.def中
xxx is a shell builtin
# 外部命令,外部命令在/usr/bin or /usr/sbin等等中
xxx is /usr/sbin/xxx
#若是得到alias的结果,说明该指令为命令别名所设定的名称;
xxx is an alias for xx --xxx

帮助命令的使用

help命令

进入bash,bash中内置该命令:

1
bash

1
help ls

会出错。因为help命令只能用于显示内建命令的帮助信息。

若是外部命令,需:

1
ls --help

man命令

1
man ls

得到的内容比help更详细,且无内建命令与外部命令的区别。

man手册:
章节数 说明
1 Standard commands (标准命令)
2 System calls (系统调用)
3 Library functions (库函数)
4 Special devices (设备说明)
5 File formats (文件格式)
6 Games and toys (游戏和娱乐)
7 Miscellaneous (杂项)
8 Administrative Commands (管理员命令)
9 其他(Linux特定的), 用来存放内核例行程序的文档。

可通过pgup与pgdn或上下键翻看,按q退出。

info命令

1
info ls

比man更详细。

Linux任务计划crontab

crontab的使用

crontab简介

crontab命令用于设置周期性被执行的指令。该命令从输入设备读取指令,并将其存放在crond文件中,以供之后读取和执行。通常,crontab 储存的指令被守护进程激活,crond 为其守护进程,crond 常常在后台运行,每一分钟会检查一次是否有预定的作业需要执行。通过 crontab 命令,我们可以在固定的间隔时间执行指定的系统指令或 shell script 脚本。时间间隔的单位可以是分钟、小时、日、月、周的任意组合。
crontab格式:

1
2
3
4
5
6
7
8
# Example of job definition:
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# | | | | |
# * * * * * user-name command to be executed

crontab准备

Ubuntu默认启动。

crontab使用

添加一个计划任务:

1
crontab -e

出现选择编辑工具,这里选第一个基本的vim。
1
man crontab

查看详细格式。

添加任务:在文档的最后一排加上一排命令,该任务是每分钟我们会在/home/test目录下创建一个以当前的年月日时分秒为名字的空白文件

1
*/1 * * * * touch /home/test/$(date +\%Y\%m\%d\%H\%M\%S)

添加成功后我们会得到最后一排 installing new crontab 的一个提示。
也可以通过这样的一个指令来查看我们添加了哪些任务
1
crontab -l

虽然添加了任务,但是如果 cron 的守护进程没有启动,它不会监测到有任务,也就不会执行,通过以下2种方式来确定cron是否成功的在后台启动。
1
2
3
ps aux|grep cron
or
pgrep cron

查看执行任务命令之后在日志中的信息反馈

1
sudo tail -f /var/log/syslog

删除任务:

1
crontab -r

crontab的深入

每个用户使用 crontab -e 添加计划任务,都会在 /var/spool/cron/crontabs 中添加一个该用户自己的任务文档,这样目的是为了隔离。
如果是系统级别的定时任务,只需要以 sudo 权限编辑 /etc/crontab 文件就可以。

cron 服务监测时间最小单位是分钟,所以 cron 会每分钟去读取一次 /etc/crontab 与 /var/spool/cron/crontabs 里面的內容。

在 /etc 目录下,cron 相关的目录有下面几个:
每个目录的作用:
/etc/cron.daily,目录下的脚本会每天执行一次,在每天的6点25分时运行;
/etc/cron.hourly,目录下的脚本会每个小时执行一次,在每小时的17分钟时运行;
/etc/cron.monthly,目录下的脚本会每月执行一次,在每月1号的6点52分时运行;
/etc/cron.weekly,目录下的脚本会每周执行一次,在每周第七天的6点47分时运行;
系统默认执行时间可以根据需求进行修改。

进一步学习参考

http://linux.vbird.org/linux_basic/0430cron.php

命令执行顺序控制与管道

命令执行顺序的控制

顺序执行多条命令

一般终端一次输入一条命令,按下回车执行。若需一次执行多条命令,可用;完成。

1
$ sudo apt-get update;sudo apt-get install some-tool;some-tool

有选择的执行命令

若需上一条命令执行成功才执行下一条,或不成功执行其它什么处理,可使用which来查找是否安装某个命令。
例:

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

使用$?环境变量获取上一次命令的返回结果:
1
2
3
4
5
6
7
$ which cowsay
cowsay not found
$ echo $?
$ which cat
/bin/cat
$ echo $?
0

||与&&结果相反,当上一条命令执行结果为≠0($?≠0)时则执行它后面的命令。

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

管道

管道是一种通信机制,通常用于进程间的通信(也可通过socket进行网络通信)。它表现出来的形式是将前面每一个进程的输出(stdout)直接作为一个进程的输入(stdin)。
管道分为匿名管道和具名管道。在使用一些过滤程序时经常用到匿名管道,在命令行中由|分隔符表示。具名管道,简单来说是有名字的管道,通常只在源程序中用到具名管道。

试用

例:查看/etc目录下有哪些文件和目录,使用ls命令来查看:

1
$ ls -al /etc

有太多内容屏幕不能完全显示,此时可用滚动条或快捷键滚动窗口来查看。也可以使用管道:
1
$ ls -al /etc | less

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

cut命令

cut命令,打印每一行的某一字段。
例:打印/etc/passwd文件中以:为分隔符的第1个字段和第6个字段分别表示用户名和其家目录:

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

打印/etc/passewd文件中每一行的前N个字符:
1
2
3
4
5
6
7
8
# 前五个(包含第五个)
$ cut /etc/passwd -c -5
# 前五个之后的(包含第五个)
$ cut /etc/passwd -c 5-
# 第五个
$ cut /etc/passwd -c 5
# 2到5之间的(包含第五个)
$ cut /etc/passwd -c 2-5

grep命令

grep命令,在文本中或stdin中查找匹配字符串。它结合正则表达式可以实现很复杂却很高效的匹配和查找。
grep命令的一般形式为:

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

搜索/home目录下所有包含”helloworld”的所有文本文件,并显示在文本中的行号:
1
$ grep -rnI "helloworld" ~

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

也可在匹配字段中使用正则表达式:

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

$表示一行的末尾。

wc命令

wc命令,简单小巧的计数工具。wc命令用于统计并输出一个文件中行、单词和字节的数目,例:输出/etc/passwd文件的统计信息:

1
$ wc /etc/passwd

分别只输出行数、单词数、字节数、字符数和输入文本中最长一行的字节数:
1
2
3
4
5
6
7
8
9
10
# 行数
$ wc -l /etc/passwd
# 单词数
$ wc -w /etc/passwd
# 字节数
$ wc -c /etc/passwd
# 字符数
$ wc -m /etc/passwd
# 最长行字节数
$ wc -L /etc/passwd

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

结合管道统计/etc下面所有目录数:

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

sort排序命令

将输入按照一定方式排序,然后再输出,它支持的排序有按字典排序,数字排序,按月份排序,随机排序,反转排序,指定特定字段进行排序等等。
默认为字典排序:

1
$ cat /etc/passswd | sort

反转排序:
1
$ cat /etc/passwd | sort -r

按特定字段排序:
1
$ cat /etc/passwd | sort -t':' -k 3

-t参数用于指定字段的分隔符,-k字段号用于指定对哪一个字段进行排序。若/etc/passwd文件的第三个字段为数字,默认情况下是以字典序排序的,若要按照数字排序则要加上-n参数:
1
$ cat /etc/passwd | sort -t':' -k 3 -n

uniq去重命令

uniq命令可用于过滤或输出重复行。

  • 过滤重复行
    可使用history命令查看最近执行过的命令,若只想查看使用了哪个命令而无需知道具体干了什么,可去掉命令后的参数并去掉重复的命令:
    1
    $ history | cut -c 8- | cut -d ' ' -f 1 | uniq
    uniq命令只能去除连续重复的行,不是全文去重。

要达到预期效果,先排序:

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

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

简单的文本处理

文本处理命令

tr命令

tr命令可用来删除一段文本信息中的某些文字,或将其进行转换。

使用方式:

1
tr [option]...SET1 [SET2]

常用的选项有:
选项 说明
-d 删除和set1匹配的字符,注意不是全词匹配也不是按字符顺序匹配
-s 去除set1指定的在输入文本中连续并重复的字符
例:
1
2
3
4
5
6
7
# 删除“hello world”中所有的'o','l','h'
$ echo 'hello world' | tr -d 'olh'
# 将‘hello’中的ll,去重为一个l
$ echo 'hello' | tr -s 'l'
# 将输入文本,全部转换为大写或小写输出
$ echo 'input some text here' | tr '[:lower:]''[:upper:]'
# 上面的'[:lower:]''[:upper:]'也可简写为'[a-z]''[A-Z]',反过来将大写变小写也是可以的

col命令

col命令可将Tab换成对等数量的空格,或反转该操作。
使用方式:

1
col [option]

常用的选项有:
选项 说明
-x 将Tab转换为空格
-h 将空格转换为Tab(默认选项)
例:
1
2
3
4
# 查看/etc/protocols中的不可见字符,可看到很多^I,这其实是Tab转移成可见字符的符号
$ cat -A /etc/protocols
# 使用col -x将/etc/protocols中的Tab转换为空格,然后再使用cat查看,会发现^I不见了
$ cat /etc/protocols | col -x | cat -A

join命令

join命令用于将两个文件中包含相同内容的那一行合并在一起。
使用方式:

1
join [option]... file1 file2

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

例:

1
2
3
4
5
6
7
8
# 创建两个文件
$ echo '1 hello' > file1
$ echo '1 world' > 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

paste命令

与join命令类似,它是在不对比数据的情况下,简单地将多个文件合并在一起,以Tab隔开。
使用方式:

1
paste [option] file...

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

例:

1
2
3
4
5
$ echo hello > file1
$ echo world > file2
$ echo www.hubojing.me > file3
$ paste -d ':' file1 file2 file3
$ paste -s file1 file2 file3

输出结果为:
1
2
3
4
hello:world:www.hubojing.me
hello
world
www.hubojing.me

数据流重定向

重定向,将输出到标准输出的数据重定向到一个文件中。如>>>操作。

数据流重定向

1
2
3
$ echo 'hello world' > redirect
$ echo 'www.hubojing.me' >> redirect
$ cat redirect

>表示从左到右,<从右到左。

简单的重定向

Linux默认提供三个特殊设备,用于终端显示和输出,分别为stdin(标准输入),stdout(标准输出),stderr(标准错误输出)。
文件描述符 设备文件 说明
0 /dev/stdin 标准输入
1 /dev/stdout 标准输出
2 /dev/stderr 标准错误

文件描述符是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。当程序打开一个现有文件或创建一个新文件时,内核向进程返回一个文件描述符。

默认使用终端的标准输入作为命令的输入和标准输出作为命令的输出:

1
2
$ cat
(按Ctrl+C退出)

将cat的连续输出(heredoc方式)重定向到一个文件
1
2
3
4
5
6
7
8
9
10
11
$ mkdir Documents
$ cat > Documents/test.c <<EOF
#include <stdio.h>

int main()
{
printf("hello world\n");
return 0;
}

EOF

将一个命令作为命令的输入,标准输出作为命令的输出
1
$ cat Documents/test.c

将echo命令通过管道传过来的数据作为cat命令的输入,将标准输出作为命令的输出
1
$ echo 'hi' | cat

将echo命令的输出从默认的标准输出重定向到一个普通文件
1
2
$ echo 'hello world' > redirect
$ cat redirect

输出结果:
1
hello world

管道和重定向的区别:管道默认是连接前一个命令的输出到下一个命令的输入,重定向是需要一个文件来建立两个命令的连接。

标准错误重定向

1
2
# 使用cat命令同时读取两个文件,其中一个存在,另一个不存在
$ cat Documents/test.c hello.c

结果:

1
2
3
4
5
6
7
8
#include <stdio.h>

int main()
{
printf("hello world\n");
return 0;
}
cat: hello.c:没有那个文件或目录

按理,继续将输出重定向到一个文件,将看不到任何输出
1
$ cat Documents/test.c hello.c > somefile

然而依然出现了同样的错误信息。标准输出和标准错误虽然都指向终端屏幕,实际它们并不一样。若要隐藏某些错误或者警告,就需要用到文件描述符。
1
2
3
4
# 将标准错误重定向到标准输出,再将标准输出重定向到文件,注意要将重定向到文件写到前面
$ cat Documents/test.c hello.c >somefile 2>&1
# 或者只用bash提供的特殊的重定向符号"&"将标准错误和标准输出同时重定向到文件
$ cat Documents/test.c hello.c &>somefilehell

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

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

除了西药将输出重定向到文件,也需要将信息打印在终端的话,

1
2
3
4
$ echo 'hello world' | tee hello
hello world
$ cat hello
hello world

永久重定向

之前的操作都是临时性的,若要实现永久有效,例如在一个脚本中,需要在某一部分的命令的输出全部进行重定向,并不需要在每个命令上加上临时重定向的操作,使用exec命令即可。exec命令是使用指定的命令替换当前的Shell,及使用一个进程替换当前进程,或指定新的重定向:

1
2
3
4
5
6
7
8
# 先开启一个子 Shell
$ zsh
# 使用exec替换当前进程的重定向,将标准输出重定向到一个文件
$ exec 1>somefile
# 后面执行的命令的输出都将被重定向到文件中,直到退出当前子shell,或取消exec的重定向
$ ls
$ exit
$ cat somefile

创建输出文件描述符

在Shell中有9个文件描述符。上面使用了它默认提供的0,1,2号文件描述符。查看当前Shell进程中打开的文件描述符:

1
$ cd /dev/fd/;ls -Al

使用exec命令创建新的文件描述符:
1
2
3
4
5
6
7
8
$ zsh
$ exec 3>somefile
# 先进入目录再查看,否则可能不能得到正确的结果,然后再回到上一次的目录
$ cd /dev/fd/;ls -Al;cd -
# 注意下面的命令>与&之间不应该有空格,如果有空格则会出错
$ echo "this is test" >&3
$ cat somefile
$ exit

关闭文件描述符

例:上面打开的3号文件描述符,使用如下操作关闭它:

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

完全屏蔽命令的输出

Linux中有一个被称为“黑洞”的设备文件,所有导入它的数据都将被“吞噬”。
在类UNIX系统中,/dev/null,或称空设备,是一个特殊的设备文件,通常用于丢弃不需要的输出流,或作为用于输入流的空文件,这些操作通常由重定向完成。读取它则会立即得到一个EOF。
设个/dev/null屏蔽命令的输出:

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

上述操作将得不到任何输出结果。

使用xargs分割参数列表

xargs是一条UNIX和类UNIX操作系统的常用命令。作用是将参数列表转换成小块分段传递给其它命令,以避免参数列表过长。
当处理产生大量输出结果的命令,如find,locate和grep的结果。

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

该命令用于将/etc/passwd文件按:分割取第一个字段排序后,使用echo命令生成一个列表。

轻松一下:
将图片转换为 ascii 字符查看的工具 aview/asciiview,彩色的。

1
2
3
4
$ sudo apt-get install caca-utils
$ cacaview <pic_file>
$ cacademo
$ cacafire

正则表达式基础

正则表达式

正则表达式使用单个字符串来描述、匹配一系列符合某个句法规则的字符串。在很多文本编辑器里,正则表达式通常被用来检索、替换那些符合某个模式的文本。

和通配符的区别:
例:

1
shi*

正则表达式:*表示匹配前面的子表达式(这里就是它前面一个字符)零次或多次,比如它可以匹配”sh”,”shii”,”shish”,”shiishi”等等。
通配符:匹配通配符后面任意多个任意字符,所以它可以匹配”shiyanlou”,和”shiyanxiang”两个字符。

基本语法

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

选择

|竖直分隔符表示选择,如”boy|girl”匹配”boy”或”girl”

数量限定

除了*,还有+?,如果在一个模式中不加数量限定符则表示出现一次且仅出现一次:

  • +表示前面的字符必须出现至少一次(一次或多次),如,”goo+gle”可匹配”gooogle””goooogle”等;
  • ?表示前面的字符最多出现一次(0次或1次),如,”clou?r”可匹配”color”或”colour”;
  • *表示前面的字符可以不出现,也可以出现一次或多次(0次或1次或多次),如”0*42”可匹配42、042、0042、00042等。

范围和优先级

()可以用来定义模式字符串的范围和优先级。如,”gr(a|e)y”等价于”gray|grey”,”(grand)?father”匹配father和grandfather(?将圆括号内容作为一个整体匹配)。

语法(部分)

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

优先级

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

关于正则表达式的资料:
正则表达式wiki
几种正则表达式引擎的语法差异
各语言各平台对正则表达式的支持

regex思维导图:
regex思维导图

grep模式匹配命令

基本操作

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

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

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

使用正则表达式

基本正则表达式,BRE

  • 位置
    查找/etc/group文件中以”helloworld”为开头的行

    1
    2
    $ grep 'helloworld' /etc/group
    $ grep 'helloworld' /etc/group
  • 数量

    1
    2
    3
    4
    5
    6
    # 将匹配以'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为换行符。

  • 选择

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    # 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:]则不会有这个问题。

1
2
# 排除字符
$ $ echo 'geek\ngood' | grep '[^o]'

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

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

  • 数量

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

    1
    2
    3
    4
    # 匹配"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 -Ev 'www\.baidu\.com'

    .有特殊含义,需转义。

sed流编辑器

sed工具在 man 手册里面的全名为”sed - stream editor for filtering and transforming text”,意即,用于过滤和转换文本的流编辑器。

前面的”vi/vim(编辑器之神)”,”emacs(神的编辑器)”,”gedit”编辑器,sed与上述的最大不同之处在于它是一个非交互式的编辑器。

sed常用参数介绍

sed 命令基本格式:

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

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

sed编辑器的执行命令

sed执行命令格式:

1
2
3
4
5
[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 删除指定行

例:
先找一个文本文件:

1
$ cp /etc/passwd ~

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

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

行间替换

1
2
3
4
$ nl passwd | grep "hubojing"
# 删除第21行
$ sed -n '21c\www.hubojing.me' passwd
(这里只把要删的行打印出来了,并没有真正的删除,若要删除,需使用-i参数)

关于sed资料:
sed简明教程
sed单行脚本快速参考
sed完全手册

awk文本处理语言

awk介绍

简单地说,AWK是一种用于处理文本的编程语言工具。
在大多数linux发行版上面,实际使用的是gawk(GNU awk,awk的GNU版本)。nawk,gawk,mawk。

基本概念

awk所有的操作都是基于pattern(模式)—action(动作)对来完成的,如下面的形式:

1
$ pattern {action}

它将所有的动作操作用一对{}花括号包围起来。其中pattern通常是表示用于匹配输入的文本的“关系式”或“正则表达式”,action则是表示匹配后将执行的动作。在一个完整awk操作中,这两者可以只有其中一个,如果没有pattern则默认匹配输入的全部文本,如果没有action则默认为打印匹配内容到屏幕。

awk处理文本的方式,是将文本分割成一些“字段”,然后再对这些字段进行处理,默认情况下,awk以空格作为一个字段的分割符,不过这不是固定了,可以任意指定分隔符。

awk命令基本格式

1
2
awk [-F fs] [-v var=value] [-f prog-file | 'program text'] [file...]
其中-F参数用于预先指定前面提到的字段分隔符(还有其他指定字段的方式) ,-v用于预先为awk程序指定变量,-f参数用于指定awk命令要执行的程序文件,或者在不加-f参数的情况下直接将程序语句放在这里,最后为awk需要处理的文本输入,且可以同时输入多个文本文件。

例:
先用vim新建一个文本文档

1
$ vim test

包含如下内容
1
2
I like linux
www.hubojing.me

  • 使用awk将本文内容打印到终端

    1
    2
    3
    4
    5
    6
    # "quote>" 不用输入
    $ awk '{
    > print
    > }' test
    # 或者写到一行
    $ awk '{print}' test

    说明:该操作省略了pattern,所以awk会默认匹配输入文本的全部内容,然后在”{}”花括号中执行动作,即print打印所有匹配项,这里是全部文本内容。

  • 将test的第一行的每个字段单独显示为一行

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    $ awk '{
    > if(NR==1){
    > print $1 "\n" $2 "\n" $3
    > } else {
    > print}
    > }' test

    # 或者
    $ awk '{
    > if(NR==1){
    > OFS="\n"
    > print $1, $2, $3
    > } else {
    > print}
    > }' test

    NR与OFS,这两个是awk内建的变量,NR表示当前读入的记录数,可简单的理解为当前处理的行数,OFS表示输出时的字段分隔符,默认为” “空格。将字段分隔符设置为\n换行符,所以第一行原本以空格为字段分隔的内容就分别输出到单独一行了。然后是$N其中N为相应的字段号,这也是awk的内建变量,它表示引用相应的字段,因为这里第一行只有三个字段,所以只引用到了$3。除此之外另一个这里没有出现的$0,它表示引用当前记录(当前行)的全部内容。

  • 将test的第二行的以点为分段的字段换成以空格为分隔

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    $ awk -F'.' '{
    > if(NR==2){
    > print $1 "\t" $2 "\t" $3
    > }}' test

    # 或者
    $ awk '
    > BEGIN{
    > FS="."
    > OFS="\t" # 如果写为一行,两个动作语句之间应该以";"号分开
    > }{
    > if(NR==2){
    > print $1, $2, $3
    > }}' test

-F参数,它是用来预先指定待处理记录的字段分隔符。需注意除了指定OFS我们还可以在print 语句中直接打印特殊符号如这里的\t,print打印的非变量内容都需要用””一对引号包围起来。上面另一个版本,展示了实现预先指定变量分隔符的另一种方式,即使用BEGIN,就这个表达式指示了,其后的动作将在所有动作之前执行,这里是FS赋值了新的”.”点号代替默认的” “空格。

awk常用的内置变量

变量名 说明
FILENAME 当前输入文件名,若有多个文件,则只表示第一个。如果输入是来自标准输入,则为空字符串
$0 当前记录的内容
$N N表示字段号,最大值为NF变量的值
FS 字段分隔符,由正则表达式表示,默认为” “空格
RS 输入记录分隔符,默认为”\n”,即一行为一个记录
NF 当前记录字段数
NR 已经读入的记录数
FNR 当前输入文件的记录数,请注意它与NR的区别
OFS 输出字段分隔符,默认为” “空格
ORS 输出记录分隔符,默认为”\n”

awk相关资料:
awk程序设计语言
awk简明教程
awk用户指南

一个学习vim的游戏vim大冒险

Linux下软件安装

在不同的linux发行版上面在线安装方式会有一些差异包括使用的命令及它们的包管理工具,本文基于ubuntu的,所以涉及的在线安装方式将只适用于ubuntu发行版,或其它基于ubuntu的发行版如国内的ubuntukylin(优麒麟),ubuntu又是基于debian的发行版,它使用的是debian的包管理工具dpkg,所以一些操作也适用与debian。而在其它一些采用其它包管理工具的发行版如redhat,centos,fedora等将不适用(redhat和centos使用rpm)。

例:比如安装一个软件,名字叫做 w3m(w3m是一个命令行的简易网页浏览器),那么输入如下命令:

1
$ sudo apt-get install w3m

注意:如果在安装一个软件之后,无法立即使用Tab键补全这可命令,可尝试先执行source ~/.zshrc,然后就可以使用补全操作。

apt包管理工具介绍

APT是Advance Packaging Tool(高级包装工具)的缩写,是Debian及其派生发行版的软件包管理器,APT可以自动下载,配置,安装二进制或者源代码格式的软件包,因此简化了Unix系统上管理软件的过程。APT最早被设计成dpkg的前端,用来处理deb格式的软件包。现在经过APT-RPM组织修改,APT已经可以安装在支持RPM的系统管理RPM包。这个包管理器包含以 apt- 开头的的多个工具,如 apt-get apt-cache apt-cdrom等,在Debian系列的发行版中使用。
当执行安装操作时,首先apt-get 工具会在本地的一个数据库中搜索关于 w3m 软件的相关信息,并根据这些信息在相关的服务器上下载软件安装。
需定期从服务器上下载一个软件包列表,使用sudo apt-get update 命令来保持本地的软件包列表是最新的(有时也需要手动执行这个操作,比如更换了软件源),而这个表里会有软件依赖信息的记录,对于软件依赖,如,安装 w3m 软件时,需要 libgc1c2 软件包才能正常工作,这时 apt-get 在安装软件的时候会一并安装了,以保证 w3m 能正常的工作。

apt-get

apt-get 是用于处理 apt包的公用程序集,我们可以用它来在线安装、卸载和升级软件包等,下面列出一些apt-get包含的常用的一些工具:

工具 说明
install 其后加上软件包名,用于安装一个软件包
update 从软件源镜像服务器上下载/更新用于更新本地软件源的软件包列表
upgrade 升级本地可更新的全部软件包,但存在依赖问题时将不会升级,通常会在更新之前执行一次update
dist-upgrade 解决依赖关系并升级(存在一定危险性)
remove 移除已安装的软件包,包括与被移除软件包有依赖关系的软件包,但不包含软件包的配置文件
autoremove 移除之前被其他软件包依赖,但现在不再被使用的软件包
purge 与remove相同,但会完全移除软件包,包含其配置文件
clean 移除下载到本地的已经安装的软件包,默认保存在/var/cache/apt/archives/
autoclean 移除已安装的软件的旧版本软件包
下面是一些apt-get常用的参数:

参数 说明
-y 自动回应是否安装软件包的选项,在一些自动化安装脚本中使用这个参数将十分有用
-s 模拟安装
-q 静默安装方式,指定多个q或者-q=#,#表示数字,用于设定静默级别,这在你不想要在安装软件包时屏幕输出过多时很有用
-f 修复损坏的依赖关系
-d 只下载不安装
–reinstall 重新安装已经安装但可能存在问题的软件包
–install-suggests 同时安装APT给出的建议安装的软件包

安装软件包

只需要执行apt-get install <软件包名>即可。
可使用如下方式重新安装:

1
$ sudo apt-get --reinstall install w3m

在不知道软件包完整名的时候进行安装,通常是使用Tab键补全软件包名,有时候需要同时安装多个软件包,可使用正则表达式匹配软件包名进行批量安装。

软件升级

1
2
3
4
5
6
# 更新软件源
$ sudo apt-get update
# 升级没有依赖问题的软件包
$ sudo apt-get upgrade
# 升级并解决依赖关系
$ sudo apt-get dist-upgrade

卸载软件

sudo apt-get remove w3m
或者

1
2
3
4
5
# 不保留配置文件的移除
$ sudo apt-get purge w3m
# 或者 sudo apt-get --purge remove
# 移除不再需要的被依赖的软件包
$ sudo apt-get autoremove

软件搜索

当刚知道了一个软件想下载使用,需要确认软件仓库里面有没有,需要用到搜索功能,命令如下:

1
sudo apt-cache search softname1 softname2 softname3……

apt-cache 命令则是针对本地数据进行相关操作的工具,search顾名思义在本地的数据库中寻找有关 softname1 softname2 …… 相关软件的信息。

关于APT的资料:
APT HowTo

使用dpkg

dpkg 是 Debian 软件包管理器的基础,它被伊恩·默多克创建于 1993 年。dpkg 与 RPM 十分相似,同样被用于安装、卸载和供给和 .deb 软件包相关的信息。

dpkg 本身是一个底层的工具。上层的工具,像是 APT,被用于从远程获取软件包以及处理复杂的软件包关系。”dpkg”是”Debian Package”的简写。
经常可在网络上见到以deb形式打包的软件包,就需要使用dpkg命令来安装。

dpkg常用参数介绍:

参数 说明
-i 安装指定deb包
-R 后面加上目录名,用于安装该目录下的所有deb安装包
-r remove,移除某个已安装的软件包
-I 显示deb包文件的信息
-s 显示已安装软件的信息
-S 搜索已安装的软件包
-L 显示已安装软件包的目录信息

使用dpkg安装deb软件包

先使用apt-get加上-d参数只下载不安装,下载emacs编辑器的deb包。
然后将第一个deb拷贝到home目录下,并使用dpkg安装

1
2
3
$ cp /var/cache/apt/archives/emacs24_24.3+1-2ubuntu1_amd64.deb ~
# 安装之前参看deb包的信息
$ sudo dpkg -I emacs24_24.3+1-2ubuntu1_amd64.deb

这个包还额外依赖了一些软件包,这意味着,如果主机目前没有这些被依赖的软件包,直接使用dpkg安装可能会存在一些问题,因为dpkg并不能解决依赖关系。
1
2
# 使用dpkg安装
$ sudo dpkg -i emacs24_24.3+1-2ubuntu1_amd64.deb

会报错,要解决错误,要用到apt-get,使用-f参数,修复依赖关系的安装。
1
$ sudo apt-get -f install

安装成功,然后可以运行emacs程序。

查看已安装软件包的安装目录

使用dpkg -L查看deb包目录信息

1
$ sudo dpkg -L emacs

从二进制包安装

二进制包的安装比较简单,我们需要做的只是将从网络上下载的二进制包解压后放到合适的目录,然后将包含可执行的主程序文件的目录添加进PATH环境变量即可。

目前linux基本操作已基本结束。

感谢实验楼。

评论