【THM】Linux Shells-学习
本文相关的TryHackMe实验房间链接:https://tryhackme.com/r/room/linuxshells
本文相关内容:学习shell脚本和不同类型的Linux shell。

Linux shell 简介
作为操作系统的常规用户,我们都广泛地在使用图形用户界面(GUI)来执行大多数操作。只需在不同的选项上单击几下,你的任务就完成了;但是,你还可以选择通过在操作系统的CLI中编写命令而不是使用GUI来执行几乎所有任务。 shell为你在CLI中编写的命令提供了一些很棒的功能。这种与操作系统进行交互的方式和使用图形用户界面相比更加高效且资源友好。
假设你在一家餐馆吃饭,有两种食物获取方式可供选择:第一种选择是从菜单上点菜,服务员就会上菜,第二种选择是在厨房自己做饭。对于Linux系统来说,这里的厨房就是指操作系统,使用操作系统的GUI就像从菜单上点菜,服务员会为你上菜一样;然而,使用CLI则意味着你必须去厨房(OS)自己烹饪你想要的食物。在此示例中,Shell将通过给你一些食谱建议来帮助你烹饪你想要的菜肴。使用CLI在Linux系统中执行操作可以让你在执行任务时拥有更多的能力和控制权限。
你可能在电影中看到过一些黑客攻击场景,其中显示了很酷的终端画面,在终端中执行了许多命令。大多数Linux用户更喜欢通过使用shell在CLI中编写命令来执行操作,而不是直接使用GUI。本文将教导我们学习如何与Linux shell进行交互,此外我们还将探索Linux中可用的不同shell,并最终编写一些shell脚本。

学习目标
- 学习如何与Linux shell 进行交互;
- 使用基本的 shell 命令;
- 探索可用的Linux shell 类型;
- 编写一些shell脚本。
前置学习条件
在学习本文内容之前,建议完成:
答题
谁是用户和操作系统之间的协调者?
Shell

如何与Shell进行交互?
在与本文相关的TryHackMe实验房间中,准备了一台目标机器。首先,让我们通过点击下面给出的“启动机器”按钮来启动虚拟机,然后目标机器将会以分屏视图的形式启动并展现。

如果目标虚拟机不可见,请使用实验房间页面顶部的蓝色显示拆分视图按钮。目标机器将会以GUI的形式为你打开。你还可以使用以下SSH凭据通过Attackbox或者使用你自己的本地攻击机来连接到目标实验计算机:

- Username:user
- Password:user@Tryhackme
- IP:MACHINE_IP
一旦目标计算机在分屏视图中打开,你将会有一个 shell 提示符界面来准备接受命令。
user@ubuntu:~$
虽然大多数Linux发行版本将会使用 Bash (Bourne Again Shell) 来作为默认的 shell;但是实际打开终端时所显示的默认 shell 还取决于你所使用的具体的Linux发行版本。
注意:在本文接下来的内容中,我们将会讨论不同类型的 shells。
你可能已经探索过了本文的前置学习条件中所提及的Linux基础模块中的基础Linux命令。在此,让我们简要讨论一下我们在shell中经常会使用到的一些最重要的函数。
当我们与 shell 进行交互时,你必须位于要执行具体操作的目录中。在默认情况下,当你在大多数Linux发行版本中打开 shell 时,你将位于主目录中。要查看当前的工作目录,你可以执行pwd命令,它代表打印工作目录(Print Working Directory),如下面的终端输出所示:
#Check Current Working Directory 检查当前工作目录
user@ubuntu:~$ pwd
/home/user
在上面的命令输出结果中,你可以看到你当前的工作目录是/home/user。
但是,你也可以更改你的目录。为此,你可以使用cd (Change Directory的缩写)命令,如下面的终端输出所示:
#Change Directory 更改目录
user@ubuntu:~$ cd Desktop
user@ubuntu:~$/Desktop$
当你使用操作系统的GUI时,你可以直接在屏幕上看到目录下的内容;但是,在你使用 shell 时,如果想要查看当前目录下的内容,你必须输入以下命令:
#List Directory Contents 列出目录内容
user@ubuntu:~$ ls
Desktop Documents Downloads Music Pictures Public Templates Videos
如果你想要读取指定文件的内容,你可以在 shell 中键入以下命令:
#Displaying File Contents 显示文件内容
user@ubuntu:~$ cat filename.txt
this is a sample file
this is the second line of the file
grep命令是Linux用户中非常流行的命令。这个强大的命令可以搜索文件内的任何单词或模式。假设你要在一个大文件中搜索特定条目,你可以使用grep命令并且附加这些条目的模式,这将为你提取它们。此命令还可以帮助你在大文件中搜索特定的关键字。
以下终端向我们展示了如何使用 grep 命令在大文本文件中搜索单词“THM”,输出结果将显示包含该单词的文本文件的特定行。
#Searching a Word In File 在文件中搜索单词
user@ubuntu:~$ grep THM dictionary.txt
The flag is THM
答题
大多数 Linux 发行版中的默认 shell 是什么?
Bash
哪个命令实用程序可用于列出目录的内容?
ls
哪个命令实用程序可以帮助你搜索文件中的任何内容?
grep

Linux shell的类型
与 Windows 操作系统中的命令提示符和 PowerShell 一样, Linux 也有不同类型的 shell,每种shell都有它们自己的功能和特性。
不同的Linux发行版中安装了多个 shell。要查看你当前正在使用哪个 shell,请键入以下命令:
#Current Shell
user@ubuntu:~$ echo $SHELL
/bin/bash
你还可以列出Linux操作系统中可用的 shell。文件/etc/shells包含了Linux系统上所有已安装的shell。你可以通过在终端中输入cat /etc/shells命令来列出当前的Linux操作系统中可用的shell:
#Available Shells
user@ubuntu:~$ cat /etc/shells
# /etc/shells: valid login shells
/bin/sh
/bin/bash
/usr/bin/bash
/bin/rbash
/usr/bin/rbash
/bin/dash
/usr/bin/dash
/usr/bin/tmux
/usr/bin/screen
/bin/zsh
/usr/bin/zsh
如果想要在这些 shell 之间进行切换,你可以在终端界面中输入操作系统上已存在的 shell 名称,它将为你打开对应的shell,如下所示:
#Switch Shell 切换Shell
user@ubuntu:~$ zsh
user@ubuntu ~ $
如果你想要永久更改当前操作系统的默认 shell,你可以使用命令: chsh -s /usr/bin/zsh 。这将使得指定的 shell 成为终端的默认 shell。
Linux shell 有多种类型,接下来我们将讨论其中的一些shell及其具备的功能。
Bash
Bourne Again Shell (Bash) 是大多数Linux发行版本的默认shell,当你打开终端时,会出现bash供你输入命令。在bash之前,一些shell(例如 sh、ksh和csh)具有不同的能力,Bash是这些shell的增强替代品shell,它借用了这些shell的功能。这意味着它有 这些旧shell的许多特征以及一些独特之处 的能力。
下面列出了bash可提供的一些关键功能:
- Bash是一种被广泛使用的具有脚本功能的shell。
- 它提供了Tab补全功能,这意味着如果你正在完成命令,你可以按键盘上的Tab键来进行命令补全。它将根据可能的匹配自动完成命令,或者为你提供多个完成命令的建议。
- Bash 会保留历史文件并记录所有命令。你可以使用向上和向下箭头键来使用以前的命令,而无需再次键入它们。你还可以键入
history来显示以前使用过的所有命令。
Fish
友好的交互式 Shell (Fish-Friendly Interactive Shell) 在大多数Linux发行版中不是默认的。正如其名称所暗示的那样,它更专注于 比其他 shell 更友好。Fish可提供的一些关键功能的分类如下:
- 它提供了非常简单的语法,对于初学者用户来说是可行的。
- 与 bash 不同的是,它可以自动拼写纠正你编写的命令。
- 你可以通过 fish 使用一些很酷的主题来自定义命令提示符。
- Fish 的语法高亮功能会根据命令的不同部分对命令进行颜色显示,这可以提高命令的可读性,它还可以帮助我们通过其独特的颜色来发现错误。
- Fish 还提供脚本编写、选项卡补全和命令历史记录功能,就像本小节中所提到的其他shell一样。
Zsh
大多数Linux发行版中默认未安装 Z Shell (Zsh) 。它被认为是一种现代式的Shell,结合了 一些以前的 shell 的功能。Zsh能够提供的一些关键功能如下所示:
- Zsh 能够提供高级Tab键补全功能,同时也能够支持脚本编写。
- 就像fish shell一样,Zsh 也能够提供命令的自动拼写纠正功能。
- 它提供了广泛的定制化功能,这可能会使其比其他 shell 更慢。
- 它还提供了选项卡补全、命令历史记录功能以及其他一些功能。
| Feature(特征) | Bash | Fish | Zsh |
|---|---|---|---|
| Full Name(全名) | Bash的完整名称是 Bourne Again Shell | Fish的完整名称是Friendly Interactive Shell | Zsh的完整名称是Z Shell |
| Scripting(脚本编写功能) | 它能提供广泛兼容的脚本和大量可用文档 | 与其他两个 shell相比,它的脚本功能有限 | 它提供了出色的脚本编写功能,它结合了Bash shell的传统功能与一些额外的功能 |
| Tab completion(Tab键补全功能) | 它具有基础的Tab键补全功能 | 它将根据你之前使用的命令来提供建议以完成高级Tab键补全 | 它的Tab键补全功能可以通过使用插件来进行大幅度扩展 |
| Customization(定制化) | 提供基础的定制级别 | 它通过交互式工具提供了一些很好的定制选项 | 它允许用户通过 oh-my-zsh 框架来进行高级定制 |
| User friendliness(用户友好性) | 它的用户友好性较差,但作为一种传统且广泛使用的shell,大部分用户对它非常熟悉而且使用起来较为舒适 | 它是最能体现用户友好性的shell | I通过适当的定制,它可以变得高度用户友好 |
| Syntax highlighting(语法高亮) | 语法突出显示功能在此 shell 中不可用 | 语法高亮显示是内置于该 shell 中的功能 | 通过引入一些插件,语法高亮功能可以与此shell一起使用 |
选择最佳的Linux shell 取决于你的具体使用情况以及功能需求。在本小节中所讨论的 shell 是Linux中可用的许多不同 shell 中的一些。你可以比较这些不同shell的功能,并根据你的实际需求选择最合适的一种 进行使用。
答题
哪个 shell 带有语法高亮作为开箱即用的功能?
Fish
哪个 shell 没有自动拼写更正功能?
Bash
哪个命令可以显示当前会话中所有先前执行过的命令?
history

Shell脚本和组件
shell 脚本只不过是一组命令。假设有一个重复的任务要求你使用 shell 输入多个命令,但我们不想在每次重复该任务时都将相关命令一一输入,因为这可能需要花更多的时间,所以你可以将它们组合成一个脚本,如果想执行所有这些命令,你只需简单地执行脚本文件,然后所有命令都将被执行。前面提到的所有的不同shell都支持脚本编写功能。编写脚本可以帮助我们自动化执行任务。 在学习如何编写脚本之前,我们需要知道即使 Linux shell 具有脚本编写功能,但这并不意味着你只能使用shell来编写脚本。编写脚本也可以通过使用其他各种编程语言来完成。本文的内容范围将涵盖如何使用 shell 编写脚本。
Shell脚本编写的第一步是打开终端并选择一个 shell。这里我们可以使用 bash shell,它是大多数Linux发行版本中默认且被广泛使用的 shell。
与我们在 shell 中键入的其他命令不同,我们首先需要使用支持脚本编写的任何文本编辑器来创建一个新文件。该文件必须以扩展名.sh命名,这是bash脚本的默认扩展名。以下终端示例显示了脚本文件的具体创建过程:
#Create Script File 创建Shell脚本文件
user@ubuntu:~$ nano first_script.sh
每个Shell脚本都应该从 shebang 开始。 Shebang 是在脚本内容开头默认添加的一些字符的组合,由 #!后跟执行脚本时所使用的解释器的名称而组成。当我们在bash Shell中编写Shell脚本时,我们需要将bash定义为 shebang 中的解释器。
#!/bin/bash
现在我们已经准备好编写我们的第一个Shell脚本了。Shell脚本的一些基本构建块将共同构成一个高效的Shell脚本。接下来让我们学习并利用这些脚本结构来自己编写一个Shell脚本。
Variables 变量
变量,用于存储一个值。假设你需要在脚本中多次使用一些复杂的值,例如 URL、文件路径等,那么你可以将它们存储在变量中,并且在需要的地方使用变量名称,而不是重复地记住和编写它们。
下面的Shell脚本将在屏幕上显示字符串:“Hey, what’s your name?”这是通过echo命令完成的。 脚本的第二行包含read name,read用于获取用户的输入, 而name是一个用于存储输入内容的变量。下面脚本的最后一行使用“echo”为用户显示欢迎行,并且将用户输入的name值存储在给定的变量中。
# Defining the Interpreter
#!/bin/bash
echo "Hey, what’s your name?"
read name
echo "Welcome, $name"
要执行一个shell脚本,我们首先需要确保该脚本文件具有可执行权限,为了向脚本文件授予这样的权限,我们可以在终端中键入以下命令:
#Execution Permission to Script 脚本执行权限
user@ubuntu:~$ chmod +x variable_script.sh
现在示例脚本文件具有可执行权限,我们就可以在脚本名称之前使用./来尝试执行它。我们在脚本运行之前使用./而不是直接键入脚本名称,是因为./会告诉shell去执行当前目录中已存在的指定文件。如果在脚本名称之前没有定义./,那么系统将在 PATH 环境变量(包含除当前目录之外的所有目录)中搜索具体的脚本,但是如果在任何这些目录中找不到定义的脚本,就会产生执行错误。
下面的终端输出显示了我们正在执行variable_script.sh脚本文件:
user@ubuntu:~$ ./variable_script.sh
Hey, What's your name?
John
Welcome, John
Loops 循环
循环,顾名思义,是重复的东西。例如,你有一个包含许多朋友的列表,并且你想向他们发送相同的消息,那么你就可以在脚本内容中创建一个循环,将你的朋友列表提供给循环和消息,而不是单独发送它们,这会将该消息发送给你的所有朋友。
为了对循环进行一般性解释,让我们编写一个循环示例,以下脚本示例将会在屏幕上显示从 1 到 10 的所有数字:
# Defining the Interpreter
#!/bin/bash
for i in {1..10};
do
echo $i
done
第一行有变量i,它将从 1 迭代到 10 并每次执行后面的代码。 do表示循环代码的开始, done表示结束。在它们之间,写入我们想要在循环中执行的具体代码。for循环将在每次迭代中获取{}括号中的每个数字并将其分配给变量i ,而echo $i将会在每次迭代时向屏幕显示该变量的值。
现在,让我们在授予该脚本可执行权限后尝试执行该脚本。
#chmod +x loop_script.sh
user@ubuntu:~$ ./loop_script.sh
1
2
3
...
上述终端的输出结果被削减为3个数字以供演示。当根据上述脚本的逻辑实际执行脚本文件时,它会显示从1 到 10的所有数字。
Conditional Statements 条件语句
条件语句是Shell脚本编写的重要组成部分。它们可以帮助你仅在满足条件时执行特定代码,否则你可以执行另一段代码。假设你想要制作一个向用户显示秘密内容的脚本,但是你希望它仅向某些用户显示,比如仅向高权限用户显示;那么你就可以创建一个条件语句,首先询问用户的姓名,如果姓名与高权限用户的姓名匹配,就向该用户显示秘密内容。
# Defining the Interpreter
#!/bin/bash
echo "Please enter your name first:"
read name
if [ "$name" = "Stewart" ]; then
echo "Welcome Stewart! Here is the secret: THM_Script"
else
echo "Sorry! You are not authorized to access the secret."
fi
fi(即if倒过来拼写)是 Bash 中用来显式关闭if语句的关键字,类似于其他编程语言中的}或endif。类似的其他 Shell 语法结束标记:
case ... esac(case语句的结束)do ... done(for/while循环的结束)
上面的脚本将用户名作为输入并将其存储到变量中。条件语句以 if 开头,并将该变量的值与字符串 Stewart 进行比较;如果成功匹配,那么它将向用户显示秘密内容,否则不显示。 fi 则用于结束 for 循环。
以下是相关的终端示例界面 以及 当用户名与脚本中已定义的授权用户名成功匹配时所显示的脚本执行结果:
user@ubuntu:~$ ./conditional_script.sh
Please enter your name first:
Stewart
Welcome, Stewart! Here is the secret: THM_Script
但是,当用户名与脚本中已定义的授权用户名不匹配时,那么将显示的脚本执行情况会如下所示:
user@ubuntu:~$ ./conditional_script.sh
Please enter your name first:
Alex
Sorry! You are not authorized to access the secret.
Comments 注释
有时,Shell脚本内容中的代码可能会很长,在这种情况下,当你在一段时间后查看该代码或者与他人共享该代码时,你可能会在理解的时候感到困惑。解决此问题的一个简单方法是在代码的不同部分使用注释。注释是我们为了便于理解而在代码中写的一些话,它在shell脚本中由 # 符号标识,后面会跟一个空格以及你需要编写的一些具体注释内容。例如,我们可以重写在上文的条件语句介绍部分中所讨论的示例脚本 并且向其添加一些注释内容:
# Defining the Interpreter
#!/bin/bash
# Asking the user to enter a value.
echo "Please enter your name first:"
# Storing the user input value in a variable.
read name
# Checking if the name the user entered is equal to our required name.
if [ "$name" = "Stewart" ]; then
# If it equals the required name, the following line will be displayed.
echo "Welcome Stewart! Here is the secret: THM_Script"
# Defining the sentence to be displayed if the condition fails.
else
echo "Sorry! You are not authorized to access the secret."
fi
通过注释来查看Shell脚本,这看起来会让内容理解起来更加简单。注释不会影响任何脚本的实际工作。好的脚本总会有一些注释。上面所显示的脚本示例包含了每行的注释内容,这只是对其概念的更好解释,在实际使用注释功能时 包含注释的最佳方法是在脚本的主要区域和复杂区域中定义它们。
注意:我们也可以使用其他类型的变量、循环和条件语句来实现不同的任务,此外,我们还可以在单个注释中添加多行注释。不过,这并不属于本文的内容范围。
答题
Bash 脚本中使用的 shebang 是什么?
“#!/bin/bash” (去掉引号)
哪条命令可以赋予脚本可执行权限?
chmod +x
哪个脚本功能可以帮助我们配置迭代任务?
Loops 循环

The Locker Script(储物柜脚本-示例)
在上一个小节中,我们研究了 shell 脚本中的变量、循环和条件语句。现在让我们利用这些知识来创建一个可以利用所有这些组件的 shell 脚本。
功能需求
某用户在银行中有一个储物柜,为了确保该储物柜的安全性,我们必须有一个脚本来在打开该储物柜之前先验证用户的身份。在实际执行时,该脚本会询问用户的姓名、公司名称和 PIN。如果某个用户输入了以下的详细信息,则应该允许进入,否则应拒绝访问。
- Username: John
- Company name: Tryhackme
- PIN: 7385

示例脚本的内容
# Defining the Interpreter
#!/bin/bash
# Defining the variables
username=""
companyname=""
pin=""
# Defining the loop
for i in {1..3}; do
# Defining the conditional statements
if [ "$i" -eq 1 ]; then
echo "Enter your Username:"
read username
elif [ "$i" -eq 2 ]; then
echo "Enter your Company name:"
read companyname
else
echo "Enter your PIN:"
read pin
fi
done
# Checking if the user entered the correct details
if [ "$username" = "John" ] && [ "$companyname" = "Tryhackme" ] && [ "$pin" = "7385" ]; then
echo "Authentication Successful. You can now access your locker, John."
else
echo "Authentication Denied!!"
fi
脚本执行
#Executing the Locker Script 执行Locker脚本
user@ubuntu:~$ ./locker_script.sh
Enter your Username:
John
Enter your Company name:
Tryhackme
Enter your PIN:
1349
Authentication Denied!!
答题
在Locker(储物柜)脚本中进行身份验证的正确 PIN 码是什么(参考本小节中所给定的内容)?
7385

实践练习
在与本文相关的实验环境中,已连接的Ubuntu计算机的默认用户目录/home/user下被放置了一个脚本,该脚本可以在特定目录中的所有文件(扩展名为 .log)中搜索特定的关键字。

注意:在正式执行给定的脚本文件之前,我们还需要进行一些更改操作。当你按照小节#2 中的说明启动计算机时,你将能够以普通用户的身份获得终端会话;但是,我们建议你升级成为 root 用户,以便在本小节的实际操作中 能够更好地在给定目录的所有文件中搜索flag内容。
要成为 root 用户,你只需键入以下命令并输入给定的用户密码(参考本文的第二小节-user@Tryhackme)即可:
#Become Root User 成为root用户
user@ubuntu:~$ sudo su
[sudo] password for user: user@Tryhackme
root@tryhackme:/home/user#
你可以通过参考以下信息来对给定的脚本文件的内容进行更改:
- Flag: thm-flag01-script
- Directory: /var/log
#!/bin/bash
# Defining the directory to search our flag
directory=" "
# Defining the flag to search
flag=" "
echo "Flag search in directory: $directory in progress..."
# Defining for loop to iterate over all the files with .log extension in the defined directory
for file in " "/*.log; do
# Check if the file contains the flag
if grep -q "$flag" "$file"; then
# Print the filename
echo "Flag found in: $(basename "$file")"
fi
done
提示:在脚本文件的内容中查找空双引号" "并填充它们,确保它们之间不留有任何空间。
答题
哪个文件的内容中包含了特定关键字?
tips:为了正确执行给定的脚本文件(flag_hunt.sh),我们需要对脚本文件进行 3 处更改。
ls
nano flag_hunt.sh
chmod +x flag_hunt.sh
./flag_hunt.sh


authentication.log
猫在哪里睡觉?
tips:打开包含给定flag的文件并查看其具体内容。
cat /var/log/authentication.log

under the table

本文小结
在本文中,我们研究了 shell 的重要性,并深入了解了Linux shell的世界,探索了它们的主要类型。我们对shell脚本及其在自动化任务中的作用有了很好的了解。最后,我们还尝试编写了一些很酷的shell脚本,并解决了一个与 从不同目录中查找神秘内容的脚本 相关的实践实验。

学习shell脚本和不同类型的Linux shell。
浙公网安备 33010602011771号