查看PID所在的文件夹

1
2
cd /proc/23333  
ls -al

1. Ubuntu Linux 系统的介绍

1.1. Linux 操作系统的概述

Linux 是一种自由和开源的 UNIX 类操作系统,其源代码可以被公开研究、更改和分发。Linux 由芬兰的 Linus Benedict Torvalds 于 1991 年首次发布,其设计遵循了 POSIX 和 Unix 的标准。

Linux 是一个多用户、多任务、支持多线程和多 CPU 的操作系统。它能运行主要的 UNIX 工具软件、应用程序和网络协议,也支持 32 位和 64 位硬件。

Linux 的内核原始代码由 Linus Benedict Torvalds 撰写,但现在世界各地的程序员都参与了 Linux 的开发。根据开放源代码的特性,任何人都可以修改和改进 Linux,并且这种改动可以被广泛传播,让其他人也能从中受益。

1.2. Linux 和 Windows 的主要区别

对于 C 开发者来说,Linux 和 Windows 的主要区别体现在以下几个方面:

开发环境:Linux 提供了强大的终端和命令行工具,如 Bash Shell、sed、awk、grep 等,这些工具可以极大提高 C 程序员的生产力。另外,Linux 还支持了许多开源的编程工具,如 GCC、GDB、Valgrind 等。而在 Windows,这些工具可能需要额外安装,且可能不提供与 Linux 完全相同的功能。

系统调用和库:Linux 遵循 POSIX 标准,其系统调用和库与 Unix 和其他 Unix-like 系统(如 macOS)高度兼容。这意味着,基于 POSIX 的 C 程序可以在这些系统之间轻松迁移。而 Windows 的系统调用和库则有很大不同,需要使用 Windows API,这可能导致移植性问题。

文件系统:Linux 使用区分大小写的文件系统,而 Windows 默认不区分大小写。这可能在处理文件名时造成一些差异。此外,Linux 中所有内容都组织在一个单一的目录树下,包括文件、目录、设备等,这与 Windows 的驱动器字母(如 C:D:)有很大不同。

1.3. Linux 常见目录结构和作用

在 Linux 系统中,文件和目录的组织方式遵循了一种标准,称为文件系统层次结构标准(Filesystem Hierarchy Standard,FHS)。理解这些目录结构以及其各自的作用对于有效地使用和管理 Linux 系统是非常重要的。以下是 Linux 中一些最常见的目录及其作用:

目录 描述
/ 根目录,所有的目录都从这里开始。
/bin 包含了用户级别的基本命令,如 lscprm 等。
/sbin 包含了系统级别的命令,只有 root 用户可以执行。
/etc 包含所有系统管理所需要的配置文件和子目录。
/home 普通用户的主目录,例如 /home/john 是用户 john 的主目录。
/root root 用户(系统管理员)的主目录。
/var 存储着在正常运行中的系统不断增加的文件。
/usr 存放和共享只读的数据,包括很多用户级别的应用程序、库等。
/tmp 用于存放临时文件,这些文件在系统重启后会被删除。
/lib 包含系统最基本的动态链接共享库。
/opt 用于存放所有的可选应用软件包。
/dev 包含所有的设备文件,硬件设备被视为文件,可以像操作文件一样操作这些设备。

1.4. Ubuntu 的特点和优势

Ubuntu 以其易用性、稳定性、丰富的软件和社区支持,以及强大的商业支持赢得了用户的喜爱。不少供应商的 SDK 需要在特定版本的 Ubuntu 下构建,这也是许多公司选择 Ubuntu 的原因之一。公司可以通过维护内部的镜像源,用户可以将 apt 源设置为公司的镜像源,这将显著提升 deb 包的下载速度,有效提高工作效率。

1.5. Ubuntu 的配置

运行在 VirtualBox 环境下的 Ubuntu 可以通过多种配置技巧来提升开发效率,以下是一些常见的配置方法:

关闭屏幕锁定:在 Ubuntu 中,屏幕锁定功能可能会在你不操作电脑一段时间后自动启动,这可能会带来一些不便,因此建议关闭屏幕锁定。虽然这样可能会降低一些安全性,但如果你在已经给宿主机设置了密码和屏幕锁定的情况下,则已经处于一个安全的环境中,因此可以关闭虚拟机的屏幕锁定,这可以提高你的工作效率。

安装增强功能套件:VirtualBox 的 “增强功能套件” 可以提供更好的视频性能,更强大的虚拟机控制,以及文件和文件夹的拖放功能。在 VirtualBox 的 “设备” 菜单中选择 “安装增强功能”,然后在虚拟机中运行自动启动的安装程序。

设置共享文件夹:在主机和虚拟机之间共享文件可以大大提高工作效率。在 VirtualBox 的设置中,你可以为虚拟机设置一个或多个共享文件夹。

使用双向剪贴板:在主机和虚拟机之间共享剪贴板可以让你在两个环境中更轻松地复制和粘贴文本。在 VirtualBox 的设置中,选择 “常规”,然后在 “高级” 选项卡中设置 “双向” 剪贴板。

调整处理器分配:如果你的主机有多个处理器核心,你可以调整虚拟机使用的核心数,以获得更好的性能。在 VirtualBox 的设置中,选择 “系统”,然后在 “处理器” 选项卡中设置核心数。

调整内存分配:可以调整虚拟机使用的内存数,以获得更好的性能。通常,根据你的电脑的硬件配置和你要运行的任务,你可以设置为你电脑 RAM 的一半。

通过 SSH 连接到虚拟机:,如果你主要用命令行进行工作,完全可以关闭图形界面以节省资源。你可以通过 SSH 连接到虚拟机,这样可以显著减少内存的使用,从而提高系统的整体性能。建议在熟悉 Samba 和共享文件夹的操作后,有余力和有需要的情况下再开展。下面是如何进行这些操作的步骤:

  1. 关闭图形界面:Ubuntu 默认启动图形用户界面,但是我们可以设置为命令行模式,以下是如何设置的步骤:
    • 打开终端。
    • 输入 sudo systemctl set-default multi-user.target 并回车。你可能需要输入你的密码。
    • 重启你的系统,你会发现系统启动后进入命令行模式。
  2. 设置 SSH 连接:为了远程访问你的 Ubuntu 系统,你需要安装并设置 SSH 服务,以下是如何设置的步骤:

在你的 Ubuntu 系统中,打开终端。

  • 输入 sudo apt-get update 来更新你的包列表。
  • 输入 sudo apt-get install openssh-server 来安装 SSH 服务器。
  • 输入 sudo systemctl start ssh 来启动 SSH 服务。
  • 输入 sudo systemctl enable ssh 来设置 SSH 服务在启动时自动运行。

现在你可以从你的主机或其他电脑通过 SSH 连接到你的 Ubuntu 系统了,命令如下:

1
ssh username@ip-address

其中,username 是你的 Ubuntu 用户名,ip-address 是你的 Ubuntu 系统的 IP 地址。

  1. 调整内存分配:现在你可以进一步调整内存分配了。现在你可以设置的更小一些,因为你关闭了图形界面。

通过关闭图形界面并使用 SSH 连接,你可以使你的 Ubuntu 虚拟机更高效地使用资源。

如果你之后需要再次使用 Ubuntu 的图形界面,你可以按照以下步骤操作:

  1. 打开虚拟机内的终端。
  2. 输入以下命令并回车:sudo systemctl set-default graphical.target。这将把默认目标设置回图形用户界面。
  3. 重启你的系统。你可以输入 sudo reboot 命令并回车来重启你的系统。

重启后,你的 Ubuntu 系统会启动到图形用户界面。

2. Ubuntu Linux 环境的基本操作

2.1. Nautilus 文件管理器

Nautilus 是 Ubuntu 系统中默认的文件管理器,提供了强大的文件浏览和管理功能。

Nautilus 基础用法

Nautilus 文件管理器允许你浏览和管理文件和目录。你可以通过双击桌面上的 “文件” 图标,或者在 Dash(Ubuntu 默认的应用启动器)中搜索 “文件” 来打开 Nautilus。

Nautilus 的主窗口分为三个主要部分:

  • 左侧的边栏显示了你的文件系统的各个位置,包括你的主目录、网络位置、已连接的设备和书签。
  • 中央的主视图显示了当前选定位置的文件和目录。
  • 顶部的工具栏提供了各种文件操作的按钮,如创建新文件夹、改变视图模式、搜索文件等。

Nautilus 快捷键

Nautilus 提供了许多快捷键以便更快速、更有效地进行文件操作。以下是一些常用的快捷键:

  • Ctrl+H:显示或隐藏隐藏文件。在 Linux 中,隐藏文件的文件名是以 “.” 开头的。
  • Ctrl+L:高亮地址栏,让你可以输入路径或 URL,这对于访问网络位置非常有用。
  • Ctrl+N:打开新的 Nautilus 窗口。
  • Ctrl+T:在当前 Nautilus 窗口中打开新的标签。
  • Ctrl+W:关闭当前 Nautilus 窗口或标签。
  • Ctrl+D:将当前位置添加到书签。
  • Ctrl+1Ctrl+2:在图标视图和列表视图之间切换。

通过 SMB 协议访问特定 URL

Nautilus 支持通过多种协议来访问网络位置,包括 SMB、FTP、SFTP 等。你可以直接在地址栏中输入 URL 来访问这些位置。

以下是通过 SMB 协议访问特定 URL 的步骤:

  1. 打开 Nautilus 并按 Ctrl+L 来高亮地址栏。
  2. 在地址栏中输入 SMB URL,格式为 smb://hostname_or_IP/shared_folder。例如,如果你想访问名为 “file.com” 的主机上的 “Public” 共享文件夹,你应该输入 smb://file.com/Public
  3. 按 Enter 键。如果需要,输入你的用户名和密码,然后点击 “连接”。

这样,你就可以在 Nautilus 中浏览和管理 SMB 共享的文件和目录了。

2.2. 命令语法

Bash 命令的基本语法是 command [options] [arguments]

  • command 是想要执行的命令的名称。
  • [options] 是可选的,用于修改命令的行为。它们通常以破折号 - 开始。例如,ls -l 中的 -l 是一个选项,它告诉 ls 以列表形式显示文件。
  • [arguments] 也是可选的,它们是命令要操作的对象。例如,cd /path/to/directory 中的 /path/to/directory 是一个参数,它告诉 cd 要切换到哪个目录。

2.3. 命令提示符

在 Bash shell 中,命令提示符是出现在每行命令前的字符或一组字符。它通常用于提供有关环境或当前状态的信息。

默认的 Bash 命令提示符是一个美元符号 $。对于 root 用户,命令提示符是井号 #

你可以通过修改 PS1 环境变量来自定义命令提示符。例如,如果你想让命令提示符显示当前目录,你可以输入 export PS1='\w\$ '。这将使命令提示符显示当前工作目录的完整路径。

你可以通过编辑 ~/.bashrc~/.bash_profile 文件(取决于你的系统和特定的环境)来使改变的命令提示符在每次新开启的 Bash 会话中都自动显示当前目录。

下面是具体步骤:

  1. 使用文本编辑器打开 ~/.bashrc~/.bash_profile 文件。例如,你可以在 Bash 中输入 nano ~/.bashrcnano ~/.bash_profile
  2. 在文件的末尾添加以下行:
1
export PS1='\w\$ '
  1. 保存并关闭文件。
  2. 为了让改变立即生效,你需要在 Bash 中输入 source ~/.bashrcsource ~/.bash_profile。或者,你可以通过关闭并重新打开 Bash 会话来让改变生效。

这样,每次新开启的 Bash 会话都将显示当前目录在命令提示符中。

请注意,~/.bashrc 文件通常用于非登录 shell (例如,新打开的终端窗口),而 ~/.bash_profile 文件通常用于登录 shell (例如,通过 SSH 登录)。在某些系统中,可能只有其中一个文件存在。如果都存在,可以选择一个进行编辑,或者在 ~/.bash_profile 中添加一行 source ~/.bashrc,以确保无论使用哪种类型的 shell,都会读取 ~/.bashrc 中的设置。

2.4. 系统操作

正确地管理虚拟机的状态是非常重要的,以确保数据的完整性和系统的稳定性。以下是一些关于管理虚拟机状态的建议:

  1. 保存状态:在 VirtualBox 中,你可以选择保存虚拟机的当前状态,而不是完全关闭虚拟机。这就像是在物理机上休眠。当你下次启动虚拟机时,它会恢复到你保存状态时的情况。你可以在 VirtualBox 的 “机器” 菜单中选择 “保存状态” 来进行这个操作。
  2. 优雅地关机:如果你需要完全关闭虚拟机,你应该在虚拟机内部执行关机命令,而不是强制关闭虚拟机。在 Ubuntu 中,你可以输入 sudo poweroff 命令来优雅地关机。这会让系统有足够的时间来正确地关闭所有的进程和服务,然后安全地关机。

强制关闭虚拟机(就像物理机突然断电一样)可能会导致数据丢失或系统错误。因此,你应该尽量避免这样做,除非你没有其他选择。

通过正确地管理虚拟机的状态,你可以最大限度地保护你的数据,并确保系统的稳定性和可靠性。

如果你的磁盘空间不足,你需要找到占用大量空间的文件或目录。

  • 检查磁盘使用情况:
1
2
# df = disk free
df -h
  • 目录大小统计
1
2
3
4
5
6
# du = disk usage 磁盘使用率
du -sh
# 查看当前目录各级子目录空间占用情况
du -sh .
# 查看当前目录下一级子文件和子目录占用的磁盘容量
du -lh --max-depth=1

2.5. 环境变量

在 Linux 操作系统中,环境变量是用户和系统进程之间的一种信息交互方式,它们包含了诸多用于控制系统行为的重要数据。环境变量的值可以在当前 Shell 会话以及其启动的任何子进程中被访问和使用。环境变量可包含诸如软件安装的路径、当前用户的主目录或者可执行文件的默认位置等信息。下面我们将以 PATH 环境变量为例,来讲解如何在 Linux 中定义和修改环境变量。

PATH 是一个在 Linux 和其他 Unix-like 系统中非常关键的环境变量,它决定了 Shell 在哪些目录下查找用户输入的命令。当你在终端输入一个命令,Shell 将在 PATH 变量指定的目录中,依次查找对应的可执行文件。

你可以使用 echo 命令查看当前的 PATH 变量值,例如:

1
echo $PATH

此命令会返回一个由冒号(:)分隔的目录列表,这些目录就是 Shell 查找命令的路径。

如果你想修改 PATH 变量,有两种方式:一种是临时修改,另一种是永久修改。

临时修改:此种修改方式只在当前的 Shell 会话中有效。当你关闭终端或启动新的 Shell 会话时,修改不会被保存。例如,你可以使用下列命令临时添加一个目录到 PATH 变量:

1
export PATH=$PATH:/path/to/your/dir

在上述命令中,/path/to/your/dir 是你希望添加的新目录路径。

永久修改:如果你希望修改的 PATH 变量能在新的 Shell 会话或系统重启后仍然有效,你应该在 Shell 的配置文件中修改 PATH 变量。对于 Bash Shell,你可以在用户的 home 目录下的 .bashrc.bash_profile 文件中修改 PATH 变量。如下所示:

打开 .bashrc 文件:

1
nano ~/.bashrc

在文件的末尾添加下列行:

1
export PATH=$PATH:/path/to/your/dir

保存并关闭文件。然后,你可以通过执行下列命令使更改立即生效:

1
source ~/.bashrc

以上就是如何在 Linux 中定义和修改 PATH 环境变量的过程。对于其他环境变量,你可以采取类似的步骤来进行修改和定义。在实际应用中,你应当根据实际需求来设置和使用环境变量。

2.6. 文件和目录操作

在 Ubuntu Linux 中,有一系列的命令用于管理文件和目录:

下面是对以上每个命令的详细介绍,包括常见的选项和操作技巧:

**ls**:这个命令用于列出当前目录的内容。常用的选项包括:

  • -l:以详细格式列出文件 / 目录信息,包括权限、所有者、大小、修改时间等。
  • -a:显示所有文件,包括隐藏文件(以 . 开头的文件)。
  • -h:以易读的格式显示文件大小(例如,显示 1K 234M 2G)。
  • -1:以一列的方式显示文件和目录,这在需要清晰看到每个文件和目录时非常有用。

例如,ls -lha 会以详细格式列出所有文件,包括隐藏文件,并以易读的格式显示文件大小。

此外,ls 命令可以与管道 |grep 命令结合使用来过滤输出结果。例如,如果你只想列出所有 .txt 文件,你可以使用 ls | grep .txt 命令。这里,grep .txt 会过滤出包含 .txt 的行。

**tree**:这个命令用于以树状图列出目录的内容。常用的选项包括:

  • -f:在每个文件或目录前面显示完整的路径前缀。这会使得每个文件名前面都有一个对应的路径。
  • -i:不显示树状图结构。只显示文件和目录的名称。这个选项通常用来提供一个非分层的文件列表。
  • -n:禁止打印文件和目录名的颜色。默认情况下,tree命令会使用颜色来标记文件和目录的类型,例如目录、符号链接、文件等。使用 -n 选项,tree将只以纯文本的形式打印名称。
  • -d:只显示目录,不显示文件。这可以帮助你快速查看目录的结构,而忽略其中的文件。

例如,tree -f 会以完整的路径前缀列出所有文件和目录。tree -i 则只显示文件和目录的名称,而不显示它们的结构。

此外,tree 命令可以使用 -P 选项配合通配符,来匹配特定的文件或目录。例如,如果你只想列出所有 .txt 文件,你可以使用 tree -P '*.txt' 命令。这里,-P '*.txt' 会过滤出所有后缀为 .txt 的文件。

**cd**:这个命令用于改变工作目录。你可以使用相对路径或绝对路径。以下是一些常见的使用方式:

  • cd Documents:将进入当前目录下的 “Documents” 目录。
  • cd /home/user/Documents:将进入用户主目录下的 “Documents” 目录。
  • cd ..:返回上级目录。
  • cdcd ~:返回用户主目录。

此外,如果你想切换到上一次的工作目录,你可以使用 cd - 命令。这个命令会将当前的工作目录切换到上一次的工作目录。例如,如果你当前在 /home/user/Documents 目录,然后你执行 cd /etc 命令进入到 /etc 目录,此时你可以通过执行 cd - 命令快速切换回 /home/user/Documents 目录。

**pwd**:这个命令用于显示当前工作目录的完整路径。它没有额外的选项。

**cp**:这个命令用于复制文件或目录。常用的选项包括:

  • -r-R:递归复制,用于复制目录及其内部的所有文件和子目录。
  • -i:在覆盖文件之前提示用户。
  • -v:在复制过程中显示详细信息。
  • -f:强制复制,即如果目标文件已经存在,不会询问用户,直接覆盖。

例如,cp -Riv source_dir destination_dir 将复制整个 source_dir 目录(包括其内部的所有文件和子目录)到 destination_dir,并在覆盖文件之前提示用户,同时在过程中显示详细信息。

如果使用 -f 选项,如 cp -Rfv source_dir destination_dir,则在目标目录存在相同文件时,会直接进行覆盖,不会询问用户。

**mv**:这个命令用于移动或重命名文件或目录。常用的选项包括:

  • -i:在覆盖文件之前提示用户。
  • -v:在移动过程中显示详细信息。

例如,mv -iv old.txt new.txt 将把 old.txt 文件重命名为 new.txt,在覆盖文件之前会提示用户,同时显示详细信息。

**rm**:这个命令用于删除文件或目录。常用的选项包括:

  • -r-R:递归删除,用于删除目录及其内部的所有文件和子目录。
  • -i:在删除文件之前提示用户。
  • -v:在删除过程中显示详细信息。
  • -f:强制删除,即不会询问用户,直接删除目标文件或目录。如果文件不存在,也不会显示错误信息。

例如,rm -Riv target_dir 将删除整个 target_dir 目录(包括其内部的所有文件和子目录),并在删除文件之前提示用户,同时在过程中显示详细信息。

如果使用 -f 选项,如 rm -Rfv target_dir,则在删除目标目录时,会直接进行删除,不会询问用户。

**mkdir**:这个命令用于创建新目录。常用的选项包括:

  • -p:创建多级目录。如果中间的某些目录不存在,会自动创建。

例如,mkdir -p Dir/SubDir 将创建一个名为 “Dir” 的目录和一个名为 “SubDir” 的子目录。

**rmdir**:这个命令用于删除空目录。如果一个目录不为空(即,包含其他文件或子目录),则不能用 rmdir 删除。在这种情况下,你需要使用 rm -rrm -R 命令。

2.7. 链接

在 Linux 中,链接是一种特殊的文件类型,它允许我们创建对现有文件或目录的引用。链接有两种类型:硬链接和符号链接,也叫软链接。

硬链接

硬链接是一个文件在磁盘上的一个引用。一个文件可能有一个以上的硬链接,每个硬链接都对应同一个文件的数据。这意味着,即使原始文件名被删除,只要至少有一个硬链接存在,文件的数据就可以被访问。

我们可以使用 ln 命令来创建硬链接。例如,要为一个名为 file1 的文件创建一个名为 link1 的硬链接,可以使用以下命令:

1
ln file1 link1

虽然硬链接在许多情况下都很有用,但它们也有一些限制。首先,硬链接不能跨文件系统,也就是说,硬链接只能在同一文件系统的文件之间创建。其次,硬链接不能引用目录,只能引用文件。

软链接

符号链接(软链接)是对另一个文件或目录的间接指针。与硬链接不同,符号链接可以跨文件系统,可以链接目录,且它们是包含了目标文件路径的特殊文件。

我们可以使用 ln 命令的 -s 选项来创建符号链接。例如,要为一个名为 file1 的文件创建一个名为 link1 的符号链接,可以使用以下命令:

1
ln -s file1 link1

与硬链接不同,如果删除了符号链接的目标文件,符号链接将变得无效。此外,符号链接的权限位通常显示为 lrwxrwxrwx,但实际上符号链接的权限由其目标文件的权限决定。

查看链接

我们可以使用 ls -l 命令来查看文件的链接信息。对于硬链接,ls -l 将显示文件的链接数量;对于符号链接,ls -l 将显示链接的目标文件。

删除链接

删除链接的方式与删除普通文件相同,使用 rm 命令。需要注意的是,删除一个硬链接不会影响其它链接,只有当所有链接都被删除,文件才会被真正删除。对于符号链接,删除链接不会删除目标文件。

以上就是 Linux 中的链接的基本概念和使用。理解和掌握链接,对于有效地管理和组织文件系统中的文件和目录具有重要意义。

2.8. 打包和解压

tar 命令

tar(磁带存档)命令是 Unix 和 Linux 系统中用于文件打包和解压的工具。tar 可以将多个文件和目录打包为一个 tar 文件,也可以将 tar 文件解压到其组成的文件和目录。以下是 tar 命令的一些常用选项和用法:

创建存档:使用 -c 选项创建新的 tar 文件。

1
tar -cvf archive.tar file1.txt file2.txt

这会创建一个名为 archive.tar 的文件,其中包含 file1.txtfile2.txt

列出存档内容:使用 -t 选项列出 tar 文件的内容。

1
tar -tvf archive.tar

这会列出 archive.tar 文件中的所有文件和目录。

解压存档:使用 -x 选项解压 tar 文件。

1
tar -xvf archive.tar

这会解压 archive.tar 文件中的所有文件和目录。

带有 gzip 压缩的存档:使用 -z 选项创建或解压带有 gzip 压缩的 tar 文件。

1
tar -czvf archive.tar.gz file1.txt file2.txt

这会创建一个 gzip 压缩的 tar 文件 archive.tar.gz,其中包含 file1.txtfile2.txt

1
tar -xzvf archive.tar.gz

这会解压 gzip 压缩的 tar 文件 archive.tar.gz

带有 bzip2 压缩的存档:使用 -j 选项创建或解压带有 bzip2 压缩的 tar 文件。

1
tar -cjvf archive.tar.bz2 file1.txt file2.txt

这会创建一个 bzip2 压缩的 tar 文件 archive.tar.bz2,其中包含 file1.txtfile2.txt

1
tar -xjvf archive.tar.bz2

这会解压 bzip2 压缩的 tar 文件 archive.tar.bz2

在上述选项中,v 是可选的,它表示 “verbose”(详细),如果使用该选项,tar 命令会打印正在进行的操作。

tar 命令是一个非常重要的工具,对于文件的打包和解压,以及和其他系统的文件交换,它都是非常有用的。

unzip 命令

unzip 是一个在 Unix 和 Linux 系统中用于解压缩 ZIP 文件的命令。以下是 unzip 命令的一些常用选项和用法:

解压缩 ZIP 文件:不带任何选项,直接使用 unzip 命令可以解压缩 ZIP 文件。

1
unzip archive.zip

这会解压缩 archive.zip 文件中的所有文件和目录到当前目录。

列出 ZIP 文件内容:使用 -l 选项可以列出 ZIP 文件的内容。

1
unzip -l archive.zip

这会列出 archive.zip 文件中的所有文件和目录,但不会解压缩。

解压缩到指定目录:使用 -d 选项可以解压缩 ZIP 文件到指定目录。

1
unzip archive.zip -d /path/to/directory

这会解压缩 archive.zip 文件到 /path/to/directory 目录。

测试 ZIP 文件:使用 -t 选项可以测试 ZIP 文件的完整性。

1
unzip -t archive.zip

这会检查 archive.zip 文件中的所有文件是否完整。

unzip 命令是一个非常重要的工具,对于处理 ZIP 文件,无论是解压缩还是检查 ZIP 文件的完整性,它都是非常有用的。

2.9. 文本文件的操作

在 Ubuntu Linux 中,有几种方法可以查看文本文件的内容:

  • cat:显示文件的全部内容。例如,cat file.txt 会显示 file.txt 的全部内容。
  • moreless:用分页的方式显示文件内容。例如,more file.txtless file.txt 会以分页方式显示 file.txt
  • tail:显示文件的最后几行。例如,tail file.txt 会显示 file.txt 的最后 10 行。
  • head:显示文件的前几行。例如,head file.txt 会显示 file.txt 的前 10 行。

2.10. 计算哈希值

在 Unix 和 Linux 系统中,可以使用 md5sumsha256sum 命令计算文件的 MD5 和 SHA-256 哈希值。这些命令可以用于验证文件的完整性和验证下载的文件是否被篡改。

计算文件的 MD5 哈希值

1
md5sum file.txt

这将返回 file.txt 的 MD5 哈希值。

计算文件的 SHA-256 哈希值

1
sha256sum file.txt

这将返回 file.txt 的 SHA-256 哈希值。

注意:上述命令输出的哈希值应该与预期的哈希值或提供者给出的哈希值匹配,以确保文件完整性和防止篡改。如果两个哈希值不匹配,那么文件可能已经被更改或损坏。

2.11. 编程和系统管理

在编程和系统管理中,还常用如下命令:

  • diff 命令

diff 命令用于比较两个文件的不同点。这对于查看两个版本的文件之间的差异非常有用。例如,你可以使用以下命令比较 file1file2

1
diff file1 file2

这将输出 file1file2 之间的所有差异。

  • vimdiff 命令

vimdiffvim 文本编辑器的一个模式,用于显示两个或多个文件的差异。它的使用方式和 diff 类似,但它提供了一个交互式的界面,可以更方便地浏览和编辑差异。例如:

1
vimdiff file1 file2

这将在 vim 中打开 file1file2,并在分割的窗口中显示它们的差异。

  • patch 命令

patch 命令用于将由 diff 生成的差异应用到文件中。这对于应用别人的更改或撤销自己的更改非常有用。例如,如果你有一个 file.diff 包含了 file 的一些更改,你可以使用以下命令应用这些更改:

1
patch file file.diff

这将应用 file.diff 中的所有更改到 file 中。

  • file 命令

file 命令用于确定文件类型。这个命令对于查看未知文件的信息非常有用。它不仅可以识别文本文件,还可以识别二进制文件,如程序可执行文件。

示例:

1
file myscript.sh

这将告诉你 myscript.sh 是什么类型的文件。

2.12. 输入输出重定向

在 Unix 和 Linux 系统中,>>><<< 是用于输入输出重定向的操作符。这些操作符可以帮助你将命令的输出写入文件,或者从文件中读取输入。

  • >:这个操作符将命令的输出重定向到一个文件。如果文件已经存在,它会被覆盖。例如,echo Hello > file.txt 会将 “Hello” 写入 file.txt,如果 file.txt 已经存在,它的内容会被 “Hello” 替换。
  • >>:这个操作符将命令的输出追加到一个文件。如果文件已经存在,新的内容会被添加到文件的末尾。例如,echo Hello >> file.txt 会将 “Hello” 添加到 file.txt 的末尾。
  • <:这个操作符将文件的内容作为命令的输入。例如,sort < file.txt 会将 file.txt 的内容排序。
  • <<:这个操作符用于创建一个 “here-document”。”here-document” 是一个在 shell 脚本中使用的输入重定向方式,它可以将多行的输入重定向到一个命令。例如:
1
2
3
4
cat << EOF
Hello
World
EOF

这个命令会输出:

1
2
Hello
World

EOF 是 “End of File” 的缩写,它是 “here-document” 的结束标志。你可以使用其他的单词作为结束标志,但 EOF 是最常见的。在 << EOFEOF 之间的所有行都会被视为输入内容。

在 C 程序中,scanf 函数用于从标准输入(通常是键盘)读取数据。你可以使用输入重定向操作符(<)将文件的内容作为输入提供给 scanf 函数。

例如,假设你有一个 C 程序 program.c,它使用 scanf 函数读取两个整数:

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

int main ()
{
int a, b;
scanf ("% d % d", &a, &b);
printf ("You entered: % d and % d
", a, b);
return 0;
}

你可以先编译这个程序:

1
gcc program.c -o program

然后,你可以创建一个包含两个整数的文件 input.txt

1
echo "123 456" > input.txt

最后,你可以使用输入重定向操作符将 input.txt 的内容作为输入提供给 program

1
./program < input.txt

这个命令会输出:

1
You entered: 123 and 456

这说明 scanf 函数已经成功地从 input.txt 中读取了两个整数。这种方法对于需要大量输入或者需要重复测试的情况非常有用。

2.13. 剪切

cut 是一个在 Linux 和 Unix 系统中常用的命令行工具,它用于从文件或标准输入中提取或 “剪切” 出列的部分。cut 命令主要用于处理文本数据,特别是处理分隔符分隔的数据。下面是一些常用的 cut 命令选项以及使用示例。

cut 命令的选项:

  • -d:指定字段的分隔符,默认为制表符。例如,-d ':' 会设置分隔符为冒号。
  • -f:指定要显示的字段。例如,-f 1 会显示第一个字段,-f 1,3 会显示第一个和第三个字段,-f 1-3 会显示第一到第三个字段。
  • -c:指定要显示的字符。例如,-c 1-10 会显示每行的第一到第十个字符。

cut 命令的使用示例:

假设有一个文件 users.txt,内容如下:

1
2
alice:secret:1000:1000:Alice:/home/alice:/bin/bash
bob:secret:1001:1001:Bob:/home/bob:/bin/bash

以下是一些 cut 命令的使用示例:

  1. 获取用户名:cut -d ':' -f 1 users.txt。这个命令会显示 users.txt 文件中的每一行的第 1 个字段,即用户名。
  2. 获取用户 ID:cut -d ':' -f 3 users.txt。这个命令会显示 users.txt 文件中的每一行的第 3 个字段,即用户 ID。
  3. 获取用户名和用户 ID:cut -d ':' -f 1,3 users.txt。这个命令会显示 users.txt 文件中的每一行的第 1 个和第 3 个字段,即用户名和用户 ID。

以上就是 cut 命令的基本用法。在处理文本文件时,cut 命令是一个非常有用的工具。

2.14. 排序和去重

sort 命令

sort 的主要功能是对输入行进行排序。sort 可以基于字符串或数字排序,也可以基于字段排序。以下是一些常用的 sort 命令选项:

  • -n:基于数字值进行排序。
  • -r:反向排序,即降序排序。
  • -k:按照指定的字段进行排序。

以下是一个 sort 命令的基本用法:

1
sort -n -k 2 file.txt

这个命令会按照 file.txt 文件中的第2个字段进行数字排序。

uniq 命令

uniq 的主要功能是从输入中过滤掉重复的行。uniq 命令通常与 sort 命令结合使用,因为 uniq 只能检测相邻的重复行。以下是一些常用的 uniq 命令选项:

  • -d:仅显示重复出现的行。
  • -u:仅显示非重复的行。
  • -c:显示每行在输入文件中出现的次数。

以下是一个 uniq 命令的基本用法:

1
sort file.txt | uniq

这个命令会先对 file.txt 文件进行排序,然后通过 uniq 删除所有重复的行。

uniqsort 命令都是处理文本文件的强大工具,它们可以帮助你进行数据清理和预处理,特别是在处理大量数据时。

2.15. 统计

wc(word count)命令是一个常用的 Unix/Linux 命令,它用于计算文本文件中的字节数、字数、行数。该命令接收文件名作为参数,然后返回三个值:行数、字数和字节数。

wc 的常用选项包括:

  • -l:仅打印行数。
  • -w:仅打印字数。
  • -c:仅打印字节数。

以下是一些常见的 wc 命令使用示例:

计算文件的行数、字数和字节数

1
wc file.txt

这将返回三个值:file.txt 的行数、字数和字节数。

仅计算文件的行数

1
wc -l file.txt

这将返回 file.txt 的行数。

仅计算文件的字数

1
wc -w file.txt

这将返回 file.txt 的字数。

仅计算文件的字节数

1
wc -c file.txt

这将返回 file.txt 的字节数。

2.16. 搜索和替换

在 Linux 系统中,有许多强大的命令行工具可以帮助你进行搜索和替换操作,包括但不限于 grepsedawkfind 等。下面是一些详细的使用这些工具进行搜索和替换的方法:

使用 grep 进行搜索

grep 命令是一个强大的文本搜索工具,它可以在文件或者标准输入(stdin)中搜索与指定模式相匹配的行。例如,下面的命令会在 file.txt 文件中搜索包含 ‘pattern’ 的所有行:

1
grep 'pattern' file.txt

这个命令将会在终端输出所有包含 ‘pattern’ 的行。但是,如果匹配的内容非常多,直接在终端显示可能会导致结果淹没在信息之中,影响查看。在这种情况下,你可以考虑将输出结果重定向到一个文件中,如下所示:

1
grep 'pattern' file.txt > output.txt

这个命令会将所有包含 ‘pattern’ 的行输出到 output.txt 文件中,如果 output.txt 文件已经存在,这个命令会覆盖原有的文件内容。如果你想保留原有内容,可以使用 >> 追加内容:

1
grep 'pattern' file.txt >> output.txt

此外,你还可以使用 -r(或 --recursive)选项在目录及其子目录中递归搜索,或者使用 -i(或 --ignore-case)选项忽略大小写。例如:

1
grep -r 'pattern' /path/to/directory > output.txt

这个命令会从 /path/to/directory 开始,递归搜索所有文件中包含 ‘pattern’ 的行,并将结果输出到 output.txt 文件中。

请注意,grep 命令还有许多其他选项,可以提供更多的搜索功能,例如只显示匹配数量(-c)、显示行号(-n)、使用 Perl 正则表达式(-P)等等。你可以通过 man grepgrep --help 来查看更多信息。

使用 sed 进行替换

sed 是一个流编辑器,它可以对输入流(文件或者其他命令的输出)进行处理。最常见的用法之一是进行替换操作:

1
sed's/pattern/replacement/g' file.txt

这个命令会将 file.txt 中的 ‘pattern’ 替换为 ‘replacement’。这里的 g 表示全局替换,如果去掉 g,只会替换每一行的第一个匹配。

sed-i 选项是 sed 命令中的一个非常重要的选项,用于直接修改文件。在没有 -i 选项的情况下,sed 命令会将修改后的结果输出到标准输出(通常是终端或其他命令),原文件保持不变。如果你添加了 -i 选项,sed 将直接修改文件。

例如,下面的命令会将 file.txt 中的 ‘pattern’ 替换为 ‘replacement’,并且直接修改 file.txt

1
sed -i's/pattern/replacement/g' file.txt

在使用 -i 选项时,你可以提供一个扩展名,sed 会创建一个带有该扩展名的备份文件。例如,下面的命令会将 file.txt 中的 ‘pattern’ 替换为 ‘replacement’,并且创建一个名为 file.txt.bak 的备份文件:

1
sed -i.bak's/pattern/replacement/g' file.txt

这在你想保留原始文件的情况下非常有用。

同样,你可以用 -i 选项与 find 命令结合,批量修改多个文件。例如,下面的命令会在当前目录及其子目录中的所有 .txt 文件中,将 ‘pattern’ 替换为 ‘replacement’:

1
find . -name "*.txt" -exec sed -i's/pattern/replacement/g' {} \;

这里的 {}find 找到的每个文件的占位符,\; 表示 -exec 选项的结束。

使用 awk 进行更复杂的处理

awk 是一个强大的文本处理工具,它可以对输入的每一行进行更复杂的处理。例如,下面的命令会打印 file.txt 中包含 ‘pattern’ 的行的第一列:

1
awk '/pattern/ {print $1}' file.txt

awk 命令中,{print $1} 的含义是:对于每一行,打印第一列的内容。

awk 中,$0 表示整行的内容,$1 表示第一列的内容,$2 表示第二列的内容,以此类推。列的默认分隔符是空格或者制表符,但你可以使用 -F 选项指定其他的分隔符。

所以,awk '/pattern/ {print $1}' file.txt 这个命令的意思是:对 file.txt 的每一行,如果这一行包含 ‘pattern’,就打印这一行的第一列。例如,如果 file.txt 的内容是:

1
2
3
apple fruit
banana food
cherry delicious

那么 awk '/fruit/ {print $1}' file.txt 会输出 apple,因为 ‘fruit’ 是 apple 这一行的第二列。

printawk 的一个内建函数。它用于输出文本。在 awk 脚本中,print 通常被用来显示处理过的数据。

例如,在 awk '{print $1}' file.txt 这个命令中,{print $1} 是一个 awk 动作。这个动作告诉 awk 对每一行执行 print $1 操作,也就是打印每一行的第一列。

awk 还有许多其他的内建函数,例如 length(返回字符串的长度)、sub(在字符串中进行替换)、split(将字符串分割成数组)等。你可以使用这些函数进行复杂的文本处理。

使用 find 搜索文件

find 是一个在目录中搜索文件的工具。例如,下面的命令会在当前目录及其子目录中搜索所有 .txt 文件:

1
find . -name "*.txt"

组合命令

你可以使用管道符(|)将这些命令组合起来,实现更复杂的操作。例如,下面的命令会在当前目录及其子目录中的所有 .txt 文件中搜索 ‘pattern’,然后将 ‘pattern’ 替换为 ‘replacement’:

1
find . -name "*.txt" -exec grep -l 'pattern' {} \; | xargs sed -i's/pattern/replacement/g'

这个命令首先使用 findgrep 找到包含 ‘pattern’ 的文件,然后使用 xargssed 将这些文件中的 ‘pattern’ 替换为 ‘replacement’。

这些只是 Linux 命令行工具的基本用法,通过灵活地组合这些工具,你可以实现几乎所有的文本处理任务。

2.17. 权限与所有权管理

在 Unix-like 操作系统中,每个文件和目录都有一组权限与所有权,这些权限由三个主体(所有者、用户组和其他用户)以及三种权限(读、写和执行)构成。每个文件或目录都有一个所有者和一个所属的用户组。所有者、用户组和其他用户的权限可以被分别设置,允许的操作分别为读(r)、写(w)和执行(x)。这些权限可以被表示为数字:

  • 读取权限(r):4
  • 写入权限(w):2
  • 执行权限(x):1
  • 无任何权限:0

可以使用 ls -l 命令查看文件或目录的所有者、所属用户组和权限,如:

1
ls -l myfile.txt

返回的结果可能如下:

1
-rw-r--r-- 1 user group 0 Jul 18 08:30 myfile.txt

在这个例子中,user 是所有者,group 是所属用户组,而 -rw-r--r-- 是权限的表达式。在权限表达式中,第一位 - 表示这是一个文件(如果是 d 则表示这是一个目录),之后的九个字符三个一组(rwx)分别表示所有者、用户组和其他用户的权限。

chmod 命令可以用来更改文件或目录的权限。例如,命令 chmod u+x myfile.txt 会给文件的所有者添加执行权限。权限也可以用三个数字表示,如 chmod 755 myfile.txt 将设置文件所有者的权限为读、写、执行,而所属的用户组和其他用户的权限则被设置为读、执行。

chownchgrp 命令可以用来更改文件或目录的所有者和所属的用户组。例如,chown newuser myfile.txtchgrp newgroup myfile.txt

具体使用场景中,chmod 命令的实用性是非常广泛的:

  1. 设置脚本为可执行:如 chmod +x script.sh 会给 script.sh 文件添加可执行权限。
  2. 限制对敏感文件的访问:如 chmod 600 secret.txt 会设置 secret.txt 文件的权限,使得只有文件所有者可以进行读写操作。
  3. 处理 Samba 权限问题:如 chmod -x file.txt 将去除 file.txt 文件的所有可执行权限。

以上是 Unix-like 操作系统中文件和目录的权限与所有权管理的基本知识。我们可以通过理解和运用这些知识,有效地控制在系统中的文件和目录的访问权限,提高系统的安全性。

2.18. 进程管理和系统监控

在 Unix 和 Linux 系统中,进程管理和系统监控是非常重要的。以下是一些常用的命令和操作:

2.18.1. 查看进程

top 命令可以显示系统中的进程和它们的状态。使用 top 可以查看哪些进程在使用 CPU 或内存。htoptop 的一个增强版本,它提供了一个颜色的界面,并且可以直接用键盘进行交互。

2.18.2. 结束进程

如果你需要结束一个进程,你可以使用 kill 命令。例如,kill 12345 将结束 PID 为 12345 的进程。

kill-9 选项是 kill 命令中的一种信号。在 Linux 中,每个信号都有一个名字和一个对应的数字。-9 对应的信号名字是 SIGKILL。当 kill 命令发送 SIGKILL 信号给一个进程时,它会立即结束该进程,进程没有机会进行任何清理操作。

如果你需要结束一个进程,并且该进程不响应正常的结束信号(例如 SIGTERM,对应的数字是 -15),你可以使用 -9 选项。例如,kill -9 12345 会立即结束 PID 为 12345 的进程。注意,虽然 -9 选项可以立即结束进程,但它也可能会导致数据丢失或其他问题,因为进程没有机会进行清理操作。因此,你应该尽量避免使用 -9 选项,除非你没有其他选择。

findgrep 是两个非常强大的命令,你可以用它们来查找文件和过滤输出。如果你想要查找并结束一个特定的进程,你可以这样做:

  1. 使用 ps 命令列出所有进程。
  2. 使用 grep 命令过滤出你想要结束的进程。
  3. 使用 awk 命令提取出进程的 PID。
  4. 使用 kill 命令结束该进程。

例如,如果你想要结束所有名为 firefox 的进程,你可以使用以下命令:

1
kill -9 $(ps aux | grep firefox | grep -v grep | awk '{print $2}')

这个命令的意思是:

  1. ps aux:列出所有进程。
  2. grep firefox:过滤出名为 firefox 的进程。
  3. grep -v grep:删除包含 grep 的行,因为我们不想要结束 grep 命令自身。
  4. awk '{print $2}':提取出第二列,即 PID。
  5. kill -9:结束这些进程。

你也可以使用 killall 命令结束所有名字相同的进程,例如,killall firefox 会结束所有名为 firefox 的进程。

killkillall 这两个命令都可以添加 -9 选项(或其他的信号选项)来发送特定的信号。

2.18.3. 查看进程状态

ps 命令是一个非常强大的工具,可以查看和控制系统中运行的进程。ps aux 会显示所有的进程,并包括各种详细信息,如 PID、CPU 使用率、内存使用率、所属用户等。但是,当进程数量较多时,直接运行 ps aux 可能会返回过多的结果,这时就需要依赖其他工具,如 grep,来过滤和搜索具体的进程。

grep 是一个用于文本搜索的命令行工具,它可以从输入中筛选出包含(或不包含)特定模式的行。当与 ps 命令结合使用时,你可以快速定位特定的进程。

例如,如果你想要查找所有名为 firefox 的进程,你可以使用以下命令:

1
ps aux | grep firefox

这个命令会列出所有名为 firefox 的进程。| 是一个管道符,它会把 ps aux 的输出作为 grep firefox 的输入。因此,最后的结果只会包含名为 firefox 的进程。

有时,你会发现 grep 命令自身也出现在了结果中。如果你想要排除 grep 命令,你可以再加一个 grep 命令:

1
ps aux | grep firefox | grep -v grep

这个命令会排除所有包含 grep 的行。

psgrep 的结合应用非常广泛,常常用于系统监控、故障排查等场景。另外,ps 命令还可以与其他命令结合使用,例如 awk(用于文本处理)、sort(用于排序输出结果)等,可以实现更复杂的操作。

2.18.4. 查看 /proc 中的信息

/proc 是一个虚拟的文件系统,它包含了关于系统和进程的信息。例如,/proc/cpuinfo 包含了关于 CPU 的信息,/proc/meminfo 包含了关于内存的信息,/proc/PID 包含了关于 PID 进程的信息。

确实,/proc 文件系统是一个具有大量信息的宝库,包含了关于系统和正在运行的进程的许多详细信息。你可以使用 cat 命令来查看这些文件的内容。

查看 CPU 信息

1
cat /proc/cpuinfo

这将显示关于系统 CPU 的详细信息,例如型号,厂商,核数等。

查看内存信息

1
cat /proc/meminfo

这将显示关于系统内存的详细信息,例如总内存,可用内存,缓冲区大小等。

查看特定进程的信息

每一个正在运行的进程都有一个与其 PID 对应的目录在 /proc 下。例如,如果你有一个 PID 为 1234 的进程,你可以使用以下命令查看其状态:

1
cat /proc/1234/status

这将显示关于该进程的各种信息,如其状态(Sleeping,Running 等),内存占用等。

对于查看进程的内存占用以分析是否存在内存泄露,你可以查看 /proc/PID/smaps/proc/PID/status 文件。

/proc/PID/smaps 提供了进程使用的每个内存区域的详细信息,包括大小,位置,权限等。你可以通过汇总这些区域的大小来获取进程的总内存使用量。

1
cat /proc/1234/smaps

/proc/PID/status 文件中的 VmRSSVmSize 字段也提供了有关进程内存使用的信息。VmRSS 是进程正在使用的物理内存量,VmSize 是进程虚拟内存大小。

1
cat /proc/1234/status

如果你观察到这些值随着时间的推移持续增长,可能就存在内存泄漏的问题。

请注意,分析内存泄漏通常需要结合其他工具和技术,例如 valgrindgdb,或者专门的内存分析器。

2.18.5. 查看网络参数

traceroute

traceroute 命令用于显示数据包从你的机器到达目标机器所经过的所有路由。这对于诊断网络问题非常有用:

1
traceroute www.baidu.com

ping

ping 命令用于测试你的机器和目标机器之间的网络连接。如果你能成功地 “ping” 到一个机器,那么你的机器就能和那台机器通信:

1
ping www.baidu.com

nslookup

nslookup 命令用于查询 DNS 记录。这可以帮助你查看域名的 IP 地址,以及其他 DNS 记录:

1
nslookup www.baidu.com

ifconfig 和 ip

ifconfigip 命令用于查看和配置网络接口。你可以使用这些命令来查看你的网络配置,或者更改你的 IP 地址或路由表:

1
2
ifconfig
ip addr

netstat 和 ss

netstatss,能够显示网络连接,路由表,接口状态等:

1
2
netstat -tuln
ss -t

以上的命令都是网络诊断工具中的基础,但是也有许多其他的工具和技术可以用于更复杂的网络问题的诊断。例如,tcpdumpwireshark 可以用于捕获和分析网络流量,nmap 可以用于网络扫描和安全审计,curlwget 可以用于从 web 服务器下载文件,等等。

2.19. 键盘快捷和命令

在 Ubuntu 的命令行中,有很多键盘快捷键和命令可以提高程序员的效率。以下是一些实用的操作技巧:

自动完成(Tab 键):在输入命令或文件名的时候,可以按 Tab 键自动补全。如果有多个选项,按两次 Tab 键将列出所有匹配的选项。

历史命令(上 / 下方向键):在命令行中,你可以使用上 / 下方向键来浏览你之前输入过的命令。按上方向键可以回到更早之前的命令,按下方向键可以回到更近的命令。

命令行中的光标移动(左 / 右方向键):左 / 右方向键可以在当前命令行中移动光标,这样你可以编辑命令行中的任何部分。

历史命令(history)history 命令可以显示你之前输入过的所有命令。这样你可以找到并重新执行之前的命令,而不是手动输入。

搜索历史命令(Ctrl+R):按下 Ctrl+R,然后开始输入,你会看到一个提示符,显示你正在搜索历史命令。这是一个增量搜索,也就是说,随着你的输入,系统会显示匹配的历史命令。在执行 Ctrl+R 输入关键词进行搜索后,可以使用上 / 下方向键在匹配的历史命令之间进行切换。

跳转到行首(Ctrl+A)和行尾(Ctrl+E):在命令行中,你可以使用 Ctrl+A 快速跳到当前行的开头,或者使用 Ctrl+E 快速跳到当前行的末尾。

单词跳跃(Ctrl + 左方向键 / 右方向键):按下 Ctrl 键的同时按左方向键或右方向键,可以一次跳过一个单词,而不是一个字符。

删除单词(Ctrl+W):按下 Ctrl+W 会删除光标左边的一个单词。

清空命令行(Ctrl+L):这个快捷键可以帮助你清空命令行界面,类似于输入 clear 命令。

中止当前命令(Ctrl+C):这个快捷键可以帮助你中止当前正在运行的命令。

将命令放入后台运行(Ctrl+Z):这个快捷键可以将当前正在运行的命令放入后台。你可以使用 fg 命令将其恢复到前台。

复制和粘贴(Ctrl+Shift+C 和 Ctrl+Shift+V):在命令行中,你不能直接使用 Ctrl+CCtrl+V 来复制和粘贴,因为这两个快捷键已经被其他功能占用。但你可以使用 Ctrl+Shift+C 来复制,使用 Ctrl+Shift+V 来粘贴。

切换命令行标签页(Ctrl+PgUp 和 Ctrl+PgDn):如果你在使用带标签页的命令行界面(例如 GNOME Terminal),你可以使用 Ctrl+PgUpCtrl+PgDn 在标签页之间切换。

命令别名(alias):如果你有一些经常使用的长命令,你可以使用 alias 命令为它们创建别名。例如,你可以使用 alias ll='ls -lh' 创建一个 ll 的别名,这样每次输入 ll 都相当于输入 ls -lh

以上只是一部分实用的命令行技巧,还有许多其他的技巧和快捷键可以帮助你提高效率。你可以尝试在网上搜索更多的信息,或者查看相关的文档和教程。

2.20. 包管理

Ubuntu 使用 apt 包管理器来处理软件包。以下是一些基本的 apt 命令:

  • sudo apt update:更新软件包列表。这应该是安装新软件之前执行的第一个命令。
  • sudo apt upgrade:升级所有的软件包。这将更新所有已安装的软件包至最新版本。
  • sudo apt install:安装一个新的软件包。例如,sudo apt install firefox 将安装 Firefox 浏览器。
  • sudo apt remove:删除一个已安装的软件包。例如,sudo apt remove firefox 将卸载 Firefox 浏览器。
  • sudo apt search:搜索软件包。例如,sudo apt search firefox 将显示所有与 Firefox 相关的软件包。

如果你下载了一个 .deb 文件并希望通过命令行手动安装,你可以使用 dpkg 命令。以下是具体的操作:

  • sudo dpkg -i package_file.deb:安装一个 .deb 软件包。例如,sudo dpkg -i firefox.deb 将安装名为 firefox.deb 的软件包。

这里的 sudo 命令是 “superuser do” 的缩写,它允许普通用户以超级用户(或称为 root 用户)的身份执行命令。由于安装和卸载软件包可能会影响系统的运行,所以需要超级用户的权限。当你在命令前添加 sudo 时,系统可能会提示你输入密码,以验证你有执行该命令的权限。

2.21. 其他

watch 命令

watch 是一个非常有用的命令,它允许你周期性地执行命令并显示结果。这对于监视文件、系统状态或任何可以通过命令行查看的内容非常有用。

例如,你可以使用 watch 每两秒刷新一次 ls 命令的输出,以监视目录的变化:

1
watch -n 2 du -sh

这将每两秒执行一次 du -sh 命令并显示其输出。

time 命令

time 命令用于测量命令的执行时间。这对于性能测试非常有用。

例如,你可以使用 time 来测量 make all 命令的执行时间:

1
time make all

这将显示 make all 命令的执行时间,包括用户态,内核态的 CPU 时间以及实际经过的墙钟时间。

这些工具提供了非常有用的功能,可以帮助你更好地理解和监控你的系统。和其他命令一样,你可以通过查看它们的手册页(例如,通过运行 man watchman time)来学习更多关于它们的信息。

2.22. 查看帮助手册

在 Ubuntu Linux 中,你可以通过两种主要方式查看命令的帮助和手册:使用 man 命令或者使用 --help-h 选项。

man 命令man 命令用于显示用户手册页,这些手册页包含了关于各种命令和程序的详细信息。要查看某个命令的手册页,只需在 man 后面跟上你想要查询的命令即可。例如,man ls 将显示 ls 命令的手册页。这个命令的结果通常会很详尽,包含了命令的描述、选项、使用示例等。

–help 或 -h 选项:大多数的命令都支持 --help-h 选项,这个选项可以显示命令的简短帮助信息。这个选项通常会列出命令的基本用法和所有可用的选项,但不会像 man 命令那样详尽。例如,ls --helpls -h 将显示 ls 命令的帮助信息。

需要注意的是,不是所有的命令都支持 --help-h 选项,而且即使支持,显示的信息也可能因命令而异。如果 --help-h 选项无法提供足够的信息,那么你可以考虑使用 man 命令。

3. 编辑器的使用

3.1. Vim 编辑器的介绍

Vim 是一款由 Bram Moolenaar 开发的文本编辑器,它是 Unix 类操作系统下 vi 编辑器的克隆版本,但比 vi 更为强大。Vim 是全键盘操作的编辑器,可以实现对文本的高效编辑。

Vim 的功能强大,主要表现在以下几个方面:

  • 语法高亮:Vim 支持多种编程语言的语法高亮。
  • 多重撤销:Vim 支持无限次的撤销操作。
  • 分屏:Vim 可以打开多个文档,并进行分屏显示。
  • 扩展性:Vim 的功能可以通过插件进行扩展,有丰富的插件可供选择。

3.2. Vim 的模式

Vim 有以下几种模式:

  • 一般模式(Normal Mode):这是 Vim 打开后的默认模式,可以进行光标移动、复制、粘贴、搜索、替换等多种操作。
  • 插入模式(Insert Mode):在此模式下,可以插入文本。从一般模式按 i 键进入此模式,按 ESC 键回到一般模式。
  • 命令模式(Command Mode):在此模式下,可以输入命令行命令。从一般模式按 : 键进入此模式,按 ESC 键回到一般模式。
  • 可视模式(Visual Mode):在此模式下,可以对文本进行选中操作。从一般模式按 v(字符可视模式)、V(行可视模式)或 Ctrl+v(块可视模式)进入此模式,按 ESC 键回到一般模式。

3.3. Vim 的基本操作

以下是 Vim 的一些基本操作:

  • 光标移动:在一般模式下,h(左)、j(下)、k(上)、l(右)用于光标的基础移动。
  • 插入文本:在一般模式下,i 进入插入模式,然后可以输入文本。在完成后,按 ESC 键回到一般模式。
  • 保存文件:在命令模式下,输入 :w 可以保存文件。
  • 退出 Vim:在命令模式下,输入 :q 可以退出 Vim。如果有未保存的修改,需要输入 :q! 强制退出。

在 Vim 中,你可以快速地跳转到文件的任何一行。以下是具体的步骤:

  • 在命令模式(也就是一般模式)下,输入行数,然后按 G 键。例如,如果你想跳转到第 25 行,你应该输入 25G
  • 另一种方法是在命令行模式中使用 : 和行号。例如,如果你想跳转到第 25 行,你应该输入 :25。在输入完毕后,按 Enter 键即可。

这两种方法都可以让你快速地在文件中跳转。

3.4. Vim 的高级功能

以下是 Vim 的一些高级功能:

  • 搜索:在一般模式下,输入 / 后跟着要搜索的内容,然后按 Enter 键可以进行搜索。按 n 键跳转到下一个搜索结果,按 N 键跳转到上一个搜索结果。
  • 替换:在命令模式下,输入 :s/old/new/g 可以替换当前行中的所有 “old” 为 “new”。如果要在整个文件中进行替换,可以使用 :% s/old/new/g 命令。
  • 分屏:在命令模式下,输入 :split:vsplit 可以进行水平分屏或垂直分屏。使用 Ctrl+w 键可以在各个分屏窗口中切换。
  • 宏:Vim 支持宏录制和播放,可以批量处理复杂的文本操作。

3.5. Vim 的实际应用练习

Vim 是一款高度可配置的文本编辑器,用于有效地创建和更改任何类型的文本。 它被包含在大多数 UNIX 系统并且在许多其他地方有所应用。 在本章节中,我们将通过一些实际的练习来探索 Vim 编辑器的应用。

练习 1:创建和保存文件

让我们从创建和保存一个新文档开始。 在终端中,键入以下命令:

1
vim newfile.txt

这将打开一个名为 “newfile.txt” 的新 Vim 窗口。 现在,键入 i 进入插入模式,在其中你可以输入文本。 输入一些文本,然后按 ESC 返回到命令模式。 在命令模式下,键入 :wq 或者按 Shift + ZZ 快捷键保存并退出 Vim。

练习 2:导航文本

Vim 有多种导航文档的方法。 在 Vim 中打开一个文档,然后试试下面的命令:

  • gg - 跳到文档的开始
  • G - 跳到文档的结尾
  • 0 - 跳到行的开头
  • $ - 跳到行的末尾
  • w - 跳到下一个单词的开头
  • b - 跳到上一个单词的开头

练习 3:编辑文本

Vim 提供了许多强大的文本编辑功能,包括复制、粘贴和删除。 在 Vim 中打开一个文档,然后尝试以下命令:

  • dd - 删除当前行
  • yy - 复制当前行
  • p - 粘贴剪贴板中的内容到当前行之后
  • u - 撤销上一次操作
  • Ctrl + r - 重做上一次撤销的操作

练习 4:查找和替换

Vim 的查找和替换功能非常实用。 在 Vim 中打开一个文档,然后尝试以下命令:

  • /word - 查找 “word”
  • n - 跳到下一个匹配项
  • N - 跳到上一个匹配项
  • :% s/old/new/g - 全文替换 “old” 为 “new”

练习 5:使用 Vim 宏

Vim 的宏是一种强大的自动化工具,可以记录和重播键入序列。 试试以下步骤:

  • 在命令模式下,键入 qa 开始记录宏 a
  • 输入一系列的命令,例如 iHello World<Esc>
  • 键入 q 停止记录
  • 键入 @a 运行宏 a

4. Bash Shell 编程基础

4.1. 介绍

Bash Shell 是什么

Bash(Bourne Again Shell)是一个 Unix shell 和命令语言,由 Brian Fox 为 GNU 项目开发。它是 Bourne Shell (sh) 的扩展版,并提供了许多改善和新特性。Bash 是许多 Linux 发行版的默认 shell,并且也是 macOS 和 Windows 的 Subsystem for Linux(WSL)中可用的。

Shell 是一个用户与操作系统进行交互的界面。通过 shell,用户可以执行命令、运行脚本、操作文件系统等。Bash 作为一个 shell,提供了丰富的编程特性,如变量、数组、流程控制结构(如 if,for,while 等)和函数。

Bash Shell 的历史和应用

Bash Shell 最初于 1989 年发布,作为自由软件基础构建块的一部分,它旨在完全兼容 “sh”(Bourne Shell),同时还引入了 C Shell(csh)和 Korn Shell(ksh)的许多有用特性。

由于其强大的特性和开源的本质,Bash 已经成为了许多系统管理员和开发人员的首选工具。它不仅用于日常的文件管理和系统管理任务,也用于编写复杂的脚本和自动化程序。

4.2. Shell 变量

什么是变量

在 Bash shell 中,变量是用来存储和操作数据的名称。这些数据可能是字符串,数字,或者是其他命令的输出。变量的主要用途是提供一个方法来保存和操纵数据,以便在脚本或命令行中使用。

如何声明和使用变量

在 Bash 中,你可以使用等号 = 来声明变量和赋值。例如,下面的命令声明了一个名为 my_variable 的变量,并将其值设置为 Hello, world!

1
my_variable="Hello, world!"

请注意,变量名和等号之间不能有空格。

一旦你声明了一个变量,你就可以使用美元符号 $ 来使用它。例如:

1
echo $my_variable

这会在终端中输出 Hello, world!

环境变量和局部变量

Bash 中有两种主要类型的变量:环境变量和局部变量。

局部变量只在它们被声明的 shell 会话中可用。如果你在一个终端窗口中声明了一个变量,然后打开了一个新的终端窗口,那么新的终端窗口将无法访问那个变量。

环境变量,另一方面,是在所有的 shell 会话中都可用的。你可以使用 export 命令来创建环境变量。例如:

1
export my_variable="Hello, world!"

一旦你这样做,my_variable 将在所有的子 shell 会话中都可用。

特殊变量

Bash 还定义了一些特殊的变量,这些变量在 shell 中有特定的用途。以下是一些最常用的特殊变量:

  • $HOME:当前用户的主目录的路径。
  • $PATH:用于查找命令的目录列表。
  • $PS1:默认的命令提示符。
  • $USER:当前用户的用户名。
  • $?:最后执行的命令的退出状态。如果命令成功执行,该值为 0,否则为非零值。
  • $$:当前 shell 进程的 PID。
  • $#:传递给脚本或函数的参数个数。
  • $*$@:传递给脚本或函数的所有参数。

这些特殊变量为你在 Bash 中编写脚本和处理数据提供了强大的工具。

4.3. Shell 脚本

什么是 Shell 脚本

Shell 脚本是一个包含了一系列命令的文本文件,当这个脚本被执行时,这些命令会按照它们在脚本中出现的顺序被执行。Shell 脚本可以帮助我们自动化一些日常的任务,例如文件管理、程序运行等。

如何创建和运行 Shell 脚本

创建一个 Shell 脚本其实就是创建一个文本文件,并在文件中写入你想要执行的命令。例如,你可以创建一个名为 my_script.sh 的文件,并在其中写入以下内容:

1
2
3
#!/bin/bash

echo "Hello, world!"

在这个脚本中,#!/bin/bash 是一个特殊的指示符,称为 shebang,它告诉系统这个脚本应该用哪个解释器来执行,这里是 /bin/bash。接下来的命令 echo"Hello, world!"将会在脚本被执行时输出”Hello, world!”。

你可以通过以下命令来运行这个脚本:

1
bash my_script.sh

或者,你可以先给这个脚本添加执行权限,然后直接运行它:

1
2
chmod +x my_script.sh
./my_script.sh

Shell 脚本的结构和语法

一个典型的 Shell 脚本包含了以下元素:

  • Shebang:这是脚本的第一行,它指定了执行这个脚本的解释器。对于 Bash 脚本,这通常是 #!/bin/bash
  • 命令:这些是你想要自动执行的命令。它们按照在脚本中出现的顺序执行。
  • 注释:以 # 开始的行是注释,它们不会被执行。你可以使用注释来解释脚本的功能或者说明某个命令的作用。
  • 变量:你可以在脚本中定义变量来保存和操作数据。
  • 控制结构:例如 ifforwhile。这些可以让你的脚本根据条件执行不同的命令,或者重复执行某些命令。

以下是一个更复杂的脚本的例子,它使用了变量和 if 控制结构:

1
2
3
4
5
6
7
8
9
#!/bin/bash

name=$1

if [ -z "$name" ]; then
echo "Hello, world!"
else
echo "Hello, $name!"
fi

这个脚本接受一个参数,并将其值赋给 name 变量。然后,它使用 if 语句检查 name 是否为空。如果 name 为空,它会输出 “Hello, world!”,否则,它会输出 “Hello, $name!”。

参数传递

你可以在执行脚本时传递参数,这些参数在脚本中可以通过 $1$2$3 等变量来访问,其中 $1 对应第一个参数,$2 对应第二个参数,以此类推。例如,如果你执行 bash my_script.sh Alice,那么在 my_script.sh 脚本中,$1 的值就会是 “Alice”。

另外,你也可以使用 $@ 或者 $* 来获取所有的参数,而 $# 可以获取参数的个数。

4.4. 流程控制

条件语句

在 Shell 脚本中,我们可以使用 ifelsecase 来进行条件判断。

-if/else语句

if 语句用于根据条件执行不同的代码块。基本的语法如下:

1
2
3
4
5
if [ condition ]; then
# commands to execute if condition is true
else
# commands to execute if condition is false
fi

例如:

1
2
3
4
5
if [ $1 -gt 100 ]; then
echo "The number is larger than 100."
else
echo "The number is 100 or less."
fi

-case语句

case 语句用于根据值的不同执行不同的代码块。基本的语法如下:

1
2
3
4
5
6
7
8
9
10
11
case value in
pattern1)
# commands to execute if value matches pattern1
;;
pattern2)
# commands to execute if value matches pattern2
;;
*)
# commands to execute if value doesn't match any pattern
;;
esac

例如:

1
2
3
4
5
6
7
8
9
10
11
case $1 in
start)
echo "Starting..."
;;
stop)
echo "Stopping..."
;;
*)
echo "Unknown command: $1"
;;
esac

循环语句(for, while, until)

在 Shell 脚本中,我们可以使用 forwhileuntil 来进行循环。

-for循环

``for` 循环用于重复执行一段代码。基本的语法如下:

1
2
3
for var in list; do
# commands to execute
done

例如:

1
2
3
for i in 1 2 3; do
echo $i
done

-while循环

``while` 循环用于当条件为真时重复执行一段代码。基本的语法如下:

1
2
3
while [ condition ]; do
# commands to execute
done

例如:

1
2
3
4
5
i=1
while [ $i -le 3 ]; do
echo $i
i=$((i+1))
done

-until循环

``until` 循环用于当条件为假时重复执行一段代码。基本的语法如下:

1
2
3
until [ condition ]; do
# commands to execute
done

例如:

1
2
3
4
5
i=1
until [ $i -gt 3 ]; do
echo $i
i=$((i+1))
done

这些流程控制结构为我们在 Shell 脚本中编写复杂的逻辑提供了强大的工具。

4.5. 函数

什么是函数

在 Shell 脚本中,函数是一段可被重复使用的代码块。你可以在脚本的任何地方声明一个函数,并在需要的地方调用它。函数可以帮助你组织和重用代码,使你的脚本更简洁、更易于理解和维护。

如何声明和调用函数

在 Shell 脚本中,你可以使用 function 关键字或者直接使用函数名来声明函数。函数的基本语法如下:

1
2
3
function_name () {
# commands
}

或者

1
2
3
function function_name {
# commands
}

你可以通过函数名来调用函数,例如:

1
function_name

以下是一个简单的函数示例:

1
2
3
4
5
greet () {
echo "Hello, $1!"
}

greet "world" # 输出 "Hello, world!"

在这个示例中,greet 是一个接受一个参数的函数,它会输出 “Hello, $1!”,其中 $1 是函数的第一个参数。

函数的返回值

在函数中,你可以使用 return 语句来指定函数的返回值,但是这个值只能是一个介于 0 到 255 的整数。如果你不指定返回值,函数将返回最后一个命令的退出状态。

你可以使用 $? 变量来获取上一个命令或函数的返回值,例如:

1
2
3
4
5
6
my_func () {
return 42
}

my_func
echo $? # 输出 "42"

如果你想返回一个字符串或其他类型的值,你可以通过 echoprintf 命令将值输出到标准输出,然后在调用函数时使用命令替换的方式来获取这个值,例如:

1
2
3
4
5
6
my_func () {
echo "Hello, $1!"
}

greeting=$(my_func "world")
echo $greeting # 输出 "Hello, world!"

递归函数

递归函数是一种在其定义中调用自身的函数。在 Shell 脚本中,你可以创建递归函数,但是请注意控制递归的深度,避免出现无限递归的情况。

以下是一个计算阶乘的递归函数的示例:

1
2
3
4
5
6
7
8
9
10
factorial () {
if [ $1 -eq 0 ]; then
echo 1
else
last_factorial=$(factorial $(( $1 - 1 )))
echo $(( $1 * last_factorial ))
fi
}

echo $(factorial 5) # 输出 "120"

在这个示例中,factorial 函数接受一个参数,如果这个参数等于 0,它就返回 1,否则,它就调用自身来计算 ($1 - 1) 的阶乘,然后将这个值乘以 $1

4.6. 用户输入和输出

在 Shell 脚本中,处理用户输入和输出是非常重要的。我们可以通过几种不同的方式来读取用户的输入,打印输出到终端,或者将输出重定向到文件或其他命令。

读取输入

在 Shell 脚本中,我们可以使用 read 命令来读取用户的输入。例如:

1
2
3
echo "What is your name?"
read name
echo "Hello, $name!"

在这个例子中,read 命令会等待用户输入,然后将输入的值赋给变量 name

打印输出

在 Shell 脚本中,我们一般使用 echoprintf 命令来打印输出到终端。例如:

1
2
name="John Doe"
echo "Hello, $name!"

这个例子中,echo 命令会打印出 “Hello, John Doe!”。

文件重定向

在 Shell 中,我们可以使用重定向操作符 >>> 来将输出重定向到文件。例如:

1
echo "Hello, world!" > myfile.txt

这个例子中,echo 命令的输出 “Hello, world!” 会被写入到 myfile.txt 文件中。如果文件已经存在,> 操作符会覆盖文件的内容。如果我们想要将内容追加到文件的末尾,可以使用 >> 操作符:

1
echo "Hello again, world!" >> myfile.txt

管道

在 Shell 中,我们可以使用管道 | 操作符将一个命令的输出作为另一个命令的输入。例如:

1
ls | grep ".txt"

这个例子中,ls 命令会列出当前目录下的所有文件,然后这个列表会被传递给 grep 命令,grep 命令会从这个列表中筛选出所有包含 “.txt” 的行。这样我们就可以找出当前目录下的所有 txt 文件。

4.7. 错误处理和调试

在编写和运行 Shell 脚本时,错误处理和调试是必不可少的环节。在不同的情况下,我们可以使用不同的技术来寻找和解决问题。

4.7.1. 错误处理

在 Shell 脚本中,我们可以使用特殊变量 $? 来获取上一个命令的退出状态。如果命令成功执行,退出状态为 0,否则为非零值。例如:

1
2
3
4
ls /nonexistentdirectory
if [ $? -ne 0 ]; then
echo "An error occurred."
fi

在这个例子中,如果 ls 命令因为目录不存在而失败,我们会打印出一条错误信息。

另外,我们可以使用 set -e 命令让脚本在任何命令失败时立即退出:

1
2
3
set -e
ls /nonexistentdirectory
echo "This will not be printed."

在这个例子中,ls 命令会失败,然后脚本立即退出,所以 “This will not be printed.” 永远不会被打印出来。

4.7.2. 脚本调试

在 Shell 脚本中,我们可以使用 set -x 命令打开调试模式,这会打印出所有执行的命令:

1
2
set -x
echo "Hello, world!"

在这个例子中,我们会看到 + echo 'Hello, world!'Hello, world! 两行输出。前一行显示了实际执行的命令,后一行显示了命令的输出。

如果你想在运行某个 shell 脚本时启用调试模式,你可以在命令行中使用 -x 选项和 Shell 解释器一起调用脚本,如:

1
bash -x script.sh

在这个例子中,bash -x 会启动一个新的 bash shell,并在这个 shell 中以调试模式运行 script.sh 脚本。这样,脚本中的每一条命令在执行前都会被打印出来。

4.7.3. 日志记录

在 Shell 脚本中,记录执行过程和结果是一种常见的做法,以便于后续查看和分析。这通常通过将脚本的输出(包括标准输出和错误输出)重定向到文件实现。这样,我们可以随时查看这些日志文件,了解脚本运行时的具体情况。

标准输出重定向

我们可以使用 >>> 运算符将脚本的标准输出重定向到文件。例如:

1
echo "This is a message." > output.log

这个例子中,”This is a message.” 会被写入到 output.log 文件中。如果文件已经存在,> 运算符会覆盖文件的内容。如果我们想要将内容追加到文件的末尾,可以使用 >> 运算符。

错误输出重定向

同样地,我们也可以使用 2>2>> 运算符将脚本的错误输出重定向到文件。例如:

1
ls /nonexistentdirectory 2> error.log

这个例子中,如果 ls 命令失败,错误信息会被写入到 error.log 文件中。

同时重定向标准输出和错误输出

如果我们想要同时重定向标准输出和错误输出,可以使用 &> 运算符:

1
ls /nonexistentdirectory &> output_and_error.log

这个例子中,ls 命令的标准输出和错误输出都会被写入到 output_and_error.log 文件中。

通过这样的方式,我们可以将脚本的输出和错误信息记录下来,以便于后续查看和分析,从而更好地理解和控制 Shell 脚本的行为,更有效地找出和解决问题。

4.8. Python 与 Shell 脚本的差异

Python 和 Shell 脚本是两种常用的脚本语言,它们各有特点和用途。了解它们的差异有助于我们在不同的场景下选择合适的工具。

变量和类型

在 Python 中,我们使用 = 来给变量赋值,可以直接使用变量名引用变量,而且变量可以有多种类型,如整数、浮点数、字符串、列表、字典等。例如:

1
2
3
x = 1
y = "hello"
z = [1, 2, 3]

在 Shell 脚本中,我们同样使用 = 来给变量赋值,但是不能在变量名和 = 之间有空格,而且需要使用 $ 来引用变量。Shell 脚本中的变量只有字符串一种类型。例如:

1
2
3
x=1
y="hello"
z="1 2 3"

控制结构

Python 和 Shell 脚本都支持常见的控制结构,如条件判断和循环,但是语法有所不同。

在 Python 中,我们使用 ifelifelse 进行条件判断,使用 forwhile 进行循环。例如:

1
2
3
4
5
6
7
8
9
if x == 1:
print ("x is 1")
elif x == 2:
print ("x is 2")
else:
print ("x is neither 1 nor 2")

for i in range (3):
print (i)

在 Shell 脚本中,我们使用 ifelifelse 进行条件判断,需要配合 thenfi 关键字。循环则可以使用 forwhile,且 for 循环的语法与 Python 有显著差异。例如:

1
2
3
4
5
6
7
8
9
10
11
if [ $x -eq 1 ]; then
echo "x is 1"
elif [ $x -eq 2 ]; then
echo "x is 2"
else
echo "x is neither 1 nor 2"
fi

for i in 1 2 3; do
echo $i
done

函数

Python 和 Shell 脚本都支持定义和调用函数,但是语法有所不同。

在 Python 中,我们使用 def 关键字来定义函数,使用函数名和括号来调用函数。例如:

1
2
3
4
def greet (name):
print ("Hello," + name + "!")

greet ("world")

在 Shell 脚本中,我们使用 function 关键字或直接使用函数名来定义函数,调用函数时只需写出函数名,无需括号。例如:

1
2
3
4
5
greet () {
echo "Hello, $1!"
}

greet "world"

以上只是 Python 和 Shell 脚本的一部分差异,它们在其他方面,如错误处理、文件操作、进程控制等,也有各自的特点和用法。但是,了解这些基本的差异可以帮助我们更快地从 Python 迁移到 Shell 脚本。

4.9. C 语言与 Shell 脚本的差异

C 语言和 Shell 脚本是两种常用的编程和脚本语言,它们各有特点和用途。了解它们的差异有助于我们在不同的场景下选择合适的工具。

数据类型和变量

在 C 语言中,我们必须为每个变量声明数据类型。C 语言支持多种数据类型,包括整型、浮点型、字符型、数组、结构体等。例如:

1
2
3
int x = 1;
char y [] = "hello";
int z [] = {1, 2, 3};

在 Shell 脚本中,所有的变量都是字符串类型,我们不需要声明变量类型。例如:

1
2
3
x=1
y="hello"
z="1 2 3"

控制结构

C 语言和 Shell 脚本都支持常见的控制结构,如条件判断和循环,但是语法有所不同。

在 C 语言中,我们使用 ifelse ifelse 进行条件判断,使用 forwhiledo...while 进行循环。例如:

1
2
3
4
5
6
7
8
9
10
11
if (x == 1) {
printf ("x is 1");
} else if (x == 2) {
printf ("x is 2");
} else {
printf ("x is neither 1 nor 2");
}

for (int i = 0; i < 3; i++) {
printf ("% d", i);
}

在 Shell 脚本中,我们使用 ifelifelse 进行条件判断,需要配合 thenfi 关键字。循环则可以使用 forwhile。例如:

1
2
3
4
5
6
7
8
9
10
11
if [ $x -eq 1 ]; then
echo "x is 1"
elif [ $x -eq 2 ]; then
echo "x is 2"
else
echo "x is neither 1 nor 2"
fi

for i in 1 2 3; do
echo $i
done

函数

C 语言和 Shell 脚本都支持定义和调用函数,但是语法有所不同。

在 C 语言中,我们需要为函数声明返回类型和参数类型。例如:

1
2
3
4
5
6
void greet (char* name) {
printf ("Hello, % s!
", name);
}

greet ("world");

在 Shell 脚本中,我们不需要声明函数的返回类型和参数类型。例如:

1
2
3
4
5
greet () {
echo "Hello, $1!"
}

greet "world"

变量相等的判断

在 C 语言中,我们使用 == 符号来判断两个变量是否相等。例如:

1
2
3
4
if (x == y) {
printf ("x is equal to y
");
}

在 Shell 脚本中,我们使用 -eq(用于整数)或 =(用于字符串)来判断两个变量是否相等。例如:

1
2
3
if [ $x -eq $y ]; then
echo "x is equal to y"
fi

变量的大小比较

在 C 语言中,我们使用 <><=>= 符号来比较两个变量的大小。例如:

1
2
3
4
5
6
7
8
9
10
if (x < y) {
printf ("x is less than y
");
} else if (x > y) {
printf ("x is greater than y
");
} else {
printf ("x is equal to y
");
}

在 Shell 脚本中,我们使用 -lt-gt-le-ge 来比较两个整数的大小。例如:

1
2
3
4
5
6
7
if [ $x -lt $y ]; then
echo "x is less than y"
elif [ $x -gt $y ]; then
echo "x is greater than y"
else
echo "x is equal to y"
fi

字符串操作

在 C 语言中,我们使用字符串函数(如 strcpystrcatstrlen 等)来操作字符串。例如:

1
2
3
4
5
6
7
char s [100];
strcpy (s, "hello");
strcat (s, ", world");
printf ("% s
", s); //prints "hello, world"
printf ("% lu
", strlen (s)); //prints "13"

在 Shell 脚本中,我们可以直接使用变量和字符串字面量来连接字符串,使用 ${# 变量名} 来获取字符串长度。例如:

1
2
3
4
s="hello"
s+=", world"
echo $s # prints "hello, world"
echo ${#s} # prints "13"

在 C 语言中,我们通常使用函数(如 strstrregex 库函数)来进行字符串的模式匹配。

在 Shell 脚本中,我们可以直接使用 =!= 运算符来进行简单的模式匹配,或者使用 case 语句、[[ ]] 结构,或者 grep 命令等来进行更复杂的模式匹配。

字符串空值和非空值的判断

在 C 语言中,我们通常使用 ==!= 符号来判断字符串是否为空。例如:

1
2
3
4
5
6
7
8
char *s = "hello";
if (s [0] == ' ') {
printf ("s is an empty string
");
} else {
printf ("s is not an empty string
");
}

在 Shell 脚本中,我们使用 -z-n 来判断字符串是否为空。另外,为了避免字符串变量未定义或为空时出错,我们在比较字符串时,常常会在字符串前加一个常量,例如 x$string。例如:

1
2
3
4
5
6
7
8
s="hello"
if [ -z "$s" ]; then
echo "s is an empty string"
elif [ "x$s" = "x" ]; then
echo "s is an empty string"
else
echo "s is not an empty string"
fi

数组操作

在 C 语言中,我们使用索引来访问数组元素,使用循环来遍历数组。例如:

1
2
3
4
5
int a [] = {1, 2, 3};
for (int i = 0; i < 3; i++) {
printf ("% d
", a [i]);
}

在 Shell 脚本中,我们也使用索引来访问数组元素,使用 ${数组名 [@]} 来获取数组的所有元素,然后用 for 循环来遍历数组。例如:

1
2
3
4
a=(1 2 3)
for i in ${a [@]}; do
echo $i
done

错误处理

在 C 语言中,错误处理通常通过函数的返回值或全局变量(如 errno)进行。

在 Shell 脚本中,我们可以使用 $? 变量来获取上一个命令的退出状态,这通常被用作错误处理。

以上只是 C 语言和 Shell 脚本的一部分差异,它们在其他方面,如文件操作、进程控制、信号处理等,也有各自的特点和用法。理解这些差异有助于我们在编写或阅读这两种语言的代码时,更准确地理解其行为。

这些只是 C 语言和 Shell 脚本的部分差异,理解这些差异有助于我们在编写或阅读代码时,更

5. 正则表达式

在 Shell 中,你可以使用正则表达式(Regular Expression,经常被简写为 RegEx)来描述复杂的匹配模式。正则表达式是一种强大的文本匹配工具,它可以用于 grepsedawk 等命令。

5.1. 元字符和构造

下面是一些常用的正则表达式元字符和构造:

.(点):匹配任何单个字符(除了换行符)。

\*(星号):匹配前面的元素零次或多次。

+(加号):匹配前面的元素一次或多次。

?(问号):匹配前面的元素零次或一次。

[](方括号):匹配方括号中的任何一个字符。例如,[abc] 会匹配 ‘a’、’b’ 或 ‘c’。

^(脱字符):在方括号中,表示否定(例如,[^abc] 会匹配任何不是 ‘a’、’b’ 或 ‘c’ 的字符);在方括号外,表示行的开始。

$(美元符号):表示行的结束。

\(反斜杠):用于转义元字符(例如,\. 会匹配实际的 ‘.’ 字符,而不是任何字符)。

()(括号):用于分组。

|(竖线):表示或(例如,a|b 会匹配 ‘a’ 或 ‘b’)。

{n}{n,}{n,m}(花括号):匹配前面的元素 n 次、至少 n 次、或者 n 到 m 次。

注意,这些元字符和构造在不同的命令和环境中可能有不同的行为,具体取决于你是否使用了扩展正则表达式(Extended Regular Expression)或者 Perl 正则表达式(Perl-Compatible Regular Expression)。你可以通过查阅相应命令的手册页(例如 man grep)来获取更详细的信息。

5.2. 正则表达式的实例

让我们看一些在 Shell 中使用正则表达式的实例。这些例子主要涉及 grepsedawk 命令,这些都是日常工作中常用的命令。

使用 grep 进行搜索

grep 是一种常见的使用正则表达式的方式。你可以使用正则表达式来匹配复杂的模式。例如,下面的命令会在 file.txt 中找到所有以’start’ 开始并以 ‘end’ 结束的行:

1
grep '^start.*end$' file.txt

如果你想使用扩展的正则表达式特性(例如 +?|()),你需要使用 egrep 或者 grep -E

1
grep -E'start.*end1|end2$' file.txt

这个命令会找到所有以’start’ 开始并以 ‘end1’ 或 ‘end2’ 结束的行。

使用 sed 进行替换

sed 可以使用正则表达式来执行复杂的替换操作。例如,下面的命令会在 file.txt 中将所有以’start’ 开始并以 ‘end’ 结束的行替换为 ‘replacement’:

1
sed -E's/^start.*end$/replacement/g' file.txt

使用 awk 进行文本处理

awk 可以使用正则表达式来处理复杂的文本模式。例如,下面的命令会打印 file.txt 中所有包含 ‘pattern’ 的行的第一列:

1
awk '/pattern/ {print $1}' file.txt

这只是正则表达式在 Shell 中的一些基本用法,你可以根据需要进行组合和扩展,以处理更复杂的模式和任务。

6. Linux 环境下的编程常见操作

6.1. C 编程环境的配置

在 Linux 环境下进行 C 语言编程,需要先配置好开发环境。一般而言,你应该已经安装了 GCC(GNU Compiler Collection)集合,它包含了 C 语言的编译器。如果你还未安装 GCC,可以通过以下命令进行安装(以 Ubuntu 为例):

1
2
sudo apt-get update
sudo apt-get install build-essential

安装完 GCC 后,你可以通过在终端输入 gcc --version 来验证安装是否成功。

6.2. 基本的编译命令

编译 C 程序主要使用 gcc 命令。如果你有一个名为 program.c 的 C 语言源文件,你可以使用以下命令进行编译:

1
gcc program.c -o program

在这个命令中,-o program 表示编译后生成的可执行文件名为 program。如果你省略 -o 选项,那么默认的输出文件名为 a.out

6.3. 版本控制工具

在 Linux 环境下,最常用的版本控制工具无疑是 Git。Git 是一个分布式的版本控制系统,可以帮助你跟踪和管理项目的代码变更。

首次使用 Git 时,你需要配置你的用户名和电子邮件地址,因为 Git 每次提交会使用这些信息:

1
2
git config --global user.name "Your Name"
git config --global user.email "Your Email"

Git 的基本工作流程包括:初始化仓库(git init)、添加文件到仓库(git add)、提交变更(git commit)、查看状态(git status)、查看提交历史(git log)等。

6.4. 调试工具

对于 C 语言程序,最常用的调试工具是 GDB(GNU Debugger)。GDB 可以让你逐行地运行程序,查看和修改程序状态,以帮助你查找和修复错误。

在使用 GDB 之前,你需要使用 -g 选项来编译你的 C 程序,以包含调试信息:

1
gcc -g program.c -o program

然后,你可以使用 gdb 命令启动 GDB 并加载你的程序:

1
gdb program

在 GDB 中,你可以使用各种命令进行调试,如:run(运行程序)、break(设置断点)、next(执行下一行程序)、print(打印变量的值)等。

以上就是在 Linux 环境下进行编程的一些常见操作,包括 C 编程环境的配置、基本的编译命令、版本控制工具以及调试工具。希望对你有所帮助。

7. Makefile 的使用和编写

在 C 程序的编译和构建过程中,make 是一个非常重要的工具。make 工具可以自动化编译和链接的过程,它依赖于一个名为 Makefile 的文件,该文件描述了各个源文件之间的依赖关系以及如何从源文件生成目标文件。

7.1. 什么是 Makefile

Makefile 是一个包含了一系列规则(rules)和变量的文件。规则定义了目标文件的生成过程,变量则可以在多个地方重复使用同一个值。

一个基本的 Makefile 规则包含了一个目标(target),它的依赖项(dependencies)和一个命令(command):

1
2
target: dependencies
command

7.2. Makefile 的基本结构

一个简单的 Makefile 示例如下:

1
2
3
4
5
6
7
8
myprogram: main.o utility.o
gcc -o myprogram main.o utility.o

main.o: main.c
gcc -c main.c

utility.o: utility.c
gcc -c utility.c

在这个示例中,myprogram 是最终的目标,它依赖于两个 .o 文件,每个 .o 文件又各自依赖于一个 .c 文件。

如果我们在终端中运行 make 命令,make 工具会检查 Makefile 文件,并按照规则执行命令。如果一个 .o 文件的时间戳比其对应的 .c 文件新,make 工具就会跳过编译这个 .c 文件的步骤。

7.3. 使用变量

Makefile 中,我们可以定义变量,然后在命令中使用它们。例如:

1
2
3
4
5
6
7
8
CC=gcc
CFLAGS=-I.

%.o: %.c
$(CC) -c -o $@ $< $(CFLAGS)

myprogram: main.o utility.o
$(CC) -o myprogram main.o utility.o

在这个示例中,CCCFLAGS 是变量,$(CC)$(CFLAGS) 是对变量的引用。$@$< 是自动变量,$@ 表示目标文件名,$< 表示第一个依赖文件名。

7.4. 使用伪目标

有时候,我们希望定义一些并不产生文件的目标,例如清理构建生成的文件。我们可以使用 .PHONY 伪目标来定义这种规则:

1
2
3
4
.PHONY: clean

clean:
rm -f *.o myprogram

在这个示例中,如果我们运行 make cleanmake 工具就会执行 rm -f *.o myprogram 命令,删除所有 .o 文件和 myprogram 文件。

以上就是 Makefile 的基础知识。理解并会用 Makefile 可以帮助你更有效地编译和构建 C 程序。在实际使用中,Makefile 可能会包含更复杂的规则和变量,但基本的思想和结构都是一样的。

7.5. 编译选项和标记

在使用 makeMakefile 进行 C 程序编译和链接时,你可能会遇到很多选项和标记。以下是其中一些最常见的。

CFLAGS

CFLAGSgcc (GNU Compiler Collection 的 C 编译器部分) 中用于设置 C 编译器选项的环境变量。这些选项包括优化级别、警告级别、调试信息等。

以下是一些常见的 CFLAGS 选项:

  • -O : 这个选项用于设置优化级别,如 -O1-O2-O3-Os。更高的优化级别会使编译器花更多的时间来优化代码,以生成更快的程序。
  • -g : 这个选项使编译器生成调试信息,这对于使用 gdb 等调试工具非常有用。
  • -Wall : 这个选项使编译器生成所有的警告信息,这可以帮助你发现代码中的问题。

LDFLAGS

LDFLAGSgcc 中用于设置链接器选项的环境变量。这些选项包括库搜索路径、链接的库等。

以下是一些常见的 LDFLAGS 选项:

  • -L : 这个选项用于指定库搜索路径,如 -L/usr/local/lib
  • -l : 这个选项用于指定要链接的库,如 -lm 指定链接数学库。

-I

-Igcc 中用于设置头文件搜索路径的选项。例如,-I/usr/local/include 会使编译器在 /usr/local/include 目录中搜索头文件。

-D

-Dgcc 中用于定义宏的选项。例如,-DDEBUG 会定义一个名为 DEBUG 的宏。

Makefile 中,你可以设置 CFLAGSLDFLAGS 变量,然后在编译和链接命令中使用它们。例如:

1
2
3
4
5
6
CC=gcc
CFLAGS=-I. -g -O2 -Wall
LDFLAGS=-L/usr/local/lib -lm

myprogram: main.o utility.o
$(CC) $(LDFLAGS) -o $@ $^ $(CFLAGS)

在这个示例中,编译命令会包含 -I. -g -O2 -Wall 选项,链接命令会包含 -L/usr/local/lib -lm 选项。

7.6. 编写通用性强的 Makefile

当我们有很多 .c 文件时,如果每次增加或删除 .c 文件都需要修改 Makefile,那么将会非常麻烦。一个解决办法是编写一个通用性强的 Makefile,使其能自动检测并编译所有 .c 文件。

以下是一个示例,这个 Makefile 可以自动检测所有 .c 文件,并编译它们生成对应的 .o 文件,最后链接所有 .o 文件生成目标程序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
CC=gcc
CFLAGS=-I.

# 使用 Shell 命令查找所有 .c 文件
SRCS=$(shell find . -name "*.c")
# 把 .c 文件列表转化为 .o 文件列表
OBJS=$(patsubst %.c,%.o,$(SRCS))

myprogram: $(OBJS)
$(CC) -o $@ $^ $(CFLAGS)

%.o: %.c
$(CC) -c -o $@ $< $(CFLAGS)

.PHONY: clean

clean:
rm -f $(OBJS) myprogram

在这个 Makefile 中:

  • $(shell find . -name "*.c") 使用 find 命令查找所有 .c 文件。
  • $(patsubst %.c,%.o,$(SRCS)).c 文件列表转化为 .o 文件列表。
  • myprogram: $(OBJS) 指定了 myprogram 依赖于所有 .o 文件。
  • %.o: %.c 是一个模式规则,它指定了如何从 .c 文件生成 .o 文件。

当我们运行 make 命令时,make 工具会自动检测并编译所有 .c 文件,然后链接所有 .o 文件生成目标程序。

这个 Makefile 具有很好的通用性,无论我们增加或删除 .c 文件,都不需要修改 Makefile。我们只需要保证所有 .c 文件都在 Makefile 所在目录或其子目录下即可。

7.7. 调试 Makefile

当你编写的 Makefile 没有按预期的方式工作时,你可能需要调试它。幸运的是,make 工具提供了一些选项来帮助我们调试 Makefile

-n--just-print 选项可以让 make 工具只打印命令,而不真正执行它们。这个选项对于检查 Makefile 中的命令是否正确非常有用。

例如,你可以运行 make -n myprogram 来查看生成 myprogram 的命令是否正确。

-d 选项会让 make 工具打印大量的调试信息,包括它是如何读取 Makefile,如何决定规则的依赖关系,以及如何执行命令等等。这个选项非常有用,但它可能会产生很多输出。

$(warning ...) 函数会打印一条警告信息,然后继续执行 make$(info ...) 函数会打印一条信息,但不会产生警告或错误。这两个函数可以用来检查变量的值或调试 Makefile

例如,你可以在 Makefile 中添加一行 $(info SRCS is $(SRCS)) 来查看 SRCS 变量的值。

--debug-d 选项可以让 make 打印出大量的调试信息,这对于理解 make 是如何解析 Makefile,以及它是如何决定哪些目标需要重新构建的,非常有用。

make 是通过比较目标和它的依赖项的时间戳来决定是否需要重新构建目标。如果你的 Makefile 没有按预期的方式工作,可能是因为文件的时间戳有问题。你可以使用 ls -l 命令来查看文件的时间戳。

调试 Makefile 可能需要一些耐心和实践,但是一旦你理解了 make 工具的工作方式,你就能编写出更强大、更灵活的 Makefile

7.8. xuedue

  • 符号信息

file 查看文件信息,可以看到符号信息,not stripped 就是没有去符号

使用 strip filename 可以去符号(strip可能在其他目录中)

附录

Shell 常用命令速查表

命令 描述 常用选项
ls 列出目录中的文件和子目录 -l:长格式 < br> -a:包括隐藏文件 < br> -h:易读的文件大小 < br> -t:按修改时间排序 < br> -r:反向排序
cd 改变当前目录 ..:上级目录 < br> ~:用户主目录 < br> -:上次工作目录
pwd 打印当前工作目录 -
cp 复制文件或目录 -r:复制目录 < br> -p:保留文件属性
mv 移动或重命名文件或目录 -
rm 删除文件或目录 -r:删除目录 < br> -f:强制删除
cat 查看或连接文件内容 -n:显示行号
less 分页查看文件内容 -
grep 搜索文本 -i:忽略大小写 < br> -r:递归搜索 < br> -v:显示不匹配行
find 查找文件或目录 -name:按名称查找 < br> -type:按类型查找 < br> -size:按大小查找
tar 打包或解压缩文件 -c:创建归档文件 < br> -x:提取文件 < br> -f:指定文件名 < br> -v:显示详细信息 < br> -z:gzip 压缩 / 解压 < br> -j:bzip2 压缩 / 解压