# 实战脚本简述
# 流程控制
# if
if [ 条件判断式 ];then
程序
fi
if [ 条件判断式 ]
then
程序
fi
if [ 条件判断式 ]
then
条件成立时,执行的程序
else
条件不成立时,执行的另一个程序
fi
if [ 条件判断式1 ]
then
条件成立时,执行的程序
elif [ 条件判断式2 ]
then
条件成立时,执行的程序
...省略更多条件...
else
条件不成立时,执行的另一个程序
fi
# case
case $变量名 in
"值1")
如果变量的值等于值1,则执行程序1
;;
"值1")
如果变量的值等于值2,则执行程序2
;;
…省略其他分支…
*)
如果变量的值都不是以上的值,则执行此程序
;;
esac
# for
for 变量 in 值1 值2 值3 ...
do
程序
done
for (( 初始值;循环控制条件;变量变化 ))
do
程序
done
# while
while [ 条件判断式 ]
do
程序
done
# until
until [ 条件判断式 ]
do
程序
done
# 特殊控制语句
exit [返回值]
break
continue
# 函数
function 函数名 () {
程序
}
# 工具命令
# cut
# cut [选项] 文件名
常见选项:
-c: 以字符为单位进行分割,截取
-d: 自定义分隔符,默认为制表符\t
-f: 与-d一起使用,提取第几列
[root@xiaoshaozi ~]# echo "zs=123=456=789" | cut -d "=" -f 1,2,4
zs=123=789
# wc
[root@localhost ~]# wc [选项] 文件名
选项:
-l:只统计行数
-w:只统计单词数
-m:只统计字符数
# seq
seq
: 是一个序列(squeue )的缩写,主要用来输出序列化的东西
seq [选项] 尾数 #从到尾数
seq [选项] 首数 尾数 #从首数到尾数
seq [选项] 首数 增量 尾数 #从首数以增量到尾数
以指定增量从首数开始打印数字到尾数。
常用选项:
-f 使用printf 样式的浮点格式
-s 使用指定字符串分隔数字(默认使用:\n)
-w 在列前添加0 使得宽度相同【自动补位】
指定分割符
[root@server1 mnt]# seq -s '#' 5
1#2#3#4#5
[root@server1 mnt]# seq -s ' ' 10
1 2 3 4 5 6 7 8 9 10
[root@server1 mnt]# seq -w 10
01
02
03
04
05
06
07
08
09
10
产生范围数字
产生-2~10内的整数,增量为2:
[root@server1 mnt]# seq -2 2 10
-2
0
2
4
6
8
10
产生98~101之间的整数,并且要求输出数字宽度相同,不足的用0或空格补足:
[root@server1 mnt]# seq -f "%03g" 98 101
098
099
100
101
[root@server1 mnt]# seq -f "%3g" 98 101
98
99
100
101
注意:通过%后添加0替代空格补足空位
# awk
# sed
# column
column对齐字段
常用选项:
-t :表格,默认以空格间隔
-s:需要配合-t使用,指定分隔符
获取的文档版式比较乱
cat tee.txt
10.10.10.161 | SUCCESS | rc=0 | (stdout) 21
10.10.10.33 | SUCCESS | rc=0 | (stdout) 22
10.10.10.1 | SUCCESS | rc=0 | (stdout) 62
排版
cat tee.txt |column -t
10.10.10.161 | SUCCESS | rc=0 | (stdout) 21
10.10.10.33 | SUCCESS | rc=0 | (stdout) 22
10.10.10.1 | SUCCESS | rc=0 | (stdout) 62
sort 多重排序 (opens new window)整理
$ cat tee.txt |column -t |sort -k5r -k1
10.10.10.97 | SUCCESS | rc=0 | (stdout) 7
10.10.10.98 | SUCCESS | rc=0 | (stdout) 7
10.10.10.99 | SUCCESS | rc=0 | (stdout) 7
10.10.10.129 | SUCCESS | rc=0 | (stdout) 65
10.10.10.130 | SUCCESS | rc=0 | (stdout) 65
10.10.10.131 | SUCCESS | rc=0 | (stdout) 65
10.10.10.1 | SUCCESS | rc=0 | (stdout) 62
10.10.10.2 | SUCCESS | rc=0 | (stdout) 62
# expr
正确: 所有操作符的两边,都需要有空格。
[root@localhost scripts]# expr 1 + 1
2
"index string chars"用法示例。
[root@localhost ~]# expr index abcde dec # 在 abcde 中搜索 d 在第几个位置
3
[root@localhost ~]# expr index abcde xdc # 在 abcde 中搜索x没有,在搜索d
3
[root@localhost ~]# expr index abcde 1
0
"substr string pos len"用法示例。
该表达式是从string中取出从pos位置开始长度为len的子字符串。如果pos或len为非正整数时,将返回空字符串。
[root@localhost ~]# expr substr abcde 2 3
bcd
[root@localhost ~]# expr substr abcde 2 4
bcde
[root@localhost ~]# expr substr abcde 2 5
bcde
[root@localhost ~]# expr substr abcde 2 0
[root@localhost ~]# expr substr abcde 2 -1
"length string"用法示例。该表达式是返回string的长度,其中string不允许为空,否则将报错,所以可以用来判断变量是否为空。
[root@xuexi ~]# expr length abcde
5
[root@xuexi ~]# expr length 111
3
[root@localhost scripts]# echo $xxx
[root@xuexi ~]# expr length $xxx
expr: syntax error
"+ token"用法示例。
expr中有些符号和关键字有特殊意义,如"match"、"index"、"length",如果要让其成为字符,使用该表达式将任意token强制解析为普通字符串。格式:expr index 特殊关键字
[root@localhost scripts]# expr index index d
expr: 语法错误
[root@localhost scripts]# expr index length g
expr: 语法错误
[root@localhost scripts]# expr index + length g
4
对值为关键字的变量来说,则无所谓。
[root@localhost scripts]# len=lenght
[root@localhost scripts]# expr index $len g
4
"string : REGEX"字符串匹配示例。要输出匹配到的字符串结果,需要使用",否则返回的将是匹配到的字符串数量。
[root@localhost ~]#expr abcde : 'ab\(.*\)' # 'ab\(.*\)' ab代表不匹配 .代表匹配一个 .*匹配所有 \是为了转移字符,转移( 和)
cde
[root@localhost ~]# expr abcde : 'ab\(.\)'
c
[root@localhost ~]# expr abcde : 'ab\(..\)'
cd
[root@localhost ~]# expr abcde : 'ab.*' # 不写() 代表反馈匹配上的数字各个数
5
[root@localhost ~]# expr abcde : 'ab.'
3
[root@localhost ~]# expr abcde : '.*cd*'
4
[root@localhost ~]# cat abc
abcdwe
[root@localhost ~]# expr `cat abc` : 'ab\(..\)'
cd
# grep
[root@localhost ~]# grep [选项] '关键字' 文件名
选项:
-i: 忽略大小写
-n: 输出行号
-v: 反向查找
^,$,?,*,[a-z],[x]正则符号
^$ 匹配空行
^[[:space:]]*# 匹配空行,匹配零个或多个空白字符,这包括空格、制表符和其他类型的空白字符
[root@localhost ~]# grep -n 'root' passwd
[root@localhost ~]# grep -ni 'root' passwd
[root@localhost ~]# grep '^root' passwd
[root@localhost ~]# grep 'root$' passwd
# grep -i root passwd 忽略大小写匹配包含root的行
# grep -w ftp passwd 精确匹配ftp单词
# grep -w hello passwd 精确匹配hello单词;自己添加包含hello的行到文件
# grep -wo ftp passwd 打印匹配到的关键字ftp
# grep -n root passwd 打印匹配到root关键字的行好
# grep -ni root passwd 忽略大小写匹配统计包含关键字root的行
# grep -nic root passwd 忽略大小写匹配统计包含关键字root的行数
# grep -i ^root passwd 忽略大小写匹配以root开头的行
# grep bash$ passwd 匹配以bash结尾的行
# grep -n ^$ passwd 匹配空行并打印行号
# grep ^# /etc/vsftpd/vsftpd.conf 匹配以#号开头的行
# grep -v ^# /etc/vsftpd/vsftpd.conf 匹配不以#号开头的行
# grep -A 5 mail passwd 匹配包含mail关键字及其后5行
# grep -B 5 mail passwd 匹配包含mail关键字及其前5行
# grep -C 5 mail passwd 匹配包含mail关键字及其前后5行
# sort
[root@localhost ~]# sort [选项] 文件名
常用选项:
-u :去除重复行
-r :降序排列,默认是升序
-n :以数字排序,默认是按字符排序
-t :分隔符
-k :第N列
# 符号
# 输出重定向
命令 &>/dev/null
命令 >/dev/null 2>&1
# 多命令
; 同时执行
&& $?=0,则命令2执行
$?≠0,命令2不执行
|| $?≠0,则命令2执行
$?=0,命令2不执行
[root@xiaoshaozi ~]# ls && echo yes || echo no
[root@xiaoshaozi ~]# [ -n "$aa" -a "$aa" -gt 23 ] && echo yes || echo no
# 其他
'' 单引号
单引号中的特殊符号没有特殊意义:如 $、`
"" 双引号
特殊符号没有含义,$、`、\ 例外
`` 反引号
``==>推荐使用==>$() bash中会先执行其中的命令
$() 引用系统命令
${} 变量引用
变量引用更加强大,可对变量进行字符串截取
$变量名 ==> ${变量名}
[] 条件判断
\$ 转移符:输出 $
(命令;命令) 在子shell中执行
{ 命令;命令; } 在当前shell中执行
# 变量
定义、引用
$变量名 或 ${变量名}
[root@xiaoshaozi ~]# test=123
[root@xiaoshaozi ~]# test="$test"456
[root@xiaoshaozi ~]# test=${test}789
`` == $(命令)
[root@xiaoshaozi ~]# test=`date`
[root@xiaoshaozi ~]# test=$(date)
unset 变量名 变量删除
[root@xiaoshaozi ~]# set [选项]
选项:
-u: 如果设定此选项,调用未声明变量时会报错(默认无任何提示)
-x: 如果设定此选项,在命令执行之前,会吧命令先输出一次
set -u 更为常用
[root@xiaoshaozi ~]# set
#直接使用set命令,会查询系统中所有的变量,包含用户自定义变量和环境变量
[root@xiaoshaozi ~]# env
# env看不到用户自定义变量,可以看到另一部分环境变量
local 定义局部变量
function Hello(){
local text="Hello World!!!" #局部变量
echo $text
}
shell脚本中定义的变量是global的,其作用域从被定义的地方开始,到shell结束或被显示删除的地方为止。
如果同名,Shell函数定义的local变量会屏蔽脚本定义的global变量。
# 环境变量
#使用export声明的变量即是环境变量
方式一:
export 变量名=变量值
[root@xiaoshaozi ~]# export ZS_AGE="18"
方式二:
[root@xiaoshaozi ~]# ZS_AGE="18"
[root@xiaoshaozi ~]# export ZS_AGE
[root@xiaoshaozi ~]# set
#直接使用set命令,会查询系统中所有的变量,包含用户自定义变量和环境变量
[root@xiaoshaozi ~]# env
# env看不到用户自定义变量,可以看到另一部分环境变量
# 位置参数变量
$n 第n位参数,0-9以内用 $n,10以上的用 ${10}
$* 把所有参数看成一个整体
$@ 代办所有参数,每个参数区分对待
$# 所有参数个数
# 预定义变量
$? 最后一次执行命令的返回状态
$$ 当前进程的进程号(PID)
$! 后台运行的最后一个进程的进程号(PID)
其中$?最为常用
# 接收键盘
[root@localhost ~]# read [选项] [变量名]
选项:
-p “提示信息”: 在等待read输入时,输出提示信息
-t 秒数: read命令会一直等待用户输入,使用此选项可以指定等待时间
-n 字符数: read命令只接受指定的字符数,就会执行
-s: 隐藏输入的数据,适用于机密信息的输入
变量名:
- 变量名可以自定义,如果不指定变量名,会把输入保存入默认变量REPLY
- 如果只提供了一个变量名,则整个输入行赋予该变量
- 如果提供了一个以上的变量名,则输入行分为若干字,一个接一个地赋予各个变量,
而命令行上如果提供了一个以上的变量名,则输入行分为若干字,一个接一个地赋予各个变量,而命令行上
# 条件判断
文件类型
格式一:
[root@xiaoshaozi ~]# test [选项] 文件
格式二:最常用格式
[root@xiaoshaozi ~]# [ 选项 文件 ]
常用选项:
-e 判断文件在不在
-f 在且是普通文件
-L 在且是链接文件
-d 判断是否是目录
-s 文件是否存在,或文件是否非空
文件权限
常用选项:
-r 读
-w 写
-x 执行
两个整数比较
常用选项:
num1 -eq num2 num1 == num2
num1 -ne num2 num1 != num2
num1 -gt num2 num1 > num2
num1 -lt num2 num1 < num2
num1 -ge num2 num1 >= num2
num1 -le num2 num1 <= num2
字符串比较
常用选项:
-z str isBlank?
-n str isNotBlank?
str1 == str2 str1==str2
str1 != str2 str1!=str2
多重条件
-a 与
-o 或
! 非
[root@xiaoshaozi ~]# [ -n "$aa" -a "$aa" -gt 23 ] && echo yes || echo no
yes
# $[ ] 、${ }、$( )、[ ]、[[ ]]、(())区别
$()
命令替换,等价于````` ```出现嵌套时只能使用$()
$( )
finish_time=$(date)
$[ ]
运算操作符,等价于$(( ))
xjh@ubuntu:~/iot/tmp$ echo $[3*5]
15
xjh@ubuntu:~/iot/tmp$ echo $[(3+4)*5]
35
xjh@ubuntu:~/iot/tmp$
${ }
变量使用操作符,有很多丰富的功能,简单引用$变量名
[ ]
test测试简写形式
[[ ]]
test升级版
(())
())是一个数学计算命令,用于对整数进行数学运算,比如((a=10+66))。
具体见博客数学计算命令(expr、(())、bc、declare等) (opens new window)中关于(())的介绍。
# 其他
# sh
sh
shell命令解释器
bash [options] [file]
选项:
-c string:命令从-c后的字符串读取。
-i:实现脚本交互。
-n:进行shell脚本的语法检查。
-x:实现shell脚本逐条语句的跟踪。
常用形式:sh -xc "ls"
[root@AY1307311912260196fcZ satools]# sh -x check_ssh_login.sh
+ DEFINE=30
+ cat /var/log/secure
+ awk '/Failed/ {++ip[$(NF-3)]} END {for (i in ip) print i"="ip[i]}'
++ cat /root/satools/black.txt
+ for i in '`cat /root/satools/black.txt`'
++ echo 121.42.0.16=1427
++ awk -F= '{print $1}'
+ IP=121.42.0.16
++ echo 121.42.0.16=1427
++ awk -F= '{print $2}'
+ NUM=1427
+ '[' 1427 -gt 30 ']'
+ grep 121.42.0.16 /etc/hosts.deny
+ '[' 1 -gt 0 ']'
+ echo sshd:121.42.0.16
+ echo vsftpd:121.42.0.16
+ for i in '`cat /root/satools/black.txt`'
++ echo 121.42.0.72=276
++ awk -F= '{print $1}'
+ IP=121.42.0.72
++ awk -F= '{print $2}'
++ echo 121.42.0.72=276
+ NUM=276
+ '[' 276 -gt 30 ']'
+ grep 121.42.0.72 /etc/hosts.deny
+ '[' 1 -gt 0 ']'
+ echo sshd:121.42.0.72
+ echo vsftpd:121.42.0.72
# 变量
# 数组
在Linux中,可以使用以下方式定义和使用数组:
使用括号和空格将数组元素括起来,每个元素之间用空格分隔。例如:
array=("apple" "banana" "orange")
使用索引访问数组元素,索引从0开始。例如:
echo ${array[0]} # 输出:apple
使用
*
或@
可以获取数组中的所有元素。例如:echo ${array[*]} # 输出:apple banana orange
使用
#
可以获取数组的长度。例如:echo ${#array[@]} # 输出:3
使用
+=
可以向数组中添加元素。例如:array+=("grape") echo ${array[*]} # 输出:apple banana orange grape
使用
unset
可以删除数组中的元素。例如:unset array[1] echo ${array[*]} # 输出:apple orange grape
使用循环遍历数组中的元素。例如:
for item in ${array[*]}; do echo $item done
循环来遍历数组,并获取每个元素的键和值
#!/bin/bash # 定义一个数组 my_array=( "key1=value1" "key2=value2" "key3=value3" ) # 循环遍历数组 for item in "${my_array[@]}" do # 使用IFS(内部字段分隔符)将键和值分割开 IFS='=' read -ra array <<< "$item" key="${array[0]}" value="${array[1]}" # 输出键和值 echo "Key: $key, Value: $value" done
循环来遍历数组,并获取每个元素的索引和值。
#!/bin/bash # 定义一个数组 my_array=("value1" "value2" "value3") # 获取数组长度 length=${#my_array[@]} # 循环遍历数组 for ((i=0; i<$length; i++)) do # 获取索引和值 index=$i value=${my_array[$i]} # 输出索引和值 echo "Index: $index, Value: $value" done 在上述示例中,我们首先定义了一个数组my_array。然后,使用length变量获取数组的长度。接下来,使用for循环遍历数组,并在循环体中获取每个元素的索引和值。最后,我们输出索引和值。 请注意,上述示例中的数组索引从0开始计数。如果你希望从1开始计数,可以在输出索引时将$i替换为$((i+1))。
使用read
命令结合循环结构来遍历以英文逗号分割的字符串
#!/bin/bash
# 定义一个包含逗号分割值的字符串
str="apple,banana,orange,grape"
# 使用IFS(内部字段分隔符)将字符串按逗号分割成数组
IFS=',' read -ra arr <<< "$str"
# 循环遍历数组中的每个值
for item in "${arr[@]}"; do
echo "$item"
done
去除数组中的重复元素
#!/bin/bash
# 定义一个包含重复元素的数组
arr=("apple" "banana" "orange" "apple" "grape" "banana")
# 使用sort和uniq命令去除重复元素
sorted_arr=($(printf "%s\n" "${arr[@]}" | sort | uniq))
# 打印去重后的数组
echo "${sorted_arr[@]}"
#!/bin/bash
# 定义一个包含重复元素的数组
arr=("apple" "banana" "orange" "apple" "grape" "banana")
# 声明关联数组
declare -A unique_arr
# 遍历原始数组,将每个元素作为关联数组的键,如果键不存在,则将其值设置为1,否则将其值递增1
for item in "${arr[@]}"; do
unique_arr["$item"]=1
done
# 打印去重后的数组(关联数组的键即为去重后的元素)
echo "${!unique_arr[@]}"
数组拷贝
在操作数组前拷贝一份数组是一种常见的做法,可以避免直接修改原始数组,从而避免循环过程中出现异常。你可以使用以下代码来复制一个数组:
# 原始数组
original_array=("element1" "element2" "element3")
# 复制数组
copied_array=("${original_array[@]}")
# 在复制的数组上进行操作
for element in "${copied_array[@]}"; do
echo $element
done
关联数组允许你将键与值相关联,类似于Map数据结构。
要在Shell中使用关联数组,首先需要声明一个关联数组变量。以下是一个示例:
declare -A map_array
接下来,你可以通过键来添加或修改关联数组中的值。以下是一个示例:
map_array["key1"]="value1" map_array["key2"]="value2"
要获取关联数组中的值,可以使用键来索引关联数组。以下是一个示例:
value1="${map_array["key1"]}" value2="${map_array["key2"]}"
要删除关联数组中的键值对,可以使用
unset
命令。以下是一个示例:bashunset "map_array["key1"]"
要遍历关联数组中的所有键值对,可以使用循环结构。以下是一个示例:
for key in "${!map_array[@]}"; do echo "Key: $key, Value: ${map_array[$key]}" done
以上就是在Shell中使用关联数组作为Map数据结构的基本用法。通过使用关联数组,你可以在Shell中实现类似Map数据结构的操作。
shell判断变量未赋值和变量为空字符
- 判断变量是否未赋值:
if [ -z "${variable+x}" ]; then echo "变量未赋值" else echo "变量已赋值" fi
上述代码中,
${variable+x}
表示如果变量variable
被赋值,则返回x
,否则返回空字符串。通过使用-z
选项,我们可以判断空字符串是否为真,从而判断变量是否未赋值。
- 判断变量是否为空字符串:
if [ -z "$variable" ]; then echo "变量为空字符串" else echo "变量不为空字符串" fi
上述代码中,
-z
选项用于判断变量是否为空字符串。如果变量为空字符串,则返回真,否则返回假。
# 数组合并
# 定义两个数组
array1=("元素1" "元素2" "元素3")
array2=("元素4" "元素5" "元素6")
# 合并数组
array3=("${array1[@]}" "${array2[@]}")
# 打印合并后的数组
echo "${array3[@]}"
//元素1 元素2 元素3 元素4 元素5 元素6
# 定义两个数组
array1=("元素1" "元素2" "元素3")
array2=("元素4" "元素5" "元素6")
# 合并数组并修改原始数组
array1=("${array1[@]}" "${array2[@]}")
# 打印合并后的数组
echo "${array1[@]}"
//元素1 元素2 元素3 元素4 元素5 元素6
# 常用代码段
# 当前脚本文件目录
$(cd $(dirname $0);pwd)
#!/bin/bash
# 获取脚本所在路径
script_path=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
echo "脚本所在路径:$script_path"
# shell调用另一个脚本中的方法
- 直接调用:
如果你知道另一个脚本中的函数名称,你可以直接在当前的脚本中调用它。
例如,假设你有两个脚本:script1.sh
和 script2.sh
。在 script2.sh
中,有一个名为 myFunction
的函数。
# script2.sh
myFunction() {
echo "Hello from myFunction in script2.sh"
}
你可以在 script1.sh
中直接调用这个函数:
# script1.sh
source script2.sh # 导入script2.sh中的函数和变量等
myFunction # 调用script2.sh中的函数
- 使用源命令 (source):
source
命令用于读取并执行指定脚本中的命令。这允许你在当前的shell环境中执行脚本,这意味着脚本中定义的任何函数或变量都将在当前环境中可用。
例如:
source /path/to/script2.sh # 使用source命令导入script2.sh中的函数和变量等
- 使用点号 (.):
点号也可以用来执行脚本,与 source
命令类似,但它不会创建新的子shell。这意味着脚本中定义的任何函数或变量都将在当前环境中可用。
例如:
. /path/to/script2.sh # 使用点号执行script2.sh中的函数和变量等
- 使用bash的
-c
选项:
如果你只想执行脚本中的一行命令,可以使用 -c
选项:
bash -c "source /path/to/script2.sh" # 导入script2.sh中的函数和变量等,但不会在当前环境中使用它们,因为它们是在新的子shell中定义的。
- 注意点:
- 当使用
source
或点号时,脚本中的任何变量或函数都将在当前shell环境中定义。如果你不想改变当前的环境,使用子shell可能是更好的选择。你可以使用bash -c "command"
的形式来在子shell中执行命令。