介绍
在这个实验(Lab)中,你将获得在 Linux 中管理文本文件和自定义 shell 环境的基本技能。你将学习如何将标准输出和错误流重定向到文件,组合不同的流,并构建强大的命令管道来自动化任务。
此外,你将探索使用 Vim(一个广泛使用且功能强大的文本编辑器)编辑文本文件的基础知识。最后,你将学习配置和使用 shell 变量和别名,以个性化你的命令行体验并提高生产力。
在这个实验(Lab)中,你将获得在 Linux 中管理文本文件和自定义 shell 环境的基本技能。你将学习如何将标准输出和错误流重定向到文件,组合不同的流,并构建强大的命令管道来自动化任务。
此外,你将探索使用 Vim(一个广泛使用且功能强大的文本编辑器)编辑文本文件的基础知识。最后,你将学习配置和使用 shell 变量和别名,以个性化你的命令行体验并提高生产力。
在这一步中,你将学习如何将命令的标准输出重定向到文件。这是 Linux 系统管理中的一项基本技能,允许你捕获命令结果,以便后续分析、日志记录或进一步处理。
shell 使用特殊的 file descriptor(文件描述符)来管理输入和输出。最常见的有:
0:标准输入(stdin)——通常来自键盘。1:标准输出(stdout)——通常到终端屏幕。2:标准错误(stderr)——通常到终端屏幕,用于错误消息。我们将在本节中重点关注重定向 stdout。
> 覆盖文件> 运算符将命令的标准输出重定向到指定的文件。如果文件不存在,则会创建它。如果文件已经存在,则其内容将被覆盖。
让我们从创建一个包含当前日期和时间的简单文本文件开始。
首先,确保你在你的主目录的 project 文件夹中。
cd ~/project
[labex@host project]$
现在,使用 date 命令并将其输出重定向到一个名为 current_datetime.txt 的新文件。
date > current_datetime.txt
此命令将执行 date,但不会将日期打印到你的终端,而是将其保存到 current_datetime.txt 中。
使用 cat 命令验证文件的内容。
cat current_datetime.txt
Mon Day XX HH:MM:SS AM/PM TimeZone YYYY
输出将显示当前的日期和时间,类似于上面的示例。
现在,让我们尝试将 echo 的输出重定向到同一个文件。这将覆盖之前的内容。
echo "This is a new line of text." > current_datetime.txt
再次检查文件内容。
cat current_datetime.txt
This is a new line of text.
正如你所看到的,原始的日期和时间被新的文本行替换了。
>> 追加到文件>> 运算符将命令的标准输出重定向到指定的文件,并将新内容追加到文件的末尾。如果文件不存在,则会创建它。
让我们向我们的 current_datetime.txt 文件追加更多内容。
向 current_datetime.txt 追加另一行文本。
echo "This line is appended." >> current_datetime.txt
查看文件的内容。
cat current_datetime.txt
This is a new line of text.
This line is appended.
请注意,新行已添加到现有内容之后。
让我们再次追加当前的日期和时间。
date >> current_datetime.txt
再次检查文件内容。
cat current_datetime.txt
This is a new line of text.
This line is appended.
Mon Day XX HH:MM:SS AM/PM TimeZone YYYY
日期和时间现在位于文件的末尾。
你可以重定向几乎任何命令的输出。让我们尝试重定向 ls 和 wc 的输出。
将 ls -l(长列表格式)的输出重定向到一个名为 file_list.txt 的文件。
ls -l > file_list.txt
检查 file_list.txt 的内容。
cat file_list.txt
total 4
-rw-r--r-- 1 labex labex 80 Jun 4 07:04 current_datetime.txt
-rw-r--r-- 1 labex labex 0 Jun 4 07:04 file_list.txt
此文件现在包含当前目录中文件的详细列表。确切的文件大小和时间戳将根据你运行命令的时间而有所不同。
现在,让我们使用 wc -l 统计 file_list.txt 中的行数,并将该计数重定向到另一个文件 line_count.txt。
wc -l file_list.txt > line_count.txt
查看 line_count.txt 的内容。
cat line_count.txt
3 file_list.txt
输出显示 file_list.txt 有 3 行(包括 total 行和两个文件条目)。
这结束了重定向标准输出的第一部分。你已经学习了如何使用 > 创建和覆盖文件,以及使用 >> 将内容追加到文件。
在这一步中,你将学习如何重定向标准错误(stderr)以及如何将 stdout 和 stderr 组合成单个流。这对于管理命令生成的错误消息至关重要,允许你根据需要记录或丢弃它们。
回想一下,stderr 是文件描述符 2。我们使用 2> 来重定向错误消息。
有时,命令会产生你希望与标准输出分开捕获的错误消息。
确保你在你的 ~/project 目录中。
cd ~/project
[labex@host project]$
让我们尝试列出不存在的目录的内容。这将生成一条错误消息。
ls non_existent_directory
ls: cannot access 'non_existent_directory': No such file or directory
你可以在终端上直接看到错误消息。
现在,让我们将此错误消息重定向到一个名为 errors.log 的文件。
ls non_existent_directory 2> errors.log
这次,你不会在你的终端上看到错误消息。
检查 errors.log 的内容。
cat errors.log
ls: cannot access 'non_existent_directory': No such file or directory
错误消息现在存储在文件中。
通常,你可能希望运行一个产生你不在乎的嘈杂错误消息的命令。在这种情况下,你可以将 stderr 重定向到 /dev/null。/dev/null 是一个特殊的设备文件,它会丢弃写入其中的所有数据。
再次尝试使用不存在的目录的 ls 命令,但这次丢弃错误。
ls non_existent_directory 2> /dev/null
你将在终端上看不到任何输出,并且没有错误消息被保存到文件中。
在某些情况下,你希望将 stdout 和 stderr 都捕获到同一个文件中。这可以通过几种方式完成。
> file 2>&1此方法将 stdout 重定向到一个文件,然后将 stderr 重定向到与 stdout 相同的位置。顺序 2>&1 很重要:它表示“将文件描述符 2(stderr)重定向到与文件描述符 1(stdout)相同的位置”。
让我们创建一个同时产生标准输出和标准错误的命令。我们将使用 find 在我们有权限的目录和我们没有权限的目录中搜索文件。
find ~/project /root -name "current_datetime.txt" > combined_output.log 2>&1
在这里,find ~/project -name "current_datetime.txt" 将产生 stdout(如果找到),而 find /root -name "current_datetime.txt" 可能会由于权限问题而产生 stderr。
检查 combined_output.log 文件。
cat combined_output.log
/home/labex/project/current_datetime.txt
find: ‘/root’: Permission denied
你可以看到成功的输出(文件的路径)和错误消息都被捕获在同一个文件中。
&> file(Bash 特有)Bash 提供了一种将 stdout 和 stderr 组合到文件中的简写方式:&>。这等效于 > file 2>&1。
让我们使用 &> 简写方式尝试相同的 find 命令。
find ~/project /root -name "file_list.txt" &> combined_output_shorthand.log
检查 combined_output_shorthand.log 的内容。
cat combined_output_shorthand.log
/home/labex/project/file_list.txt
find: ‘/root’: Permission denied
结果与前一种方法相同,证明了 &> 的便利性。
就像使用 stdout 一样,你可以使用 >> file 2>&1 或 &>> file 将组合的 stdout 和 stderr 追加到文件中。
将更多输出和错误追加到 combined_output.log。
find ~/project /root -name "line_count.txt" >> combined_output.log 2>&1
查看更新后的 combined_output.log。
cat combined_output.log
/home/labex/project/current_datetime.txt
find: ‘/root’: Permission denied
/home/labex/project/line_count.txt
find: ‘/root’: Permission denied
新的输出和错误被追加到现有内容中。
你现在已经成功学习了如何重定向标准错误以及如何将标准输出和标准错误组合到单个文件中。这些知识对于强大的脚本编写和系统管理任务至关重要。
在这一步中,你将学习命令管道,这是 Linux shell 中一个强大的功能,它允许你将多个命令链接在一起。一个命令的输出成为下一个命令的输入,从而实现复杂的数据处理和操作。
管道运算符 |(竖线)用于连接管道中的命令。它将其左侧命令的标准输出(stdout)重定向到其右侧命令的标准输入(stdin)。
让我们从一个简单的例子开始,以了解管道的工作原理。
确保你在你的 ~/project 目录中。
cd ~/project
[labex@host project]$
首先,让我们列出当前目录中的文件。
ls
combined_output.log
combined_output_shorthand.log
current_datetime.txt
errors.log
file_list.txt
line_count.txt
现在,让我们将 ls 的输出通过管道传递给 wc -l 命令,该命令计算它接收到的行数。
ls | wc -l
6
ls 命令列出文件,其输出(每个文件名在新的一行)被馈送到 wc -l 作为输入,然后 wc -l 计算这些行,有效地告诉你当前位置有多少个文件/目录。
让我们尝试另一个常见的用例:将 ls -l 通过管道传递给 less 以进行分页输出。当一个命令产生太多输出而无法容纳在一个屏幕上时,这很有用。
ls -l /usr/bin | less
total 200000
-rwxr-xr-x 1 root root 12345 Jan XX HH:MM [filename]
... (press 'q' to quit less) ...
ls -l /usr/bin 命令列出 /usr/bin 中的所有文件及其详细信息。然后将此输出发送到 less,允许你逐页滚动浏览它。按 q 退出 less。
grep 过滤输出grep 命令通常用于管道中,以过滤匹配特定模式的行。
让我们使用 ps aux 列出系统上运行的所有进程,然后过滤与 bash 相关的进程。
ps aux | grep bash
labex 1234 0.0 0.1 12345 6789 ? Ss HH:MM 0:00 /usr/bin/bash
labex 5678 0.0 0.0 9876 5432 pts/0 S+ HH:MM 0:00 grep bash
ps aux 命令列出所有正在运行的进程。它的输出通过管道传递给 grep bash,然后 grep bash 仅显示包含单词“bash”的行。你可能会看到两行:一行用于你当前的 bash shell,另一行用于 grep 命令本身。
要从输出中排除 grep 命令,你可以使用 grep -v(反向匹配)或完善你的模式。让我们尝试 grep -v grep。
ps aux | grep bash | grep -v grep
labex 1234 0.0 0.1 12345 6789 ? Ss HH:MM 0:00 /usr/bin/bash
现在,仅显示实际的 bash 进程。
sort 和 uniqsort 用于对文本行进行排序,而 uniq 用于报告或省略重复的行。它们经常一起使用。
让我们创建一个包含一些未排序的重复单词的文件。
echo -e "apple\nbanana\napple\norange\nbanana" > fruits.txt
查看 fruits.txt 的内容。
cat fruits.txt
apple
banana
apple
orange
banana
现在,让我们对 fruits.txt 中的行进行排序。
cat fruits.txt | sort
apple
apple
banana
banana
orange
要仅获取唯一的排序单词,请将 sort 的输出通过管道传递给 uniq。
cat fruits.txt | sort | uniq
apple
banana
orange
此管道首先对行进行排序,然后 uniq 删除重复的相邻行。
tee 命令tee 命令在管道中很特殊。它读取标准输入,将其写入标准输出,并同时将其写入一个或多个文件。它就像管道中的一个“T”形连接,允许数据双向流动。
让我们列出文件并将输出保存到 ls_output.txt,同时也在屏幕上显示它。
ls -l | tee ls_output.txt
total 24
-rw-r--r-- 1 labex labex 123 Jan XX HH:MM combined_output.log
-rw-r--r-- 1 labex labex 123 Jan XX HH:MM combined_output_shorthand.log
-rw-r--r-- 1 labex labex 123 Jan XX HH:MM current_datetime.txt
-rw-r--r-- 1 labex labex 123 Jan XX HH:MM errors.log
-rw-r--r-- 1 labex labex 123 Jan XX HH:MM file_list.txt
-rw-r--r-- 1 labex labex 123 Jan XX HH:MM fruits.txt
-rw-r--r-- 1 labex labex 123 Jan XX HH:MM line_count.txt
-rw-r--r-- 1 labex labex 0 Jan XX HH:MM ls_output.txt
你将在终端上看到 ls -l 的输出,并且将创建一个名为 ls_output.txt 的文件,其中包含相同的内容。
验证 ls_output.txt 的内容。
cat ls_output.txt
total 24
-rw-r--r-- 1 labex labex 123 Jan XX HH:MM combined_output.log
... (same as above) ...
你也可以使用 tee -a 将输出追加到文件。
echo "--- End of list ---" | tee -a ls_output.txt
--- End of list ---
行“--- End of list ---”被打印到终端并追加到 ls_output.txt。
检查更新后的 ls_output.txt。
cat ls_output.txt
total 24
... (previous ls -l output) ...
--- End of list ---
管道非常通用,并且构成了许多强大的 shell 脚本和单行命令的基础。通过组合简单的命令,你可以有效地执行复杂的数据转换。
在这一步中,你将学习 Vim 的基本操作,Vim 是 Linux 环境中一个强大且广泛使用的文本编辑器。Vim 在不同的模式下运行,这对于初学者来说可能有点挑战性,但掌握基础知识将显著提高你的工作效率。
Vim 是一个模式编辑器,这意味着它具有针对不同任务的不同模式:
i(在光标处插入)、a(在光标后追加)、o(在下方打开新行)等从普通模式进入插入模式。要返回普通模式,请按 Esc。v(字符级)、Shift+V(行级)或 Ctrl+V(块级)从普通模式进入可视模式。按 Esc 返回普通模式。:)开头的命令,例如保存(:w)、退出(:q)或搜索(/)。你通过按 : 从普通模式进入此模式。确保你在你的 ~/project 目录中。
cd ~/project
[labex@host project]$
使用 vim 打开一个名为 my_document.txt 的新文件。
vim my_document.txt
你的终端现在将显示 Vim 界面。你处于普通模式。
在普通模式下,你可以使用箭头键或 h(左)、j(下)、k(上)、l(右)进行导航。由于文件是空的,所以还没有太多可以导航的内容。
要开始输入,你需要进入插入模式。按 i(用于插入)。
你应该在终端的左下角看到 -- INSERT --,这表示你处于插入模式。
键入以下几行:
This is the first line.
This is the second line.
This is the third line.
要退出插入模式并返回普通模式,请按 Esc 键。
-- INSERT -- 指示符应该消失。
在普通模式下,要保存文件,请键入 :w 并按 Enter。
:w
你应该在底部看到 my_document.txt [New] 3L, 60B written,确认已保存。
要退出 Vim,请键入 :q 并按 Enter。
:q
你将返回到你的 shell 提示符。
使用 cat 验证 my_document.txt 的内容。
cat my_document.txt
This is the first line.
This is the second line.
This is the third line.
再次打开 my_document.txt。
vim my_document.txt
在普通模式下,将你的光标移动到第二行的开头(使用 j 或箭头键)。
按 Shift+V 进入可视行模式。整行将被高亮显示。
按 y “yank”(复制)选定的行。
将你的光标移动到第三行的末尾(使用 j 或箭头键)。
按 p “put”(粘贴)yank 的行到当前行的下方。
第二行现在将再次显示为第四行。
现在,让我们删除一行。将你的光标移动到第四行(你刚刚粘贴的那一行)。
按 dd(双击 d)删除整行。
要撤消你的最后一次更改,请按 u。删除的行将重新出现。
要在一个命令中保存并退出,请键入 :wq 并按 Enter。
:wq
再次验证 my_document.txt 的内容。
cat my_document.txt
This is the first line.
This is the second line.
This is the third line.
This is the second line.
该文件现在应该有四行,第二行被复制了。
有时你进行更改并决定不想保存它们。
再次打开 my_document.txt。
vim my_document.txt
通过按 i 进入插入模式。
在末尾添加一个新行:
This line should not be saved.
按 Esc 返回普通模式。
尝试使用 :q 退出。
:q
Vim 将警告你:E37: No write since last change (add ! to override)。这意味着你未保存更改。
要退出而不保存,请键入 :q! 并按 Enter。
:q!
你将返回到 shell 提示符,并且你的更改将被放弃。
验证 my_document.txt 的内容。
cat my_document.txt
This is the first line.
This is the second line.
This is the third line.
This is the second line.
你添加的最后一行不应存在。
你现在已经涵盖了 Vim 中最基本的操作:打开文件、插入文本、导航、保存、退出和放弃更改。这些是开始使用 Vim 的基本技能。
在这一步中,你将学习如何配置和使用 shell 变量和别名。这些是强大的功能,允许你自定义你的 shell 环境,存储数据,并为常用命令创建快捷方式,从而显著提高你的命令行效率。
Shell 变量是存储数据的命名实体。它们可以存储数字、文本或其他数据,这些数据可以被 shell 或在 shell 中执行的程序使用。
确保你在你的 ~/project 目录中。
cd ~/project
[labex@host project]$
设置局部变量:让我们创建一个名为 MY_MESSAGE 的简单变量。
MY_MESSAGE="Hello, LabEx!"
请注意,= 符号周围没有空格。
访问变量:要访问变量的值,请在其名称前加上 $ 符号。
echo $MY_MESSAGE
Hello, LabEx!
使用大括号进行变量扩展:有时,你需要清楚地分隔变量名,尤其是在它后面跟着其他字符时。为此使用花括号 {}。
echo "The message is: ${MY_MESSAGE}."
The message is: Hello, LabEx!.
如果你省略大括号,shell 可能会将 MY_MESSAGE. 解释为变量名,而该变量名不存在。
列出所有已设置的变量:你可以使用 set 命令列出所有当前已设置的 shell 变量和函数。此输出可能很长,因此通常通过管道传递给 less。
set | less
BASH=/usr/bin/bash
BASHOPTS=checkwinsize:cmdhist:complete_fullquote:expand_aliases:extglob:extquote:force_fignore:histappend:interactive_comments:progcomp:promptvars:sourcepath
... (press 'q' to quit less) ...
按 q 退出 less。
取消设置变量:要删除变量,请使用 unset 命令。
unset MY_MESSAGE
验证该变量是否不再设置。
echo $MY_MESSAGE
你应该看到一个空行,这表示该变量已取消设置。
环境变量是一种特殊类型的 shell 变量,由子进程继承。这意味着从你当前 shell 启动的任何程序或脚本都将有权访问这些变量。它们通常用于配置应用程序的环境。
设置环境变量:使用 export 命令将变量设置为环境变量。
export EDITOR=vim
这将设置 EDITOR 环境变量,许多程序使用它来确定你喜欢的文本编辑器。
列出环境变量:使用 env 命令仅列出环境变量。
env | grep EDITOR
EDITOR=vim
取消导出变量:你可以使用 export -n 取消导出变量,而无需取消设置它。这使其再次成为局部变量。
export -n EDITOR
验证它不再是环境变量。
env | grep EDITOR
你应该看不到任何输出。但是,它仍然是一个局部变量:
echo $EDITOR
vim
要完全删除它,请使用 unset。
unset EDITOR
别名是命令的快捷方式。它们允许你定义一个新命令,该命令扩展为更长的命令或一系列命令。这对于经常使用且带有许多选项的命令非常有用。
创建别名:让我们为 ls -l 创建一个别名,使其更短。
alias ll='ls -l'
请注意命令周围的单引号,以确保将其视为单个字符串。
使用别名:现在,你可以简单地键入 ll 而不是 ls -l。
ll
total 24
-rw-r--r-- 1 labex labex 123 Jan XX HH:MM combined_output.log
... (output of ls -l) ...
列出别名:使用不带任何参数的 alias 命令查看所有已定义的别名。
alias
alias ll='ls -l'
你可能会看到其他默认别名,具体取决于你的 shell 配置。
创建更复杂的别名:你还可以为带有参数或多个命令的命令创建别名。
alias myip='ip a | grep "inet " | grep -v "127.0.0.1" | awk "{print \$2}" | cut -d/ -f1'
在这里,myip 将显示你的主 IP 地址。请注意 \$2 以转义 $ 符号,以便将其传递给 awk,而不是在定义别名时由 shell 解释。
测试 myip 别名。
myip
172.17.0.2
(你的 IP 地址可能有所不同)
取消设置别名:要删除别名,请使用 unalias 命令。
unalias ll
验证别名是否已删除。
alias
alias myip='ip a | grep "inet " | grep -v "127.0.0.1" | awk "{print \$2}" | cut -d/ -f1'
ll 应该不再在列表中。
Shell 变量和别名是临时的,当你关闭终端会话时,它们将丢失。要使它们永久生效,你需要将它们添加到你的 shell 的配置文件(例如,~/.bashrc 或 ~/.profile)中,这将在更高级的主题中介绍。
在这个实验中,你学习了基本的 Linux 命令行技能,这些技能对于管理文本文件和 shell 环境至关重要。你首先掌握了输出重定向,特别是使用 > 覆盖文件和使用 >> 追加内容,这使你能够捕获命令结果以进行日志记录或进一步处理。你还探索了重定向标准错误(2>)以及组合标准输出和错误(&>),以有效地管理所有命令输出。
此外,你还熟练掌握了使用 | 运算符构建和理解命令管道,这使你能够链接命令并顺序处理数据。你还通过 Vim 学习了基本的文本编辑,涵盖了插入、保存和退出文件的基本命令。最后,你学习了如何配置和使用 shell 变量来存储数据,以及创建别名以简化常用命令,从而提高了你的命令行效率和自定义能力。