第二章 Bash脚本编程

在前一章中,学习了Linux中的许多命令。现在,让我们在命令行工具中将您的技能提升到一个新的水平。在本章中,您将看到如何基于目前所学的知识使用Bash创建脚本命令。为什么使用Bash脚本?Bash的通用性使渗透测试人员能够灵活地执行功能强大的终端命令,而无需安装编译器或集成开发环境(IDE)。要开发Bash脚本,您只需要一个文本编辑器,就可以了。什么时候应该使用Bash脚本?这是在开始本章之前要解决的一个重要问题!Bash不适合开发复杂的工具。如果你想这样做,你应该使用Python (Python基础知识将在本书后面介绍)。Bash用于快速、小型的工具,您可以在希望节省时间时实现这些工具(例如,为了避免重复相同的命令,您只需在Bash脚本中编写它们)。本章不仅会教你Bash脚本语言,还会向你展示编程的思想。如果您是编程新手,这是了解编程语言如何工作的一个很好的起点(它们有很多相似之处)。

一、使用BashUsing 打印到屏幕

二、使用变量

三、使用脚本参数

四、处理用户输入

五、创建函数

六、使用条件if语句

使用while和for循环


基本Bash脚本

基本的Bash脚本分为以下几类:

用户

输入

脚本输出

参数

在Bash中打印到屏幕

有两种常用的方法可以使用Bash脚本写入终端命令行输出。第一个简单的方法是使用echo命令。我们在前一章中看到(我们将文本值包含在单引号或双引号中):

echo 'test'

第二个方法是printf命令;这个命令比echo命令更灵活,因为它允许你格式化你想要打印的字符串:

printf 'message to print'

YPeegPe之前的公式过于简化;事实上,printf 还允许您格式化字符串(不仅仅是用于打印;它的作用还不止于此)。让我们看一个例子:如果我们想显示网络中活动主机的数量,我们可以使用以下模式:
printf "%s %d\n" "Number of live hosts:"

 

让我们把命令分开,这样你就可以理解发生了什么: 

%s:表示我们要在这个位置插入一个字符串(文本)

%d:表示我们要在这个位置添加一个小数(数字)

\n:表示我们要在打印完成后跳转到新的行

另外,请注意我们使用双引号而不是单引号。双引号使我们在处理字符串时比单引号更灵活。因此,大多数情况下,我们可以对printf使用双引号(很少需要使用单引号)。要使用printf命令格式化字符串,可以使用以下模式:

%s:字符串(文本)

%d:十进制(数字)

%f:浮点数(包括带符号数字)

%x:十六进制

\n:换行

\r:回车

\t:水平制表符

变量

什么是变量?为什么每种编程语言都使用它?将变量视为存储区域,您可以在其中保存字符串和数字等内容。目标是在程序中一遍又一遍地重用它们,这个概念适用于任何编程语言(不仅仅是 Bash 脚本)。要声明变量,请为其指定名称和值(默认情况下该值是字符串)。变量的名称只能包含字母字符或下划线(其他编程语言使用不同的命名约定)。例如,如果您想将路由器的 IP 地址存储在变量中,首先您将创建一个文件 test.txt。 sh(Bash 脚本文件将以 .sh 结尾),在文件中,您将输入以下内容:

让我们写入第一个脚本文件

#!/bin/bash

#Simple program with a variable

ROUTERIP="10.0.0.1"

printf "The router IP address: $ROUTERIP\n"

运行之后发现权限不够 ,需要给文件添加权限

chmod +x test.sh  #给文件添加执行权限

重新执行后发现,脚本文件就可以被执行了 

刚刚构建了第一个 Bash 脚本!假设我们希望该脚本自动运行,然后在系统中的任何位置指定其路径。因此,我们必须将其添加到 sPATH 变量中。在我们的示例中,我们将/opt 添加到 $PATH 变量,以便我们可以将自定义脚本保存在此目录中。首先,打开.使用任何文本编辑器编辑的 .bashrc 文件。
 export PATH=$PATH:/OPT/
 

cp test.sh /opt/    #将文件拷贝到opt目录下

cd /opt #进入opt目录

ls -la | grep "test.sh"    #查看test.sh 文件 

命令的变量

有时,您可能想要执行命令并将其输出保存到变量中。大多数时候,其背后的目标是操纵命令输出的内容。这是一个简单的命令,它执行 ls 命令并使用 grep 命令过滤出包含单词 simple 的文件名。 (别担心,您将在本章接下来的部分中看到更复杂的场景。暂时练习并专注于基础知识。)
#!/bin/bash

LS_CMD=$(ls | grep 'simple')

printf "$LS_CMD\n"

脚本参数

有时,您需要向 Bash 脚本提供参数。您必须用空格分隔每个参数,然后您可以在 Bash 脚本中操作这些参数。让我们创建一个简单的计算器(simpleadd .sh)来添加两个数字:
#!/bin/bash

#这是一个简单的计算机程序,需要你来输入两个数字
#我们将第一个数字存储在NUM1中
NUM1=$1

#将第二个数字存储在NUM2中
NUM2=$2

#将结果保存在 total 变量中
TOTAL=$(($NUM1 + $NUM2))
echo '########################'
printf "%s %d\n" "The total is =" $TOTAL
echo '########################'

您可以在前面的脚本中看到,我们使用$1语法访问第一个参数,使用$2访问第二个参数(您可以添加任意多的参数)。

之前的脚本有一个限制;它只能添加两个数字。如果您想灵活地添加两到五个数字怎么办?在这种情况下,我们可以使用默认参数功能。换句话说,默认情况下,所有参数值都设置为零,一旦脚本提供实际值,我们就会将它们相加:
#!/bin/bash

#这是一个简单的计算机程序,需要你来输入两个数字
#我们将第一个数字存储在NUM1中
NUM1=$1

#将第二个数字存储在NUM2中
NUM2=$2

#将第三个数字存储在NUM2中
NUM3=$3

#将第四个数字存储在NUM2中
NUM4=$4

#将第五个数字存储在NUM2中
NUM5=$5

#将结果保存在 total 变量中
TOTAL=$(($NUM1 + $NUM2+$NUM3 + $NUM4+$NUM5))
echo '########################'
printf "%s %d\n" "The total is =" $TOTAL
echo '########################'

或者

#!/bin/bash
#添加5个数字并且相加
#将第一个变量存储到NUM1中
NUM1=${1:-0}
#将第一个变量存储到NUM2中
NUM2=${2:-0}
#将第一个变量存储到NUM3中
NUM3=${3:-0}
#将第一个变量存储到NUM4中
NUM4=${4:-0}
#将第一个变量存储到NUM5中
NUM5=${5:-0}
#将相加的结果写在 total 变量中
=$(($NUM1 + $NUM2 + $NUM3 + $NUM4 + $NUM5))
echo '########################'
printf "%s %d\n" "The total is =" $TOTAL
echo '########################'
为了理解它是如何工作的,让我们以 NUM1 变量为例(相同的概念适用于五个变量)。我们将告诉它从终端窗口读取第一个参数 {1,如果用户未提供该参数,则将其设置为零,如 :-o} 所示。使用默认变量,我们不限于添加五个数字;从现在开始,我们可以添加任意数量的数字,但最多为五个(在下面的示例中,我们将添加三个数字):
如果您想知道脚本中提供的参数数量,则可以使用 $# 来获取总数。根据前面的示例,$# 将等于 3,因为我们传递了三个参数。
printf "%s %d\n" "参数的总数为 =" $#

用户输入

与 shell 脚本提供的输入进行交互的另一种方法是使用 read 函数。同样,解释这一点的最佳方法是通过示例。我们将要求用户输入他们的名字和姓氏,然后我们将在屏幕上打印全名:

要执行它,我们只需输入脚本名称(我们不需要像以前那样提供任何参数)。输入脚本名称后,系统将提示我们显示上一个脚本中定义的消息:

#!/bin/bash
read -p "请输入你的姓:" FIRSTNAME
read -p "请输入你的名字:" LASTNAME
printf "Your full name is: $FIRSTNAME $LASTNAME\n"
Functions函数

函数是一种将 Bash 脚本组织成逻辑部分的方法,而不是具有无组织的结构(程序员称之为意大利面条代码)。让我们对之前的计算器程序进行重新组织(重构),使其看起来更好。

这个 Bash 脚本分为三个部分: 在第一部分中,我们创建所有全局变量。全局变量可以在您创建的任何函数内访问。例如,我们可以在 add 函数中使用示例中声明的所有 NUM 变量。接下来,我们通过将应用程序划分为逻辑部分来构建功能。 print_custom () 函数将只打印我们提供的任何文本。我们使用¥s1 来访问传递给该函数的参数值(即字符串 CALCULATOR)。最后,我们按顺序调用每个函数(每个函数按其名称)。打印标题,添加数字,最后打印结果。

#!/bin/bash
#一个简单的计算器
 #S将第一个参数存储在numl变量中
NUM1=${1:-0}
NUM2=${2:-0}
NUM3=$(3:-0}
NUM4=${4:-0}
NUM5=${5:-0}

function print_custom(){ 
    echo $1
}

function add(){

#将加法结果存储在 TOTAL变量中

TOTAL=$(($NUM1+$NUM2+$NUM3+$NUM4+$NUM5))
}

function print_total(){

echo
printf "%s %d\n" "结果为  ="$TOTAL

echo_custom "计算器"
add
print_total

条件和循环 

现在您已经了解了Bash脚本编写的基础知识,我们可以介绍更高级的技术。当你用大多数编程语言(如PHP、Python、C、c++、c#等)开发程序时,包括Bash脚本,你会遇到条件(if语句)和循环。

 

 

条件 

if语句采用以下模式:

if [[ 比较 ]] 
then
True, 做某事
else  False, 做别的事

如果你一直注意的话,你就会知道解释这种模式的最好方法就是通过例子。让我们开发一个程序,使用Nmap ping一个主机,我们将根据条件(主机是up或down)显示机器的状态:

#!/bin/bash
#使用Nmap ping主机
### 全局变量 ###
#存储 ip地址
IP_ADDRESS=$1

function ping_host(){

ping_cmd=$(nmap -sn $IP_ADDRESS | grep 'Host is up' | cut -d '(' -f 1)

}

function print_status(){
if [[ -z $ping_cmd ]]
then
echo 'Host is down'
else
echo 'Host is up'
fi
}
ping_host
print_status

如果主机关闭,nmap命令返回一个空字符串文本,如果主机正在响应,则返回值“主机已启动”。(尝试在终端窗口中执行完整的nmap命令,以直观地看到差异。如果是,将$IP_ADDRESs替换为真实的IP地址。)在if条件下,-z选项将检查字符串是否为空;如果是,则打印“主机已关闭”,否则打印“主机已启动”。 

其他条件语句可以比较数字、字符串或文件

循环

可以用两种不同的方式编写循环:使用while循环或使用for循环。大多数编程语言都使用相同的循环模式。因此,如果您了解Bash中的循环是如何工作的,那么同样的概念也适用于Python。让我们从一个接受以下结构的while循环开始:

while [[条件]]
do
do 某物
done

解释循环的最好方法是通过从1到10的计数器。我们将开发一个显示进度条的程序:

#!/bin/bash
#while循环

#Counter

COUNTER=1

#Bar

BAR='##########'

while [[ $COUNTER -lt 11 ]]

do

#从0开始输出
echo -ne "\r${BAR:0:COUNTER}"

#休眠 1秒钟 
sleep 1
#递增计数器

COUNTER=$(( $COUNTER +1 ))
done

请注意,while 循环中的条件 ([[ $COUNTER -lt 11]]) 遵循与 if 条件相同的规则。由于我们希望分数停在 10,因此我们将使用以下数学公式:counter <11。运行时,它将显示进度。为了使这个程序更有趣,让它在进入下一个数字之前休眠一秒钟。另一方面,for循环将采用以下模式:、

#!/bin/bash
#For循环进度条
#Bar
BAR='##########'

for COUNTER in {1..10}
do

#从0索引开始打印进度条
echo -ne "\r${BAR:0:$COUNTER}"

#睡眠1秒钟
sleep 1
done

文件迭代

下面是使用for循环在Bash中读取文本文件的操作

for line in $(文件名)
do
do something
done

在下面的示例中,我们将在名为ips.txt的文件中保存IP地址列表。然后,我们将重用Nmap ping程序(我们之前创建的)来检查每个IP地址是up还是down。最重要的是,我们将检查每个IP地址的DNS名称:

#!/bin/bash
#Ping & get DNS name from a list of IPs saved in a file
#Prompt the user to enter a file name and its path.
read -p "Enter the IP addresses file name / path:" FILE_PATH_NAME
(continued)
function check_host(){
#if not the IP address value is empty
if [[ -n $IP_ADDRESS ]]
then
ping_cmd=$(nmap -sn $IP_ADDRESS| grep 'Host is up' | cut
-d '(' -f 1)
echo '------------------------------------------------'
if [[ -z $ping_cmd ]]
then
printf "$IP_ADDRESS is down\n"
else
printf "$IP_ADDRESS is up\n"
dns_name
fi
fi
}
function dns_name(){
dns_name=$(host $IP_ADDRESS)
printf "$dns_name\n"
}
#Iterate through the IP addresses inside the file
for ip in $(cat $FILE_PATH_NAME)
do
IP_ADDRESS=$ip
check_host
done

如果您仔细阅读了本章,您应该能够理解前面代码中的所有内容。这个程序的唯一不同之处在于,我使用了制表符间距来使脚本看起来更好。前面的例子涵盖了到目前为止我们所做的大部分工作,包括以下内容:

用户输入、声明变量、使用函数、使用if条件、循环迭代、sprint到屏幕

总结

我希望您已经练习了本章中的所有练习,特别是如果您是编程新手的话。上面提到的许多概念将适用于许多编程语言,因此将练习视为学习基础知识的机会。我个人在小而快速的场景中使用Bash脚本。如果您想构建更复杂的应用程序,那么您可以尝试用Python代替。别担心!在本书的最后,您将了解Python,以便您可以处理渗透测试员职业生涯中的任何情况。最后,本章讨论了很多关于Bash脚本的信息。然而,还有比本章更多的信息。在实践中,我使用internet搜索引擎快速查找Bash脚本参考。事实上,你不需要记住本章所学的所有内容。请记住,这本书是一个参考,你可以依靠它来记住在每种情况下使用的语法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

YJlio

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值