—— 导读 ——
近期有很多小伙伴们在公众号留言询问有关Shell脚本的内容。因此我们决定新增一个合集,专门分享Shell脚本编写的相关知识。除此之外我们还会更新一些在工作中常用的脚本和可复用的Shell函数,帮助大家更高效地解决实际问题。本篇主要介绍Shell变量相关,包括变量基础知识、变量使用进阶、位置参数的使用、特殊变量的使用、为变量定义默认值以及变量值截取、变量值替换等。
变量基础知识
- 变量定义
如下为几个简单的变量示例
MY_VAR="Hello, World!"``MAX_COUNT=10``FILE_PATH="/home/user/file.txt"
常见的规范:
-
在 Shell 中定义变量时,变量名和等号之间不能有空格。
-
变量名通常使用大写字母,以便与命令和其他变量区分开来,变量名包含多个单词时使用下划线进行分隔。
-
变量值尽量使用双引号包围起来,以防止值中存在空格或特殊字符引发错误。
-
变量值可以包含其他变量,但是需要使用花括号 {} 来明确变量的边界。
-
变量使用
引用变量时,需要在变量前加上美元符号 $ :
NAME="Shuai"``echo "My name is $NAME"
变量使用进阶
1、变量值中包含变量
基于执行时间写入新的日志文件:
[root@imzcy ~]# cat t1.sh``#!/bin/bash`` ``LOG_PATH="/var/log/mytest"``NOW_TIME="$(date +%Y%m%d_%H%M%S)"``LOG_FILE="${LOG_PATH}/start_${NOW_TIME}.log"`` ``echo "当前日志将写入文件:${LOG_FILE}"``[root@imzcy ~]#
[root@imzcy ~]# sh t1.sh``当前日志将写入文件:/var/log/mytest/start_20240730_020340.log``[root@imzcy ~]#``[root@imzcy ~]# sh t1.sh``当前日志将写入文件:/var/log/mytest/start_20240730_020343.log``[root@imzcy ~]#
2、截取字符串内容同时定义多个变量
使用 eval 和 awk 命令实现,将字符串中空格分隔的多个字段分别赋值给指定变量。
[root@imzcy ~]# cat t2.sh``#!/bin/bash`` ``NOW_LINE="1008858 zhangsan 18"``eval $(echo "$NOW_LINE" |awk '{printf("KEY_ID=%s; KEY_NAME=%s; KEY_AGE=%s",$1,$2,$3)}')`` ``echo "ID:${KEY_ID} ,姓名:${KEY_NAME} , 年龄:${KEY_AGE}"``[root@imzcy ~]#
[root@imzcy ~]# sh t2.sh``ID:1008858 ,姓名:zhangsan , 年龄:18``[root@imzcy ~]#
3、获取用户的输入定义变量
使用 read 命令实现,可以读取定义单个变量或读取定义多个变量(以空格分隔多个值)。
[root@imzcy ~]# cat t3.sh``#!/bin/bash`` ``echo "请输入空格分隔的两个内容:"``read KEY_NAME KEY_AGE`` ``echo "第一个值为:${KEY_NAME},第二个值为:${KEY_AGE}"``[root@imzcy ~]#
[root@imzcy ~]# sh t3.sh``请输入空格分隔的两个内容:``zhangsan 18``第一个值为:zhangsan,第二个值为:18``[root@imzcy ~]#
也可以使用 -p 选项设置输入提示符:
[root@imzcy ~]# cat t3-2.sh``#!/bin/bash`` ``read -p "请输入您的国家: " KEY_COUNTRY``echo "您输入的国家是: ${KEY_COUNTRY}"``[root@imzcy ~]#
[root@imzcy ~]# sh t3-2.sh``请输入您的国家: China``您输入的国家是: China``[root@imzcy ~]#
位置参数的使用
在 Shell 脚本中,你可以使用位置参数来处理用户输入的传参。位置参数是传递给脚本或函数的参数,通常通过 $1, $2, $3 … $9 等等来访问(超过9个的位置参数引用时需要使用花括号围起来,例如使用 ${10} 来获取第10个参数的值)。如果你希望处理任意数量的参数,你还可以使用 $@ 和 $* 来引用所有的参数。另外可以使用 $0 获取脚本的名称,使用 $# 来获取传递给脚本的参数的个数。
[root@imzcy ~]# cat t4.sh``#!/bin/bash`` ``# 打印第一个和第二个参数``echo "第一个参数: $1"``echo "第二个参数: $2"`` ``echo "当前 Shell 脚本名称为:$0 ,你总共输入了 $# 个参数"``[root@imzcy ~]#
[root@imzcy ~]# sh t4.sh arg1 arg2 arg3``第一个参数: arg1``第二个参数: arg2``当前 Shell 脚本名称为:t4.sh ,你总共输入了 3 个参数``[root@imzcy ~]#
在 Shell 脚本中引用所有的参数时,如果 $* 和 $@ 不被双引号包围,它们之间没有任何区别,都将接收到的每个参数视为独立的单元,参数之间以空格分隔。
[root@imzcy ~]# cat t4-2.sh``#!/bin/bash`` ``echo "如下为 \$*"``for i in $* ; do`` ` `echo $i`` ``done`` `` ``echo "如下为 \$@"``for i in $@ ; do`` ` `echo $i`` ``done``[root@imzcy ~]#
[root@imzcy ~]# sh t4-2.sh arg1 arg2 arg3``如下为 $*``arg1``arg2``arg3``如下为 $@``arg1``arg2``arg3``[root@imzcy ~]#
如果被双引号包围起来,区别就显现出来了。 $*会将所有参数视为一个整体(作为一个单一的字符串处理),而 $@ 仍然将每个参数视为独立的单元。这种区别在处理参数时尤为重要。
[root@imzcy ~]# cat t4-3.sh``#!/bin/bash`` ``echo "如下为 \$*"``for i in "$*" ; do`` ` `echo $i`` ``done`` `` ``echo "如下为 \$@"``for i in "$@" ; do`` ` `echo $i`` ``done``[root@imzcy ~]#
[root@imzcy ~]# sh t4-3.sh arg1 arg2 arg3``如下为 $*``arg1 arg2 arg3``如下为 $@``arg1``arg2``arg3``[root@imzcy ~]#
**特殊变量的使用
**
除了上面的位置参数外,在 Shell 脚本中还有一些其他的特殊变量,如下所示。
1、$? 获取上一个命令的退出状态码
值为 0 表示执行成功,非 0 表示执行失败。
[root@imzcy ~]# cat t5-1.sh``#!/bin/bash`` ``echo "$1" |grep hello``echo "grep 命令退出状态码为:$?"``[root@imzcy ~]#
[root@imzcy ~]# sh t5-1.sh``grep 命令退出状态码为:1``[root@imzcy ~]# sh t5-1.sh hello``hello``grep 命令退出状态码为:0``[root@imzcy ~]#
2、$$ 获取当前脚本的进程ID(PID)
[root@imzcy ~]# cat t5-2.sh``#!/bin/bash`` ``echo "当前脚本的进程ID为:$$" >/root/my.pid``sleep 100``[root@imzcy ~]#
[root@imzcy ~]# nohup sh t5-2.sh &
[root@imzcy ~]# cat my.pid``当前脚本的进程ID为:24817``[root@imzcy ~]``[root@imzcy ~]# ps -ef |grep t5-2 |grep -v grep``root 24817 22205 0 03:43 pts/1 00:00:00 sh t5-2.sh``[root@imzcy ~]#
3、$! 获取最后一个后台运行进程的ID(PID)
[root@imzcy ~]# cat t5-3.sh``#!/bin/bash`` ``nohup sh /root/t5-2.sh &``echo "上一个后台运行的进程的PID为:$!"``[root@imzcy ~]#
[root@imzcy ~]# sh t5-3.sh``上一个后台运行的进程的PID为:24881``[root@imzcy ~]#
[root@imzcy ~]# cat my.pid``当前脚本的进程ID为:24881``[root@imzcy ~]#``[root@imzcy ~]# ps -ef |grep t5-2 |grep -v grep``root 24881 1 0 03:47 pts/1 00:00:00 sh /root/t5-2.sh``[root@imzcy ~]#
4、$- 获取当前shell选项
[root@imzcy ~]# cat t5-4.sh``#!/bin/bash`` ``echo $-``[root@imzcy ~]#
[root@imzcy ~]# sh t5-4.sh``hB``[root@imzcy ~]# sh -x t5-4.sh``+ echo hxB``hxB``[root@imzcy ~]#
为变量设置默认值
常用有两种。当变量没有被定义或为空时,一种只返回默认值不会修改变量,另一种则会设置变量为默认值。
1、:-
如果变量 VAR 没有被定义或为空,则返回默认值(VAR本身没有任何改变)。
[root@imzcy ~]# cat t6-1.sh``#!/bin/bash`` ``echo "如下为未定义变量时"``unset VAR``RESULT=${VAR:-"默认值"}``echo "RESULT: $RESULT"``echo "VAR: $VAR"`` `` ``echo "如下为定义变量后"``VAR="Hello"``RESULT=${VAR:-"默认值"}``echo "RESULT: $RESULT"``echo "VAR: $VAR"``[root@imzcy ~]#
[root@imzcy ~]# sh t6-1.sh``如下为未定义变量时``RESULT: 默认值``VAR:``如下为定义变量后``RESULT: Hello``VAR: Hello``[root@imzcy ~]#
2、:=
如果变量 VAR 没有被定义或为空,则设置变量 VAR 的值为默认值,并返回其值(VAR发生改变)。
[root@imzcy ~]# cat t6-2.sh``#!/bin/bash`` ``echo "如下为未定义变量时"``unset VAR``RESULT=${VAR:="默认值"}``echo "RESULT: $RESULT"``echo "VAR: $VAR"`` `` ``echo "如下为定义变量后"``VAR="Hello"``RESULT=${VAR:="默认值"}``echo "RESULT: $RESULT"``echo "VAR: $VAR"``[root@imzcy ~]#
[root@imzcy ~]# sh t6-2.sh``如下为未定义变量时``RESULT: 默认值``VAR: 默认值``如下为定义变量后``RESULT: Hello``VAR: Hello``[root@imzcy ~]#
**变量值截取
**
1、获取变量值的字符个数
[root@imzcy ~]# cat t8-1.sh``#!/bin/bash`` ``VAR="$1"``echo "输入的字符长度为:${#VAR}"``[root@imzcy ~]#
[root@imzcy ~]# sh t8-1.sh``输入的字符长度为:0``[root@imzcy ~]#``[root@imzcy ~]# sh t8-1.sh hello``输入的字符长度为:5``[root@imzcy ~]#
2、截取变量值的指定个数字符
从左边开始
// 其中的 0 表示左边第一个字符开始,5 表示字符的总个数。``[root@imzcy ~]# VAR=https://www.example.com/index.html``[root@imzcy ~]# echo ${VAR:0:5}``https``[root@imzcy ~]#
从左边开始
// 其中的 0-10 表示右边算起第十个字符开始,5 表示字符的个数。``[root@imzcy ~]# VAR=https://www.example.com/index.html``[root@imzcy ~]# echo ${VAR:0-10:5}``index``[root@imzcy ~]#
3、截取指定位置到结束字符
从左到右数第几个字符开始到结束
// 其中的 8 表示左边第9个字符开始,一直到结束。``[root@imzcy ~]# VAR=https://www.example.com/index.html``[root@imzcy ~]# echo ${VAR:8}``www.example.com/index.html``[root@imzcy ~]#
从右到左第几个字符开始到结束
// 表示从右边第四个字符开始,一直到结束。``[root@imzcy ~]# VAR=https://www.example.com/index.html``[root@imzcy ~]# echo ${VAR:0-4}``html``[root@imzcy ~]#
4、截取变量值保留右边字符
一个#符号截取,最短匹配
// 其中 VAR 是变量名,#符号是运算符,*// 表示从左边开始删除第一个 // 号及左边的所有字符,即删除 https://``[root@imzcy ~]# VAR=https://www.example.com/index.html``[root@imzcy ~]# echo ${VAR#*//}``www.example.com/index.html``[root@imzcy ~]#
两个#符号截取,最长匹配
// 其中 ##*/ 表示从左边开始删除最后(最右边)一个 / 号及左边的所有字符,即删除 https://www.example.com/``[root@imzcy ~]# VAR=https://www.example.com/index.html``[root@imzcy ~]# echo ${VAR##*/}``index.html``[root@imzcy ~]#
5、截取变量值保留左边字符
一个%符号截取,最短匹配
// 其中 %/* 表示从右边开始,删除第一个 / 号及右边的字符,即删除 /index.html``[root@imzcy ~]# VAR=https://www.example.com/index.html``[root@imzcy ~]# echo ${VAR%/*}``https://www.example.com``[root@imzcy ~]#
两个%符号截取,最长匹配
// 其中 %%/* 表示从右边开始,删除最后(最左边)一个 / 号及右边的字符,即删除 //www.example.com/index.html``[root@imzcy ~]# VAR=https://www.example.com/index.html``[root@imzcy ~]# echo ${VAR%%/*}``https:``[root@imzcy ~]#
**变量值替换
**
1、字母大写转换为小写
两个 , 符号,如果变量 VAR 中包含大写字母,则这些字母都会被转换为小写字母。
[root@imzcy ~]# VAR="Hello, World!"``[root@imzcy ~]# echo "${VAR,,}"``hello, world!``[root@imzcy ~]#
单个 , 符号,如果变量 VAR 中首个字符为大写字母,则这个字母将被转换为小写字母。
[root@imzcy ~]# VAR="Hello, World!"``[root@imzcy ~]# echo "${VAR,}"``hello, World!``[root@imzcy ~]#
2、字母小写转换为大写
两个 ^ 符号,如果变量 VAR 中包含小写字母,则这些字母都会被转换为大写字母。
[root@imzcy ~]# VAR="Hello, World!"``[root@imzcy ~]# echo "${VAR^^}"``HELLO, WORLD!``[root@imzcy ~]#
单个 ^ 符号,如果变量 VAR 中首个字符为小写字母,则这个字母将被转换为大写字母。
[root@imzcy ~]# VAR="hello, World!"``[root@imzcy ~]# echo "${VAR^}"``Hello, World!``[root@imzcy ~]#
3、字符替换
单个 / 符号,替换第一个匹配的字符
[root@imzcy ~]# VAR="hello,zhangsan. hello lisi"``[root@imzcy ~]# echo ${VAR/hello/nihao}``nihao,zhangsan. hello lisi``[root@imzcy ~]#
两个 / 符号,替换所有匹配的字符
[root@imzcy ~]# VAR="hello,zhangsan. hello lisi"``[root@imzcy ~]# echo ${VAR//hello/nihao}``nihao,zhangsan. nihao lisi``[root@imzcy ~]#
为了帮助大家更好的学习网络安全,我给大家准备了一份网络安全入门/进阶学习资料,里面的内容都是适合零基础小白的笔记和资料,不懂编程也能听懂、看懂这些资料!
因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取
优快云大礼包:《黑客&网络安全入门&进阶学习资源包》免费分享
因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取