Ubuntu 基本操作-嵌入式 Linux 入门

在 Ubuntu 基本操作 里面基本就分为两部分:

  1. 安装 VMware 运行 Ubuntu
  2. 熟悉 Ubuntu 的各种操作、命令

如果你对 Ubuntu 比较熟悉的话,安装完 VMware 运行 Ubuntu 之后就可以来学习下一章节了。

1. 安装 VMware 运行 Ubuntu

我们首先来看看怎么去安装 VMware 来运行 Ubuntu,为什么要做这些事情,我们先讲清楚原因。

一般来说我们都是在 windows 电脑上面来操作,然后你可以通过网络去访问一个服务器(linux 服务器),做 linux 开发的时候,为什么一定要用 linux 服务器,在 linux 服务器里面,你可以去编译 u-boot,可以去编译内核,可以去编译应用程序或者各种驱动程序,那么为什么这些操作必须放在 linux 服务器里面呢,为什么不能够在 windows 里面操作呢,就比如说在 linux 里面有一些链接文件,那对于 windows 来说,它根本就不支持 linux 里面的链接文件的文件格式,也不支持 Linux 里面的设备节点,所以很多的时候这种工作必须在 Linux 里面来做。

那么我们作为一个学习者,我们并没有 Linux 服务器,那怎么办?我们可以在 windows 里面来安装一个虚拟机 VMware,这个是虚拟机,它可以模拟出一台电脑,在这台模拟出来的电脑上面安装 Ubuntu,Ubuntu 是一个 Linux 系统,跟 windows 是并列的关系,我们在这台虚拟的电脑上面来运行 Ubuntu,以后在这个 Ubuntu 里面来编译 u-boot 内核、应用程序和驱动程序。

所以我们第一步干嘛呢,安装 VMware;第二步,使用 VMware 来打开 Ubuntu。

1.1 安装 VMware

首先从 VMware 官网(www.vmware.com)下载 Workstation Player 安装包,或者使用我们提供的安装包。(在 <开发板配套资料> 01_100ask_stm32mp157_pro_2022.08\02_开发工具\【Windows】VMwareWorkstation 安装包安装包中,VMWare 安装软件是:VMware-workstation-full-16.2.3-19376536.exe,一路点击安装)

VMWare 安装完成后,有两个软件,它们都可以使用,建议使用第 2 个:

① Vmware Workstation Pro:这是收费的,可以试用 30 天。

② Vmware Workstation 16 Player:这是免费的。

注意:本文是在 Windows 10 上安装 VMware。

1.2 安装 Ubuntu

在 <开发板配套资料> 中,有 Ubuntu 映像文件。(01_100ask_stm32mp157_pro_2022.08\02_开发工具\100ask-vmware_ubuntu18.04)在某个磁盘分区里解压文件,这个分区最好有 200G 的空闲空间。

1.3 使用 VMware 运行 Ubuntu

  1. 启动 Vmware Workstation 16 player,这个 player 是不需要注册号的,是可以免费使用。
  2. 点击打开虚拟机,打开 D:\ubuntu18.04\ubuntu18.04_x64.vmx
  3. 点击获取所有权,点击启动按钮就可以打开虚拟机了,我已复制该虚拟机。

这个软件模拟出来一台电脑,这个电脑上面去运行这个 Ubuntu,用户名密码是 123456,在里面你就可以像操作 windows 一样来操作 Ubuntu 了。

你不想再使用这个 Ubuntu 了之后,你可以点击关闭按钮关机,你也可以点击停止按钮挂起,确定。挂起之后,以后你再次打开这个虚拟机的时候,选中它,点击播放虚拟机,它就会恢复之前被挂起的状态。

如果你对 Linux 系统还不熟悉,对 Ubuntu 操作还不熟悉,那么你就需要去看第二篇里面的后续内容,可以看文档,也可以看视频。如果你已经熟悉了 Linux 的操作,那么下一章节里面 <配置 VMware 使用双网卡> 这个一定要看,下一章节里面我们一开始还需要去配置 VMware 里面的网络。

2. Ubuntu 的基本操作

从现在开始我们来介绍一下 Ubuntu 的简单操作。我们首先介绍一下怎么去操作桌面,然后再去介绍一下使用各种命令。

2.1 Ubuntu 下打开终端

我们之前已经使用 VMware 打开了 Ubuntu。我们以后会使用到各种 Linux 命令,那么在哪里输入命令呢?

  1. 使用右键打开终端。你可以在桌面上点击右键 open terminal,打开终端,这时候你就可以在里面输入各种命令了,这所谓的终端跟 windows 里面的命令行是类似的,在 windows 里面我们同样可以打开所谓的命令行(快捷键 Ctrl + R),你同样可以在里面执行各种 dos 命令,比如 dir,你看在 windows 里面,你要列出这些目录的话,是 dir 命令,在 linux 里面是 ls 命令,有点差别。
  2. 用搜索框打开终端。我们现在回到 Ubuntu,你可以使用右键来打开终端,你也可以点击左下角,找到终端 terminal。
  3. 快捷键打开终端。我们还可以使用快捷键"Ctrl+Alt+T" 来打开终端。

以后我们将会在终端里面输入各种命令,但是这节我们先来体验一下桌面。

2.2 Ubuntu 系统初体验

其实 Ubuntu 发展到现在,它的桌面操作跟 windows 是非常的类似。但是

2.2.1 Ubuntu 和 Windows 的最大差别:目录

对于 Windows 我们可以打开此电脑,Windows 中每个盘符都对应某个分区,在这个分区里面你可以存放目录与文件,如图所示:

那这些盘符对于哪些分区呢,你可以打开创建并格式化硬盘分区工具,就可以看到左下方有磁盘,磁盘 0 里面前面是分区表,C 盘就对应这个磁盘里面的第一个分区,D 盘对应第二个分区,E 盘对应第三个分区;另外一个磁盘呢,你看这里有 J、K、I、L,从这里你可以看到每一个盘符都对应磁盘里面的某一个分区,Windows 这种表现方法非常的直观。但是对于 Ubuntu 呢,它就不大一样了,在 Ubuntu 里面我们可以打开文件浏览器,打开其他位置,computer,从这里你可以看到它里面有各种目录。

对于 Windows,你在此电脑里面看到的是各种盘符,但是在 Ubuntu 里面,刚才我们看到了在 computer 里面,你看到的是各种目录,你看不到任何的盘符。

好,回到 Windows,在 Windows 里面我们去访问某个文件的时候,你可以使用绝对路径。比如

bash 复制代码
C:\abc\def\hello.txt

从这个绝对路径我一下就可以知道:它位于 C 盘,它位于某一个分区里面。但是对于 Ubuntu 呢,在 Ubuntu 里面它没有盘符的概念,就比如说你想去访问某个文件的时候,比如

bash 复制代码
/abc/def/hello.txt

第一个斜杠表示它位于根目录,位于根目录下面的 abc 子目录,在 abc 子目录下面又有 def 子目录,在 df 下面有 hello.txt,从这个路径你看不出它位于哪一个分区。在 Ubuntu 中,以树状的结构表示文件夹与文件。

注意:

Windows 的绝对路径中,目录使用 "" 分隔。

Linux 的绝对路径中,目录使用 "/" 分隔。

以前在 Windows 有 C 盘、D 盘 和 E 盘,这是并列的关系;但是在 Ubuntu 里面,它是一个树状的关系。就比如说,地面上有一个树,它可以分叉,在叉里面又可以继续分叉,这就是所谓的根,这个根用斜杠来表示。我们来比划一下,在根下面有 abc 目录,还可以有其他目录,有 home 目录,有 bin 目录,有 boot 目录等等等等;在 abc 目录下面又可以有什么呢,有 def 目录,或者说还有其他目录,在 def 目录下面又有什么呢,有 hello.txt,那么我怎么找到这个 hello.txt,它就是根目录下面的 abc 子目录,abc 目录下面又有 def 目录,再下面有 hello 这个文件,这就是树状结构的意思。再比如说这 home 目录下面可能又有其他子目录,有 book 一个用户名,有其他用户名 xxx,在 book 下面又有某一个文件,那么你就可以这么访问:根目录下面找到 home 目录,找到 book 目录,在 book 目录下面你可能有一个 1.txt。

bash 复制代码
/abc/def/hello.txt
/home/book/1.txt

从这些绝对路径的表示方法里面,你看不到任何分区的信息。那么我怎么才能知道我这个文件处于哪个分区呢?那么你就可以打开 Disks 工具,从这里我们就可以看出来,我这 Ubuntu 里面只有一个磁盘,这个磁盘里面的第一个分区:

bash 复制代码
/dev/sda1
  • dev:设备
  • sd:表示磁盘
  • a:表示第一个磁盘
  • 1:表示这个磁盘里面的第一个分区

sda 这个磁盘的第一个分区,它挂载在根目录下面。

看到这里,我们又听到了一个新的概念叫挂载。就比如说对于 Windows,你可以认为 C 盘挂载了那个磁盘里面的第一个分区,D 盘挂载了那个磁盘里面第二个分区;对于 Ubuntu 呢,你看,对于这个磁盘里面的第一个分区,它作为根文件系统挂载就挂载在了根下面,以后你去访问这个根的时候,访问的就是这个分区,就比如说你在这个根下面创建了一个 hello.c,这个文件就会放在这个磁盘的第一个分区里。那同样道理,如果你想去访问根目录下面的 home,访问这个 book,你访问这个目录的时候,访问的也是这个磁盘的第一个分区。

我们再来看看这个磁盘的第二个分区挂载在哪里,你点击这个磁盘里面的第二个分区,你发现,这个磁盘 dev/sda 的第二个分区挂载在 boot 目录下面,也就是说我以后去访问根目录下面的 boot 目录,我去访问里面的文件的时候,这些文件位于这个磁盘的第二个分区,为什么呢?因为这个第二个分区挂载在 boot 目录下面。

从这里你可以看到它没有像 Windows 那么直接那么直观,在 Windows 里面我就知道了,我访问 C 盘访问的是第一个分区,我访问 D 盘访问的是第二个分区;但在 Linux 这里呢你得先确认一下第二个分区挂载在哪里,然后你才可以知道,我去访问这个挂载目录的时候,我访问的就是这个分区里面的文件。

我们再来看看,第三个分区这个不用管,这是交换分区,它并没有挂载在某一个目录下面。这里第四个分区挂载在 home 目录下面。我们现在又可以推翻前面说的话了,你刚才不是说我访问 home 目录的时候,也是去访问第一个分区吗,那现在不是了,我现在看完了整个分区的挂载信息之后才发现,第四个分区挂载在 home 目录下面,那么我以后去访问根目录下面的 home 目录的时候,我就访问里面的 book 目录,或者访问这个目录下面的直接有某一个文件的话,

bash 复制代码
/home/book
/home/1.txt

这些目录,这些文件它都是放在这个分区里面,因为这个分区挂载在 home 目录下面,你访问 home 目录下面的所有的文件夹,所有文件的时候都是去访问这个分区。

我们引入了这种分区挂载在某个目录的这么一个概念,那么自然就会引发另外一个问题,就比如说,我现在第一个分区 /dev/sda 表示某个磁盘,这个设备的第一个分区挂载在了 home 目录下面,我现在假设 /dev/sda 这个分区里面它本来就有 home 目录,home 目录下面我本来就有一个 1.txt,如果我没有去挂载其他分区的话,以后我去访问这个文件的时候,我访问的就是 /dev/sda 这个分区里面的文件,这是第一步。

那第二步呢,我又把 /dev/sda4 这个磁盘的第四个分区我挂载在 home 目录下面,一旦挂载成功之后,我以后访问这个 home 目录,我访问的就是 /dev/sda4 这个分区,那意味着这些之前的这些文件就不可见了。之前 sda1 的 home 目录不可见了,因为我把你的 home 目录挂载了另外一个分区,我以后访问这个 home 目录的时候,我访问的是这个第四个分区,不再访问你之前的第一个分区了。

实际上就我个人的习惯来说,我认为 Windows 里面的表现方法更加直观,更加方便。

我们现在来看看对于 Ubuntu 它的文件系统是怎么组织的呢?

  1. 对于 Windows 你可以打开 C 盘,它都有一些约定俗成的规则,你看里面有 program 目录,就表示说里面存放有 Windows 的应用程序,有用户目录表示里面存放的是各个用户的单独的数据,还有 Windows 目录里面存放的应该就是系统的驱动啊等等等等。
  2. 同样道理,对于 Ubuntu,对于 Linux 它也有一套规则。这套规则叫做循 FHS 标准(Filesystem Hierarchy Standard,文件系统层次标准)。它定义了文件系统中目录、文件分类存放的原则、定义了系统运行所需的最小文件、目录的集合,并列举了不遵循这些原则的例外情况及其原因。FHS 并不是一个强制的标准,但是大多的 Linux、Unix 发行版本遵循 FHS。

我们简单来看看在一个 Ubuntu 里面它有哪些文件。打开 Files->other Locations->computer,你可以看到这些目录它们有什么含义呢,我们来看一看。

首先,我们可以执行各种程序,这些程序放在哪里,放在 bin 目录下面,放在 sbin 目录下面。这些 bin 目录下面放的那些应用程序(命令)是所有用户都可以使用的;这个 sbin 呢,这个 s 就是系统的意思,在 sbin 目录下面放的是基本的系统命令,只有系统管理员才可以使用。总之,这两个目录里面存放的都是命令,或者说就是各种 app 了,只不过它们的权限不一样。那么对于其他无关紧要的应用程序呢,我们可以放在 usr 目录下的 bin 目录或者 usr 目录下面的 sbin 目录,注意了这个 usr 它并不是用户的意思,它是 Unix 软件资源,里面存放的是一些资源,这些资源并不是系统启动必须的资源,就比如说你甚至还可以在里面放游戏,放头文件,头文件根本不是系统启动必须的,游戏呢也根本就不是系统启动必须的。现在我们看到了,usr/bin 目录或者 usr/sbin 目录放的是非必需的 APP。

再来看看其他目录,这些应用程序它都用到库呀,那库放在哪里,根目录下面的 lib 目录可以存放库,usr 目录下面的 lib 目录也可以存放库。

咱们再从头往下看看,boot 目录下面一般来说放一些启动文件,就比如说内核呀等等等等;device 里面存放的是各种设备文件,这是 Linux 独有的,就比如说我们之前讲到了 dev/sda 表示第一个磁盘,dev/sda1 表示这个磁盘的第一个分区,这些文件就存放在 dev 目录下面,它们叫做设备文件,用来表示某些硬件的;还有 etc,是配置文件;home 是家目录,家目录下面有各种子目录,就比如说这个 book 子目录对应着 book 用户,跟 Windows 里面的这个用户目录是类似的,你看在 Windows 里面这个用户目录下面有各种用户,每一个文件夹对应一个用户,对于 Ubuntu,对 Linux 也是类似的,home 目录下面每一个文件夹对应一个用户。

其他的无关紧要,这里还有 proc、sys,这是一些默认的文件夹,在这些文件夹里面,你可以去挂载一些虚拟的文件系统,什么叫做虚拟的文件系统呢?我们在根目录下面挂载了这个磁盘的第一个分区,在 home 目录下面挂载了这个磁盘的第四个分区,它们对应真实的存储设备,但是对于这些 proc、sys 目录,它们挂载的是某一些虚拟的文件系统,对于这些虚拟的文件系统,它并没有真实的存储设备,你可以去访问这些目录,观察到内核的一些信息。就比如说这个 proc 目录,它存放的什么呢,存放的是 process 各个进程的一些信息,这进程的信息是内核帮你提供的,它并不保存在磁盘上,我们可以去看看,打开 proc 目录,你可以看到各种数字,各种数字就对应着某一个进程,你可以进去看看,里面有它所打开的文件,我们看不了,我们是 book 用户,没有权限访问这些目录,我们现在简单的知道这些 proc 或者 sys 目录,它对应的是虚拟的文件系统,比如说 proc 目录下面你可以看到各个进程,在 sys 目录下面你可以看到其他更多的信息,就比如说设备的信息、驱动得信息等等,以后我们再介绍。

再一路往下看,你之前说这个 usr 目录它是 Unix 软件资源,它存放的是可分享的不可变动的数据,那么可以变动的数据在哪里呢。所谓可以变动的数据就是程序运行的过程中生成了各种临时文件,就比如我们在 Windows 里面会有各种缓存,在我的用户目录下面会看到各种缓存的数据,就比如说我打开了这个文件之后,它可能会有一些临时文件,这些临时文件都是可以删除的,这些可以删除的临时文件就是可变动的文件,对 Ubuntu 来说它也有类似的文件,只不过它们都放在 var 目录下面,var,可变的意思,它可以放一些临时的可变的文件,就比如说缓存、log 等等这些文件。

我们现在对 Ubuntu 的整个文件系统,对这些目录稍微简单的介绍了一下。总之,Ubuntu 发展到现在跟 Windows 是非常的类似。

2.2.2 Linux 文件属性

2.3 Linux 常用命令

2.3.1 Linux 命令行介绍

我们先来演示一个最简单的命令。在 Ubuntu 中打开终端,执行:

bash 复制代码
ls -a

我要提几个问题:

  1. 你输入 ls -a 的时候,回车,谁来解析你的输入?
1. Linux Shell 简介

Ubuntu 系统中或者 Linux 系统中有一个程序叫做 Shell,由这个程序来接收你的输入。根据你的输入,找到一个应用程序,就比如说这个应用程序是 bin 目录里面的应用程序,它根据你的输入找到 bin 目录里面的 ls 这个程序,然后去执行这个程序,它执行这个程序的时候,它会传入 -a 这个参数。根据这个演示过程,我们引入两个问题:

  1. 谁来接收你的输入?谁来解析你的输入?这是 Shell 来做的。
  2. 需要解析你的输入之后,它去哪里找到应用程序?

在回答这两个问题之前,我们先来看看:

2. Linux 命令的提示符

在 Ubuntu 中打开终端后,即可看到类似下图的提示符:

~:表示路径,就比如说你可以进入根目录,你看这个路径就变成了根目录。~ 表示家目录,当前用户的家目录,然后进入 ~,那就变成了家目录。这家目录什么意思呢,你看 home 目录下面有某些文件夹,这些文件夹每个文件夹都会对应一个用户。

我们可以在这个界面里面输入各种命令,这些命令的格式是怎样的呢?

3. Linux 命令的格式

一般来说,Linux 命令由三部分组成:

① command 命令;就比如说我们 ls 命令

② options 选项;这些选项一般来说使用一个减号开头

③ parameter 参数;

说明:

① [ ]中括号表示 该部分可选,可有可无,需要根据命令的实际需要而添加;

② 命令、选项、参数都以空格分隔,不管几个空格都算一个空格;

③ 命令输入完毕后,按回车"Enter"键启动;

就比如说我们可以来执行 ls -l 然后某一个目录(/,根目录):

bash 复制代码
ls -l /

你看,命令,可选的一些选项,还有参数,回车,它就可以列出根目录下面那些文件的详细信息。

  • ls 表示列出那些信息。
  • -l 表示详细的信息。

你列出哪一个目录的详细信息呢?你可以指定命令、选项、参数之间用空格来隔开。

再来看看这行文字,它为什么用一个中括号来表示呀,中括号的意思就是这些项目它是可选的,你可以填也可以不填,那如果用尖括号的话,就是表示说你必须填好。我们来找一个命令来演示一下:

bash 复制代码
fdisk

你看它说什么呢:错误的用法。为什么是错误的用法,因为你想去格式化某个磁盘,你就必须指定某个磁盘。来看看:

bash 复制代码
fdisk --help

命令,可选的参数,它会告诉你怎么去用。

fdisk 加上各种选项,然后你必须指定某个磁盘,这个尖括号就表示说这个参数这个项目不可以省略;中括号就表示说这些项目是可以省略的,就比如说我可以来执行:

bash 复制代码
sudo fdisk /dev/sda

因为权限不够,我们加上 sudo,密码是 123456,它就可以成功的打开这个磁盘,在里面你可以输入各种命令来操作这个磁盘。

密码输入过程是不可见的。你看着什么都没有输进去其实已经打进去了。

现在我们大概知道了命令的格式是怎样的。现在回到我们之前说的那几个问题,我们以后可以执行各种命令,再次演示下我们最简单的命令:ls -l 在我们输入过程中,我们从键盘给电脑发送字符,谁来接收这个字符,谁把它显示出来,我们输入了 ls,它就接收到了 ls,并且把 ls 显示出来了,我们回车之后,他会去找到 ls 这个应用程序来执行它,并且执行这个程序的时候,把 -l 这个参数传递给他,你看不同的参数,有不一样的行为,那么是谁在背后做这些事情,谁在背后从键盘接收数据,并且把这些数据给显示出来,当你回车的时候,谁来帮你找到应用程序并且执行它,并且把这些执行结果给显示出来,这个背后的程序就是 Shell,我们这节讲的就是 Shell。

Shell 就是一个应用程序,我们可以通过键盘、串口给它发送命令,回车后它接收到这些命令之后,就会去执行这些命令。就比如说我们以 ls -l 命令为例:

① 接收键盘数据并回显。

比如:我们使用键盘给 Shell 程序发送字母 l,它收到后会在屏幕上显示出来。

② 解析输入的字符串,寻找程序,执行程序。

当我们使用键盘给 Shell 程序发送回车是,它就知道字符输入结束了。

  1. shell 会解析字符串,这些字符串用空格分为好几部分:
    • 第一部分就是程序名、命令名(应用程序)
    • 其他部分是参数
  2. shell 会根据第一部分去寻找该程序,去哪里找?去 PATH 环境变量所指示的位置找。
    (你当然也可以指定绝对路径、相对路径,shell 就会直接去这些路径找到程序。)
  3. 找到程序后,会启动该程序,并传入参数。

这环境变量是什么意思?我们来执行一条命令:

bash 复制代码
echo $PATH

你看这 PATH 里面它的值是这些,里面是各个字符串,各个字符串之间用冒号隔开,我们的 shell 程序就是去这些目录逐个寻找,看看有没有 ls,找到之后就去执行它。在 shell 中执行程序时,你也可以使用绝对路径、相对路径来指定程序的位置,这个时候 shell 就会去这些路径中寻找应用程序,它就不会去 PATH 环境变量所指示的位置来寻找。

你可以执行:

bash 复制代码
env

看到各种变量,用 env 显示出来的这些变量就是环境变量,= 前面是环境变量,= 后面是这个变量的值。我们可以用 echo 来显示出某一个环境变量:

bash 复制代码
echo

那么怎么设置 PATH 环境变量呢?

我们先不去介绍,先来演示一下一个应用程序,我事先已经写了一个 hello 应用程序。

c 复制代码
#include <stdio.h>


/* 执行命令: ./hello abc
 * argc = 2
 * argv[0] = ./hello
 * argv[1] = abc
 */

int main(int argc, char **argv)
{
	if (argc >= 2)
		printf("Hello, %s!\n", argv[1]);
	else
		printf("Hello, world!\n");
	return 0;
}

你看如果你输入的参数超过两个的话,它就会打印 "Hello, %s!\n", argv[1],如果只输入 hello 而不带其他参数的话,它就会打印 "Hello, world!\n"。我们可以把这个程序拿到 Ubuntu 上面去,把它复制粘贴到 Ubuntu 桌面上,启动终端:

bash 复制代码
book@100ask:~$ cd /home/book/
book@100ask:~$ cd Desktop/						/* 进入桌面 */
book@100ask:~/Desktop$ ls
hello.c
book@100ask:~/Desktop$ gcc -o hello hello.c		/* 编译程序 */

这 hello 就是我们的应用程序。现在我们来执行了,直接执行 hello:

bash 复制代码
book@100ask:~/Desktop$ hello					/* 运行程序失败 */

没有任何反应,它说 hello 命令找不到,为什么?你直接输入 hello,没有使用绝对路径,也没有使用相对路径,那 shell 就会去 PATH 环境变量所指示的位置来寻找,在 PATH 环境变量所指示的那些目录里面都没有我们的 hello 程序,所以它提示 Command 'hello' not found

你可以使用相对路径来执行:

bash 复制代码
book@100ask:~/Desktop$ ./hello					/* 运行程序 */

也可以使用绝对路径来执行:

bash 复制代码
book@100ask:~/Desktop$ /home/book/Desktop/hello	/* 运行程序 */
book@100ask:~/Desktop$ /home/book/Desktop/hello	abc	/* 运行程序 */

我们在 shell 上输入了这些字符串,以空格隔开,shell 会根据第一个字符串来寻找应用程序,然后把所有的字符串都传给我们的应用程序的 main 函数,那么这些参数是怎么传的呢?来看看事先写的这么一个笔记:

c 复制代码
/* 执行命令: ./hello abc
 * argc = 2
 * argv[0] = ./hello
 * argv[1] = abc
 */

就比如说你执行 ./hello abc 这个命令时,它有两个参数,那么 main 函数里面 argc 就等于 2,这第一个参数就会保存在 argv[0] 这个字符串里面;这第二个参数就会保存在 argv[1] 这个字符串里面,所以说在执行 main 函数的时候,它发现 argc >= 2,就会执行 printf("Hello, %s!\n", argv[1]); 这条语句。在 shell 里面所执行的这些 ls 命令啊等等等等,都是这种形式的传参方式。

现在我们执行:

bash 复制代码
book@100ask:~/Desktop$ hello					/* 运行程序失败 */

表示说找不到这个命令,我们可以去设置环境变量,怎么去设置呢?

你不想去设置的话,你当然可以把这个 hello 程序拷贝到 PATH 所指定的那些目录里面去,就比如我们把它复制到 /usr/local/bin 里面去:
book@100ask:~/Desktop$ sudo cp hello /usr/local/bin/hello2

把它命名为 hello2,hello2 就可以执行了:
book@100ask:~/Desktop$ hello2

设置方法有 3 种:(假设程序在 /home/book 目录下,/home/book 不在 PATH 所指定的那些目录里面book@100ask:~/Desktop$ cp hello /home/book/)

  1. 永久设置之方法 1:(对所有的用户都有效)

修改 /etc/environment,需要加上 sudo,要使用 权限:

bash 复制代码
book@100ask:~$ sudo gedit /etc/environment

这里面就是 PATH,你可以在里面,在最后面加上一个冒号,加上你的新的路径,然后保存。这个时候你就可以重新登录,就可以看到效果了。

  1. 永久设置之方法 2:(只对当前用户有效)

修改 ~/.bashrc:

bash 复制代码
book@100ask:~/Desktop$ gedit ~/.bashrc

找到最后加上这么一行:

bash 复制代码
export PATH=$PATH:/home/book

然后保存、关闭。

现在去执行没有效果,你需要关闭终端重新打开,来执行 hello,这样就可以了。

  1. 临时设置:
bash 复制代码
book@100ask:~/Desktop$ export PATH=$PATH:/home/book
book@100ask:~/Desktop$ hello

这个临时设置的环境变量只对当前终端有效。你把它(当前终端)关掉,重新打开一个终端来执行 hello,它也表示找不到。如果你想让这个环境变量的设置永远有效的话,可以使用前面两种方法。

这节我们介绍的是 shell 是怎么回事,当然 shell 的功能肯定不仅仅有这些,它还有更加复杂的功能,在 shell 里面你不仅仅可以执行各种命令,你还可以加入各种控制,就比如说你可以在百度上搜索 shell 循环,得到一篇文章来参考这个例子来执行一个 for 循环:

bash 复制代码
for((i=0;i<10;i++));do hello $i;done

这里就循环了十次,这 shell 的功能非常的强大,你想学习的话可以去找专门的书籍,现在呢我们的视频只是粗略的介绍一下。

2.3.2 目录/文件操作命令

这节我们来介绍 Linux 中目录和文件的操作命令。

我们首先得引入几个概念:绝对路径、相对路径、当前目录(pwd.)、上级目录(..)、家目录(/home/book(当前用户路径),~)、上一个目录(-(切回到上一次的路径))。

绝对路径和相对路径

  • 绝对路径:从根路径(/)开始指定它的完整的路径名。

Linux 下的根目录为"/",从根目录下出发可以找到任意目录、任意文件。

有时候使用绝对路径太过麻烦, 可以使用相对路径。

  • 相对路径:使用 "./"、".../" 等开头表示的路径。

假设当前正位于 /home/book 目录下,那么:

  • ./1.txt 表示当前目录下的 1.txt,即/home/book/1.txt;"."表示当前目录
  • ../book/1.txt 表示当前目录的上一级目录里,book 子目录下的 1.txt
  • "/home/book/.." 就是"/home"目录,".."表示上一级目录
- 使用 . 表示当前路径
- 使用 .. 表示上一级路径
- 使用 ../.. 表示上上级路径

加不加后缀 '/' 都没有关系。

对于目录我们大概就了解了,那么对于目录的操作我们怎么进行呢。

1. pwd
  • 英文来源:print working directory
  • 功能:打印当前所在路径
  • 命令格式:
命令 选项 参数
pwd \ \
  • 示例:
bash 复制代码
book@100ask:~$ pwd
/home/book
2. cd
  • 英文来源:change directory
  • 功能:改变路径,切换路径
  • 命令格式:
命令 选项 参数
cd \ [目录]
  • 示例:
bash 复制代码
book@100ask:~$ pwd
/home/book
book@100ask:~$ cd /home/
book@100ask:~$ cd ./book
book@100ask:~$ cd -
  • 输入前面几个字母后,可以按 TAB 键补全。

  • 在整个操作过程中,我们一直都使用英文的系统,以后我们学习 Linux 的时候,去编译程序时,肯定会出现各种错误,我们希望那些错误信息以英文的方式表现出来,这样比较容易在网上找到答案。

你可以在桌面系统使用图形化的界面来创建目录,也可以使用命令行。

3. mkdir
  • 英文来源:make directory
  • 功能:创建目录
  • 命令格式:
命令 选项 参数
mkdir -p [目录]
  • 示例:
4. rmdir
  • 英文来源:remove directory
  • 功能:删除目录
  • 命令格式:
命令 选项 参数
mkdir \ [目录]
  • 示例:

不能删除一个非空目录。

5. rm
  • 英文来源:remove
  • 功能:删除文件或目录
  • 命令格式:
命令 选项 参数
mkdir -r,-p 文件 或 文件夹
  • 示例:

删除目录时,常用如下命令:rm -rf dir_a

  • r:recursive,递归地,即删除所有文件
  • f:force,强制删除
6. ls
  • 英文来源:list
  • 功能:列出目录内容
  • 命令格式:
命令 选项 参数
mkdir -l,-a,-h [目录]
  • 示例:

对于 Linux 系统某个文件夹或者某些文件,它名字上有一个点的话,它就是一个隐藏的文件,一般 ls 的时候是看不见的,加上 ls -a 的时候就可以看见那些隐藏的文件夹和文件。

bash 复制代码
ls -ld /bin

查看 bin 目录本身的信息。

文件属性:

d:表示文件夹

-:表示它是一个常规的文件

后面几个字符:它列出的是文件或者文件夹的权限

7. cp
  • 示例:

复制目录时,常用如下命令:cp -rfd dir_a dir_b

  • r:recursive,递归地,即复制所有文件
  • f:force,强制覆盖
  • d:如果源文件为链接文件,也只是把它作为链接文件复制过去,而不是复制实际文件
    我们想去操作文件名里面有空格的这种文件的时候,你可以使用单引号把这个文件名给括起来。
8. cat
  • 英文来源:\
  • 功能:串联文件的内容并打印出来
  • 命令格式:
命令 选项 参数
cat \ 文件
  • 示例:
9. touch
  • 英文来源:\
  • 功能:修改文件的时间,如果文件不存在则创建空文件
  • 命令格式:
命令 选项 参数
touch \ 文件名
  • 示例:
10. 其他
bash 复制代码
echo abc > 1.txt			/* 创建文件 */
mv 1.txt 2.txt				/* 移动(改名) */
mv 2.txt ../
mv ../2.txt .

2.3.3 改变文件的权限和属性

文件属性

  • -:表示它是一个常规文件
  • d:表示它是一个目录
  • rwx:拥有者的权限(如果是这个文件的拥有者来执行这个文件的话他有哪些权限)
    • r:表示读
    • w:表示写
    • x:表示执行
    • 可读可写可执行。这个文件的拥有者是 book,对 book 用户,它可以来读这个文件、写这个文件、执行这个文件。
  • rwx:表示的是同组的其他用户对这个文件的权限。
    • 它也是可读可写可执行。
  • r-x:其他用户对这个文件的权限。
    • 它是可读、不可写、可以执行。这个文件的拥有者是 book,对 book 用户它可以读写执行这个文件;跟 book 同属一组的其他用户,它也可以读写执行这个文件;对于其他用户,跟 book 用户没有什么关系的其他用户,它可以读这个文件,可以执行这个文件,它不可以写这个文件。

对于我们的 book 用户,我可以执行这个文件,所以我可以来执行它。我执行这个文件没有问题,那么我能不能狗修改这些权限,可以的。用什么命令来修改权限呢?

1. chmod 改变文件的权限

文件权限有两种设置方法:数字类型改变权限和符号改变权限。

首先说明各个权限对应的数字(3 位对应 8 进制):

  • r: 4 或 0
  • w: 2 或 0
  • x: 1 或 0

这 3 种权限的取值相加后,就是权限的数字表示。例如:文件 a 的权限为

"-rwxrwx---",它的数值表示为:

  • owner = rwx = 4+2+1 = 7
  • group = rwx = 4+2+1 = 7
  • others = --- = 0+0+0 = 0

所以在设置权限时,该文件的权限数字就是 770。

  1. 数字类型改变权限

使用数值改变文件权限的命令如下:chmod [-R] xyz 文件或目录

  • xyz:代表权限的数值,如 770。
  • -R:以递归方式进行修改,比如修改某个目录下所有文件的属性。

范例:

bash 复制代码
chmod 777 hello

将文件 hello 这个文件的所有权限设置都启用。


作为 book 用户(拥有者本身),我无法执行,权限不够;我 root 用户作为其他用户,我是有这个文件的执行权限的,于是我可以来执行它。

sudo 可以临时切换为 root 用户。

  1. 符号类型改变文件权限方式

可以使用 a,u,g,o 指定给什么用户修改权限。

augo 分别表示所有人(all)、用户(user)、组(group)、其他用户(other)。

范例:

bash 复制代码
chmod u=rwx,go=rx hello

也可以增加或去除某种权限,"+"表示添加权限,"-"表示去除权限:

bash 复制代码
chmod a+w hello					/* 给所有用户加上 x 权限 */
chmod a-x hello					/* 给所有用户去除 x 权限 */
chmod u+w hello					/* 给拥有者加上 x 权限 */
chmod u-x hello					/* 给拥有者去除 x 权限 */

拥有者,同一组的用户,其他用户对这个文件都没有了可执行权限。

bin 目录它的拥有者是 root 用户,对 root 用户可读可写可执行;对于其他用户,就比如说对我们的 book 用户(其他用户),它可以读,可以执行,不可以写。

就比如说我想把 hello 程序拷贝到 bin 目录里面去的话,它会提示说权限不够。你可以加上 sudo,我临时把用户从 book 提升为 root,然后我去拷贝看行不行?可以。

这时候你就可以执行 bin 目录里面的 hello 程序了,或者直接去执行,因为这个 bin 目录在你的环境变量 PATH里面。

2. chowm 改变文件的所有者

对 hello 这个文件它的拥有者是 book,它的组也是 book,我们可以来修改。

把拥有者改成其他:chown [-R] 账号名 文件或目录

把组改成其他:chown [-R] 账号名:组名 文件或目录

  • -R:也是递归子目录。

范例:

我想把 hello 程序,把它的拥有者从 book 改成 root,把它的组从 book 改成 root,看行不行?

肯定不行,如果你能够随随便便去提升一个文件,把它的拥有者改成 root 用户的话,这 root 用户可是有超级权限的,你作为一个 book,作为一个普通用户,你凭什么能够去提升一个文件,把它的权限提升为 root 权限,不可能的,所以说,这样不行。

你可以加上 sudo,这样就可以了。你看,之前 hello 程序它的拥有者是 book,它的组是 book,现在呢这个 hello 程序它的拥有者是 root,它的组是 root。

那现在我能不能把它改回来,我把 sudo 先去掉,也不行,一个普通用户凭什么来修改一个 root 用户的文件,你的权限不够。

还可以加上 sudo,切换成 root 用户就可以了。

改变文件所有者和用户组的这两个命令的应用场景:复制文件,由于复制行为会复制执行者的属性和权限,因此复制后需要改变文件所属用户、用户组等。

既然说到 sudo,它是临时的把我们的用户从 book 切换成 root。我们的 Ubuntu 系统默认是不能够使用 root 用户登陆的。

2.3.4 查找/搜索命令

我们以后开发 Linux 程序的时候,会经常去查找文件,或者在文件里面去查找某些字符。我们需要用到 find 命令和 grep 命令。

1. find

主要是来查找某些名字的文件。

在 Windows 中搜索文件,一般查找文件需要传入两个条件:

① 在哪些目录中查找;

② 查找的内容;

在 Linux 中,查找文件的也需要这两个条件,不同于 Windows 使用搜索框查找,Linux 中使用 find 命令查找文件。

find 命令格式为: find 目录名 选项 查找条件

举例 1:

bash 复制代码
find /home/book/dira/ -name " test1.txt " 

说明:

  • /home/book/dira/:指明了查找的路径。
  • "-name":表明以名字来查找文件 。
  • "test1.txt":就指明查找名为 "test1.txt" 的文件。

举例 2:

bash 复制代码
find /home/book/dira/ -name "*.txt" 

说明:查找指定目录下面所有以 ".txt" 结尾的文件,其中 "*" 是通配符

bash 复制代码
find /home/book/dira/ -name "*2.txt*" 

前面是什么东西我不管,后面是什么东西我不管,但是中间一定得有 "2.txt"。

举例 3:

bash 复制代码
find /home/book/dira/ -name "dira"

说明:查找指定目录下面是否存在 "dira" 这个目录或文件,"dira" 是名称。

注意:

① 如果没有指定查找目录,则为当前目录。

bash 复制代码
find . -name " *.txt " 			//其中.代表当前路径。
find -name " *.txt " 			//没加路径,默认是当前路径下查找。

② find 还有一些高级的用法,如查找最近几天(几个小时)之内(之前)有变动的文

bash 复制代码
find /home/book -mtime -2 		//查找/home 目录下两天内有变动的文件。
2. grep 命令

它是去查找含有某些格式;它是去使用内容来查找文件。

grep 命令的作用是查找文件中符合条件的字符串,其格式如下:grep [选项] [查找模式] [文件名]

假设 dira 目录的 test1.txt 和 dirb 目录的 test1.txt 都含有如下内容:

bash 复制代码
aaa AAAAAA abc abcabcabc cbacbacba match_pattern nand->erase。

通过查找字符串,希望显示如下内容:

① 所在的文件名 ------ grep 查找时默认已经显示目标文件名

② 所在的行号 ------ 使用 -n 选项。

grep -rn "字符串" 文件名

  • r(recursive):递归查找
  • n(number):显示目标位置的行号
  • 字符串:要查找的字符串
  • 文件名:要查找的目标文件,如果是*则表示查找当前目录下的所有文件和目录。

举例:

bash 复制代码
grep -rn "abc" *					//在 test1.txt 中查找字符串 abc 
grep -n "abc" test1.txt 			//在当前目录递归查找字符串 abc

注意:可以加入 -w 全字匹配、整字,整词查找。

可以在 grep 的结果中再次执行 grep 搜索,比如搜索包含有 ABC 的头文件,可执行如下命令:

bash 复制代码
grep "ABC" * -nR | grep "\.h"

上述命令把第 1 个命令"grep "ABC" * -nR"通过管道传给第 2 个命令。即第2 个命令在第 1 个命令的结果中搜索。

find 命令和 grep 命令在去搜索庞大的源码的时候非常有用。

2.7 默认不能使用 root 用户登录

为什么呢?因为我们还没有给它设置密码。我们来体验一下。

就比如说我们现在是 book 用户,你可以执行 su root 么?

su:就是切换用户的意思。

我能不能切换到 root 用户?密码是 root 用户的密码。在这里他已经成功的从 book 用户切换到 root 用户了。意思就是说我之前曾经设置过 root 用户的密码。

那如果你切换 root 用户不成功的话,你就按照以下步骤来操作:

  • 在开发过程中很少用 root 用户,要使用 root 权限时可以在命令前加上 "sudo",比如"sudo ps -a"。
  • 如果你就是喜欢用 root 用户,可以按上图操作,先给 root 用户设置密码, 以后就可以用 root 用户登录了。

建议大家不要使用 root 用户登录。因为它的破坏性太大了,你稍有不慎就有可能把整个系统都给破坏掉。

所以我们平常使用 book 用户登录,你要临时提高权限的时候,可以加上 sudo 命令。就比如:

bash 复制代码
sudo fdisk /dev/sda

你要去操作磁盘,普通用户的权限肯定不够的,你可以加上 sudo 临时提升权限,这样就可以。平时的时候不要使用 root 用户登录。

2.3.5 压缩/解压缩命令

我先来创建一个文件,我想找到一个比较大的文件:

bash 复制代码
dd if=/dev/zero of=test bs=1024 count= 1024
  • if:输入文件
  • of:输出文件
  • bs:每次读和写 1024 字节
  • count:次数,1024

    这样就是 1M 嘛。它的大小是 1M,我们现在来压缩一下。
1. gzip

gzip 的常用选项:

  • -l(list):列出压缩文件的内容。
  • -k(keep):在压缩或解压时,保留输入文件。
  • -d(decompress):将压缩文件进行解压缩。

举例:

① 查看压缩文件

bash 复制代码
gzip -l pwd.1.gz

② 解压文件

bash 复制代码
gzip -kd pwd.1.gz 				//该压缩文件是以.gz 结尾的单个文件

test 是被覆盖过的文件。

③ 压缩文件

bash 复制代码
gzip -k test 					//得到了一个.gz 结尾的压缩文件

之前的文件是 1M,压缩之后它只有 1056 字节。

注意:

a) 如果 gzip 不加任何选项,此时为压缩。压缩完该文件会生成后缀为 .gz 的压缩文件,并删除原来的文件。所以,推荐使用 gzip -k 来压缩源文件,这样会保留原来的文件。

b) 相同的文件内容,如果文件名不同,压缩后的大小也不同。

c) gzip 只能压缩单个文件,不能压缩目录。

2. bzip2

bzip2 的常用选项:

  • -k(keep):在压缩或解压时,保留输入文件;
  • -d(decompress):将压缩文件进行解压缩;
    ① 压缩文件
bash 复制代码
bzip2 -k test 				//得到一个.bz2 后缀的压缩文。

我用另外一种格式来压缩,来看看有什么东西。同样是一个 test 文件,我用 bzip2 来压缩的时候,它只有 45 个字节;我用 gzip 来压缩的时候,它有 1056 字节,所以说,bzip2 格式它的压缩率更高。

② 解压文件

bash 复制代码
bzip2 -kd mypwd.1.bz2

我删掉了 test 文件之后,我来把 test.bz 文件解压成 test,你看 test.bz 这个文件只有 45 字节,解压出来得到了 1M 字节。

注意:

  • 如果 bzip2 不加任何选项,此时为压缩
  • 压缩完该文件会生成后缀为 .bz2 的压缩文件, 并删除原来的文件。所以说,推荐使用 bzip2 -k 来压缩文件,这样可以保留原来的文件。
  • bzip2 只能压缩单个文件,不能压缩目录。
  • 单个文件的压缩使用 gzip 或 bzip2,压缩有两个参数:
    a) 压缩时间
    b) 压缩比。

一般情况下,小文件使用 gzip 来压缩,大文件使用 bzip2 来压缩。bzip2 的压缩率更高。

3. tar

实际上经常使用的是 tar 命令,它既可以打包压缩,又可以解压之后从包里面提取文件。很少用到 gzip 命令 和 bzip2 命令,因为它们只能处理文件不能处理目录。实际上你只要记住 tar 命令就足够了。

使用 tar 命令可以去指定可以使用 gzip 来压缩或者用 gzip 来解压,可以使用 bzip2 来压缩或者解压。那到底是压缩还是解压呢?你可以使用 -c 选项来表示创建新的文件,就是去压缩;使用 -x 表示解压。

tar 常用选项:

  • -c(create):表示创建用来生成文件包 。
  • -x:表示提取,从文件包中提取文件。
  • -t:可以查看压缩的文件。
  • -z:使用 gzip 方式进行处理,它与"c"结合就表示压缩,与"x"结合就表示解压缩。
  • -j:使用 bzip2 方式进行处理,它与"c"结合就表示压缩,与"x"结合就表示解压缩。
  • -v(verbose):详细报告 tar 处理的信息。
  • -f(file):表示文件,后面接着一个文件名。
  • -C <指定目录>:解压到指定目录。

例 1:tar 压缩文件

我们先来操作单个文件,c 表示创建文件;z 表示使用 gzip 方式去压缩文件;f 后面跟着文件。我想用这个命令来创建一个文件,创建这个文件的时候,我得去使用 gzip 把它压缩起来,f 跟的就是文件的名字,源头是 test。

这后缀 tar 表示说它是用的 tar 命令来创作的,gz 表示说它里面的压缩算法是使用 gzip。

来看看压缩效率。test 它使用 tar 命令的时候,用前面的命令的时候压缩到了 test.tar.gz 这么一个文件,1123 跟之前的 1056 差不多;对于同一个 test,它使用这个 tar 加上这个 -j 选项的时候,它得到了 test.tar.bz2 这么一个压缩文件,它的 122 跟之前的 45 也差不了多少。

我现在处理的是单个文件,实际上这个 tar 它可以处理一个目录。

例 2:tar 打包、gzip 压缩

① 把目录 dira 压缩、打包为 dira.tar.gz 文件:

bash 复制代码
tar czvf dira.tar.gz dira

注意:"tar --czvf" 与 "tar czvf" 是一样的效果,所以说,后面统一取消 "-"。

② 查看压缩文件:

bash 复制代码
tar tvf dira.tar.gz

③ 解压文件,可以用 -C 指定解压到哪个目录:

bash 复制代码
tar xzvf dira.tar.gz 					//解压到当前目录
tar xzvf dira.tar.gz -C /home/book 		//解压到/home/book。

你创建压缩文件的时候用的是 gzip 格式,解压的时候也得用 gzip 格式。

注意:不会提示覆盖当前目录。

例 3:tar 打包、bzip2 压缩

④ 把目录 dira 压缩、打包为 dira.tar.bz2 文件

bash 复制代码
tar cjvf dira.tar.bz2 dira

⑤ 查看压缩文件

bash 复制代码
tar tvf dira.tar.bz2

⑥ 解压文件,可以用 -C 指定解压到哪个目录

bash 复制代码
tar xjvf dira.tar.bz2 					//解压到当前目录: 
tar xjvf dira.tar.bz2 -C /home/book 	//解压到/home/book

2.3.6 网络命令

这个章节先不用看,没必要看。
注意 :实际上只要你的 Ubunut 能上网,比如执行"ping www.baidu.com"成功,那么就不要按本章来设置网络,你就不需要来看网络命令这一章节。
注意 :那么万一你的 Ubunut 不能上网的话,就比如说有些读者他用的不是我们提供的虚拟机,这时候你就来看第三篇第 1 章《>>>>>>>>配置 VMware 使用双网卡》,你添加一个 NAT 网卡,你只要有了 NAT 网卡,你的 Ubuntu 肯定就可以上网,有 NAT 网卡之后,只要你的 Windows 能上网,你的 Ubuntu 肯定就可以上网,也不需要阅读本章。
注意 :本章只是介绍性的文档,如果你看的话,不要去练习,你只要知道 ifconfig 它可以用来查看网络、设置 ip 就可以了,其他的暂时不用管。不要执行它的命令。

看我们的 Ubuntu 能否上网,打开终端:

bash 复制代码
ping www.baidu.com

没问题。Ctrl+C 退出,那么你就不需要来设置。

2.3.7 vi 编辑器

我们在嵌入式 Linux 开发过程中,经常要去修改某些文件,那如果是在 Ubuntu 里面去修改文件的话,你可以使用一些图形化的工具。(如桌面环境、文件浏览器、gedit 文件

那么对于命令行呢?你可以在命令行里面使用某些命令来打开这个文件。什么命令呢?是 gedit,就比如说我想去修改这个文件,使用 gedit 来修改这个文件,它就会帮你打开这么一个界面,这时候你就可以在里面修改文件,保存退出。

再比如说你想去修改这个 etc 目录下面的 environment,这个文件来看看它的权限,它是属于 root 用户的,我们去修改它的话肯定不行,就比如说你可以打开,增加一点东西保存,我们点击保存,这个保存按钮根本没有起作用,你关闭要么就是不保存退出,要么是 Cancel,要么另存为,你根本没有办法去保存、修改这个文件。

那么我想去修改这个文件怎么办呢?加上 sudo,你得临时切换成 root 用户,这时候你就可以去修改这个文件了,保存就会有效果了。

但是对于我们 Linux 开发板,它并没有这种图形化的界面,你怎么办呢?我们只能使用 vi 命令,这个 vi 命令它可以使用各种串口,使用这种工具来修改文件,它非常的方便,但是它用起来稍微有点难度。

我们这节介绍的就是 vi 命令。

vi 是一个命令,也是一个命令行下的编辑器,它有如下功能:

  • 打开文件、新建文件、保存文件
  • 光标移动
  • 文本编辑
  • (多行间|多列间)复制、粘贴、删除
  • 查找和替换

很多人不习惯在命令行下编辑文件,实际开发中也不会经常在命令行下编辑文件。但是在 Linux 系统中对文件做些简单修改时,使用 vi 命令的效率非常高。并且在很多时候,比如现场调试时,并没有 GUI 形式的编辑工具,vi 是唯一选择。

我们先来了解一下,对于 vi 命令,它有几种模式。

1. 模式

vi 编辑器有三种模式,各个模式侧重点不一样:

  1. 一般模式(光标移动、复制、粘贴、删除)
  2. 编辑模式(编辑文本)
  3. 命令行模式(查找和替换)

vi 编辑器的三种模式间切换如下图所示:

注意:

  • 当不知道处于何种模式时,按 ESC 键返回到一般模式。
  • wq(write quit)
  • i(insert)

你执行 vi 命令的时候,就比如说你可以去执行 vi 1.txt。如果这个文件不存在的话,它就会帮你去新建一个文件;如果这个文件已经存在的话,他会去打开这个文件。你还可以执行 vi 1.txt +行号,就比如说你可以打开它之后,让光标处于第 100 行,执行 vi 命令之后,它会打开一个编辑界面,这个时候 vi 命令它处于一般模式。

在一般模式里面,你可以使用各种箭头啊来移动光标,你还可以输入冒号,输入冒号之后就会进入命令行模式。在这个命令行模式里面,你可以在冒号之后输入各种命令,就比如说输入查找命令,就比如说输入跳转到某一行的命令。

那怎么从这个命令行模式里面退出来呢?按 ESC,你可以多按几次 ESC 键。在一般模式下面,我们又可以使用这些 i,a,使用这些字母让它进入到编辑模式,i 就插入嘛,它就可以去插入某些字符。

2. 文件的打开/新建/保存

我们来演示一下:

打开/新建

bash 复制代码
vi 2.txt							//新建 2.txt 文件

你看这样就可以了。

在新的文件里面,我现在先不加任何内容,现在它处于什么模式呢?它处于一般模式。那现在我想新建一个空文件行不行?可以的。

保存

我怎么退出呢?退出是一个命令,输入一个冒号,之后写 w 表示保存,q 表示退出。

bash 复制代码
:wq

我已经新建了一个 2.txt,它的大小是 0 字节,它里面没有任何东西。

我们再来修改 2.txt。我现在想在里面写入某些数据,怎么写呢?一般模式里面我想去编辑,你可以输入 i,可以输入 a,我们来输入 i 看看,输入 i,就 insert 插入的意思:

看到底下它提示说你可以插入,我现在插入字符 www.100ask.net,回车,www.100ask.org,回车,输入各种字符,然后干嘛呢,就比如说我想保存退出怎么办,你得先回到一般模式,它不能够直接进入到命令行模式,你必须按 ESC 键回到一般模式,然后再输入冒号。

按一下 ESC,可以多按几次都没有关系,然后输入冒号,之后保存并且退出。

bash 复制代码
www.100ask.net
www.100ask.org
wobookyouroot
  • ESC +
bash 复制代码
:wq

取消保存

怎么取消保存呢?我仍然修改这个 2.txt,就比如说我可以去修改第二行:

bash 复制代码
vi 2.txt +2

这个光标就跳到第二行,在最后面我输入什么字母呢,我输入 a,我想在光标后面插入,我输入一个 err。然后 ESC。

然后输入冒号,我刚才写入的是一个错误,我不想保存,可以按 q,q 表示退出(:q),我们直接输入回车看看会发生什么事情,它会提示你,你刚才写的东西还没保存呢。

再输入冒号,q 加感叹号(:q!),感叹号的意思就是我不要保存,它就可以退出了。

在编辑完成时,返回一般模式,方法如下:

  1. 输入:w 则保存文件,如果已经保存文件,输入:q 则退出文件
  2. 直接输入:wq 保存并退出
  3. 如果不想保存被修改的内容,则输入 :q! 强制退出。

这些命令列表如下:

命令 描述
x 保存当前文档并且退出
q 退出
w 保存文档
q! 退出 vi/vim,不保存文档
3. 编辑文件

打开文件后,默认处于"一般模式",这时可以输入以下字母:

指令 描述
i 在当前光标所在字符的前面,转为编辑模式
I 在当前光标所在行的行首转换为编辑模式
a 在当前光标所在字符的后面,转为编辑模式
A 在光标所在行的行尾,转换为编辑模式
o 在当前光标所在行的下方,新建一行,并转为编辑模式
O 在当前光标所在行的上方,新建一行,并转为编辑模式
4. 快速移动光标

当我们去编辑一个比较大的文件的时候,想去快速的移动怎么办?你当然可以上下箭头来翻页来滑动,但是这太慢了,就比如说你想跳到一个比较大的文件的最后你怎么跳?

在一般模式下,可以使用下面快捷键移动光标或是翻页:

移动光标
h (或左方向键) 光标左移一个字符
l (或右方向键) 光标右移一个字符
j (或下方向键) 光标下移一行
k (或上方向键) 光标上移一行
nG 或 ngg 光标移动到第 n 行首
n+ 光标下移 n 行
n- 光标上移 n 行
屏幕翻滚
Ctrl + f 屏幕向下翻一页,相当于下一页
Ctrl + b 屏幕向上翻一页,相当于上一页

详细介绍如下:

  1. 快速的定位到某一行:文件头、文件尾、指定某一行
  • ngg(:n+回车):光标移至第 n 行的行首(n 为数字,想要跳转的行),例如 :250+回车
  • 1gg(:1+回车):就跳到第一行的行首,就是文件头
  • 2gg(:2+回车):就跳到第二行的行首
  • G:转至文件结尾(小写模式下:Shift+g)
  1. 在某一行如何快速定位到某一列:
  • 0:(数字零)光标移至当前行行首
  • $:光标移至当前行行末
  • fx:搜索当前行中下一个出现字母 x 的地方
  1. 显示和隐藏行号
  • 显示行号::set number
  • 隐藏行号::set nonumber

注意:当你不知道 vi 当前处于何种模式时,使用 ESC 键返回到一般模式。

5. 文本复制/粘贴/删除/撤销

在一般模式下,可以执行以下命令:

复制、删除和粘贴
cc 删除整行,并且修改整行内容
x 删除光标所在的字符
X 删除光标前面的一个字符
dw 删除光标所在的单词(光标必须在单词的首字母)
D 删除光标之后的该行的内容
dd 删除该行,不提供修改功能
ndd 删除当前行向下 n 行
u 撤销上一步操作
nyy 复制当前行及其下面 n 行
p 粘贴最近复制的内容
s 删除光标所在字符
r 替换光标处字符

a) 复制

bash 复制代码
yy 								//复制当前行(y:yank(复制)) 
nyy 							//复制当前行及其后的 n-1 行(n 是数字)

b) 粘贴

bash 复制代码
p 								//粘贴(p:paste)

c) 删除

bash 复制代码
dd 								//删除光标所在行(d:delete)
ndd 							//删除当前行及其后的 n-1 行(n 是数字)
x 								//删除光标所在位置的字符

d) 撤销

bash 复制代码
u 								//撤销上一步操作
6. 文本查找和替换

在一般模式下,可以执行以下命令。

a) 查找

bash 复制代码
/pattern 						//从光标开始处向文件尾搜索 pattern,后按下 n 或 N(自动从头查找)

注意:

  • n:在同一个方向重复上一次搜索命令
  • N:在反方向重复上一次搜索命令
  • 在 /pattern 之前先跳到第一行则进行全文件搜索。

b) 替换

bash 复制代码
:%s/p1/p2/g 					//将文件中所有的 p1 均用 p2 替换
:%s/p1/p2/gc 					//替换时需要确认
  • "s" 全称:substitute,替换;
  • "g" 全称:global,全局;
  • "c" 全称:confirm,确认
    • 输入 y:表示替换
    • 驶入 n:表示不替换

vi 命令本身稍微有点复杂,当你熟练掌握 vi 命令之后,你很多时候都不想去使用这些图形化工具,因为它实在太方便了。

相关推荐
极客小张20 分钟前
基于STM32的智能充电桩:集成RTOS、MQTT与SQLite的先进管理系统设计思路
stm32·单片机·嵌入式硬件·mqtt·sqlite·毕业设计·智能充电桩
AndyFrank27 分钟前
mac crontab 不能使用问题简记
linux·运维·macos
筱源源43 分钟前
Kafka-linux环境部署
linux·kafka
算法与编程之美1 小时前
文件的写入与读取
linux·运维·服务器
xianwu5432 小时前
反向代理模块
linux·开发语言·网络·git
Amelio_Ming2 小时前
Permissions 0755 for ‘/etc/ssh/ssh_host_rsa_key‘ are too open.问题解决
linux·运维·ssh
Ven%3 小时前
centos查看硬盘资源使用情况命令大全
linux·运维·centos
m0_739312873 小时前
【STM32】项目实战——OV7725/OV2604摄像头颜色识别检测(开源)
stm32·单片机·嵌入式硬件
嵌入式小章3 小时前
基于STM32的实时时钟(RTC)教学
stm32·嵌入式硬件·实时音视频
TeYiToKu3 小时前
笔记整理—linux驱动开发部分(9)framebuffer驱动框架
linux·c语言·arm开发·驱动开发·笔记·嵌入式硬件·arm