宅男做网站,刚做的单页网站怎么预览,网站升级维护需要多久,网站建设了解大家好#xff0c;这里是 Lucifer三思而后行#xff0c;专注于提升数据库运维效率。 文章目录 一篇文章让你彻底掌握 Shell简介什么是 shell什么是 shell 脚本Shell 环境指定脚本解释器 模式交互模式非交互模式 基本语法解释器注释echoprintfprintf 的转义符 变量变量命名原则… 大家好这里是 Lucifer三思而后行专注于提升数据库运维效率。 文章目录 一篇文章让你彻底掌握 Shell简介什么是 shell什么是 shell 脚本Shell 环境指定脚本解释器 模式交互模式非交互模式 基本语法解释器注释echoprintfprintf 的转义符 变量变量命名原则声明变量只读变量删除变量变量类型 字符串单引号和双引号拼接字符串获取字符串长度截取子字符串 查找子字符串数组创建数组访问数组元素访问数组的单个元素访问数组的所有元素访问数组的部分元素 访问数组长度向数组中添加元素从数组中删除元素 运算符算术运算符关系运算符布尔运算符逻辑运算符字符串运算符文件测试运算符 控制语句条件语句ifcase 循环语句for 循环while 循环until 循环select 循环break 和 continue 函数位置参数函数处理参数 Shell 扩展大括号扩展命令置换算数扩展单引号和双引号 流和重定向输入、输出流重定向/dev/null 文件 Debug往期精彩文章 一篇文章让你彻底掌握 Shell Bash 是 Linux 标准默认的 shell 解释器可以说 bash 是 shell 编程的基础。 本文主要介绍 bash 的语法对于 Linux 指令不做任何介绍。 ███████╗██╗ ██╗███████╗██╗ ██╗
██╔════╝██║ ██║██╔════╝██║ ██║
███████╗███████║█████╗ ██║ ██║
╚════██║██╔══██║██╔══╝ ██║ ██║
███████║██║ ██║███████╗███████╗███████╗
╚══════╝╚═╝ ╚═╝╚══════╝╚══════╝╚══════╝简介
什么是 shell
Shell 是一个用 C 语言编写的程序它是用户使用 Linux 的桥梁。Shell 既是一种命令语言又是一种程序设计语言。Shell 是指一种应用程序这个应用程序提供了一个界面用户通过这个界面访问 Linux 内核的服务。
Ken Thompson 的 sh 是第一种 Unix ShellWindows Explorer 是一个典型的图形界面 Shell。
什么是 shell 脚本
Shell 脚本shell script是一种为 shell 编写的脚本程序一般文件后缀为 .sh。
业界所说的 shell 通常都是指 shell 脚本但 shell 和 shell script 是两个不同的概念。
Shell 环境
Shell 编程跟 java、php 编程一样只要有一个能编写代码的文本编辑器和一个能解释执行的脚本解释器就可以了。
Shell 的解释器种类众多常见的有
sh - 即 Bourne Shell。sh 是 Unix 标准默认的 shell。bash - 即 Bourne Again Shell。bash 是 Linux 标准默认的 shell。fish - 智能和用户友好的命令行 shell。xiki - 使 shell 控制台更友好更强大。zsh - 功能强大的 shell 与脚本语言。
指定脚本解释器
在 shell 脚本#! 告诉系统其后路径所指定的程序即是解释此脚本文件的 Shell 解释器。#! 被称作 shebang也称为 Hashbang 。
所以你应该会在 shell 中见到诸如以下的注释
指定 sh 解释器
#!/bin/sh指定 bash 解释器
#!/bin/bash注意 上面的指定解释器的方式是比较常见的但有时候你可能也会看到下面的方式
#!/usr/bin/env bash这样做的好处是系统会自动在 PATH 环境变量中查找你指定的程序本例中的 bash。相比第一种写法你应该尽量用这种写法因为程序的路径是不确定的。这样写还有一个好处操作系统的 PATH 变量有可能被配置为指向程序的另一个版本。比如安装完新版本的 bash我们可能将其路径添加到 PATH 中来“隐藏”老版本。如果直接用 #!/bin/bash那么系统会选择老版本的 bash 来执行脚本如果用 #!/usr/bin/env bash则会使用新版本。
模式
shell 有交互和非交互两种模式。
交互模式 简单来说你可以将 shell 的交互模式理解为执行命令行。 看到形如下面的东西说明 shell 处于交互模式下
userhost:~$接着便可以输入一系列 Linux 命令比如 lsgrepcdmkdirrm 等等。
非交互模式
简单来说你可以将 shell 的非交互模式理解为执行 shell 脚本。
在非交互模式下shell 从文件或者管道中读取命令并执行。
当 shell 解释器执行完文件中的最后一个命令shell 进程终止并回到父进程。
可以使用下面的命令让 shell 以非交互模式运行
sh /path/to/script.sh
bash /path/to/script.sh
source /path/to/script.sh
./path/to/script.sh上面的例子中script.sh 是一个包含 shell 解释器可以识别并执行的命令的普通文本文件sh 和 bash 是 shell 解释器程序。你可以使用任何喜欢的编辑器创建 script.shvimnanoSublime Text, Atom 等等。
其中source /path/to/script.sh 和 ./path/to/script.sh 是等价的。
除此之外你还可以通过 chmod 命令给文件添加可执行的权限来直接执行脚本文件
chmod x /path/to/script.sh #使脚本具有执行权限
/path/to/test.sh这种方式要求脚本文件的第一行必须指明运行该脚本的程序比如 “示例源码”
#!/usr/bin/env bash
echo Hello, world!上面的例子中我们使用了一个很有用的命令 echo 来输出字符串到屏幕上。
基本语法
解释器
前面虽然两次提到了 #! 但是本着重要的事情说三遍的精神这里再强调一遍
在 shell 脚本#! 告诉系统其后路径所指定的程序即是解释此脚本文件的 Shell 解释器。#! 被称作 shebang也称为 Hashbang 。
#! 决定了脚本可以像一个独立的可执行文件一样执行而不用在终端之前输入 sh, bash, python, php 等。
# 以下两种方式都可以指定 shell 解释器为 bash第二种方式更好
#!/bin/bash
#!/usr/bin/env bash注释
注释可以说明你的代码是什么作用以及为什么这样写。
shell 语法中注释是特殊的语句会被 shell 解释器忽略。
单行注释 - 以 # 开头到行尾结束。多行注释 - 以 :EOF 开头到 EOF 结束。 “示例源码”
#--------------------------------------------
# shell 注释示例
# authorzp
#--------------------------------------------# echo 这是单行注释########## 这是分割线 ##########:EOF
echo 这是多行注释
echo 这是多行注释
echo 这是多行注释
EOFecho
echo 用于字符串的输出。
输出普通字符串
echo hello, world
# Output: hello, world输出含变量的字符串
echo hello, \zp\
# Output: hello, zp输出含变量的字符串
namezp
echo hello, \${name}\
# Output: hello, zp输出含换行符的字符串
# 输出含换行符的字符串
echo YES\nNO
# Output: YES\nNOecho -e YES\nNO # -e 开启转义
# Output:
# YES
# NO输出含不换行符的字符串
echo YES
echo NO
# Output:
# YES
# NOecho -e YES\c # -e 开启转义 \c 不换行
echo NO
# Output:
# YESNO输出重定向至文件
echo test test.txt输出执行结果
echo pwd
# Output:(当前目录路径)“示例源码”
#!/usr/bin/env bash# 输出普通字符串
echo hello, world
# Output: hello, world# 输出含变量的字符串
echo hello, \zp\
# Output: hello, zp# 输出含变量的字符串
namezp
echo hello, \${name}\
# Output: hello, zp# 输出含换行符的字符串
echo YES\nNO
# Output: YES\nNO
echo -e YES\nNO # -e 开启转义
# Output:
# YES
# NO# 输出含不换行符的字符串
echo YES
echo NO
# Output:
# YES
# NOecho -e YES\c # -e 开启转义 \c 不换行
echo NO
# Output:
# YESNO# 输出内容定向至文件
echo test test.txt# 输出执行结果
echo pwd
# Output:(当前目录路径)printf
printf 用于格式化输出字符串。
默认printf 不会像 echo 一样自动添加换行符如果需要换行可以手动添加 \n。 “示例源码”
# 单引号
printf %d %s\n 1 abc
# Output:1 abc# 双引号
printf %d %s\n 1 abc
# Output:1 abc# 无引号
printf %s abcdef
# Output: abcdef(并不会换行)# 格式只指定了一个参数但多出的参数仍然会按照该格式输出
printf %s\n abc def
# Output:
# abc
# defprintf %s %s %s\n a b c d e f g h i j
# Output:
# a b c
# d e f
# g h i
# j# 如果没有参数那么 %s 用 NULL 代替%d 用 0 代替
printf %s and %d \n
# Output:
# and 0# 格式化输出
printf %-10s %-8s %-4s\n 姓名 性别 体重kg
printf %-10s %-8s %-4.2f\n 郭靖 男 66.1234
printf %-10s %-8s %-4.2f\n 杨过 男 48.6543
printf %-10s %-8s %-4.2f\n 郭芙 女 47.9876
# Output:
# 姓名 性别 体重kg
# 郭靖 男 66.12
# 杨过 男 48.65
# 郭芙 女 47.99printf 的转义符
序列说明\a警告字符通常为 ASCII 的 BEL 字符\b后退\c抑制不显示输出结果中任何结尾的换行字符只在%b 格式指示符控制下的参数字符串中有效而且任何留在参数里的字符、任何接下来的参数以及任何留在格式字符串中的字符都被忽略\f换页formfeed\n换行\r回车Carriage return\t水平制表符\v垂直制表符\\一个字面上的反斜杠字符\ddd表示 1 到 3 位数八进制值的字符。仅在格式字符串中有效\0ddd表示 1 到 3 位的八进制值字符
变量
跟许多程序设计语言一样你可以在 bash 中创建变量。
Bash 中没有数据类型bash 中的变量可以保存一个数字、一个字符、一个字符串等等。同时无需提前声明变量给变量赋值会直接创建变量。
变量命名原则
命名只能使用英文字母数字和下划线首个字符不能以数字开头。中间不能有空格可以使用下划线_。不能使用标点符号。不能使用 bash 里的关键字可用 help 命令查看保留关键字。
声明变量
访问变量的语法形式为${var} 和 $var 。
变量名外面的花括号是可选的加不加都行加花括号是为了帮助解释器识别变量的边界所以推荐加花括号。
wordhello
echo ${word}
# Output: hello只读变量
使用 readonly 命令可以将变量定义为只读变量只读变量的值不能被改变。
rwordhello
echo ${rword}
readonly rword
# rwordbye # 如果放开注释执行时会报错删除变量
使用 unset 命令可以删除变量。变量被删除后不能再次使用。unset 命令不能删除只读变量。
dwordhello # 声明变量
echo ${dword} # 输出变量值
# Output: hellounset dword # 删除变量
echo ${dword}
# Output: 空变量类型
局部变量 - 局部变量是仅在某个脚本内部有效的变量。它们不能被其他的程序和脚本访问。环境变量 - 环境变量是对当前 shell 会话内所有的程序或脚本都可见的变量。创建它们跟创建局部变量类似但使用的是 export 关键字shell 脚本也可以定义环境变量。
常见的环境变量
变量描述$HOME当前用户的用户目录$PATH用分号分隔的目录列表shell 会到这些目录中查找命令$PWD当前工作目录$RANDOM0 到 32767 之间的整数$UID数值类型当前用户的用户 ID$PS1主要系统输入提示符$PS2次要系统输入提示符
这里 有一张更全面的 Bash 环境变量列表。 “示例源码”
#!/usr/bin/env bash################### 声明变量 ###################
nameworld
echo hello ${name}
# Output: hello world################### 输出变量 ###################
folder$(pwd)
echo current path: ${folder}################### 只读变量 ###################
rwordhello
echo ${rword}
# Output: hello
readonly rword
# rwordbye # 如果放开注释执行时会报错################### 删除变量 ###################
dwordhello # 声明变量
echo ${dword} # 输出变量值
# Output: hellounset dword # 删除变量
echo ${dword}
# Output: 空################### 系统变量 ###################
echo UID:$UID
echo LOGNAME:$LOGNAME
echo User:$USER
echo HOME:$HOME
echo PATH:$PATH
echo HOSTNAME:$HOSTNAME
echo SHELL:$SHELL
echo LANG:$LANG################### 自定义变量 ###################
days10
useradmin
echo $user logged in $days days age
days5
userroot
echo $user logged in $days days age
# Output:
# admin logged in 10 days age
# root logged in 5 days age################### 从变量读取列表 ###################
colorsRed Yellow Blue
colors$colors White Blackfor color in $colors
doecho $color
done字符串
单引号和双引号
shell 字符串可以用单引号 ‘’也可以用双引号 “”也可以不用引号。
单引号的特点 - 单引号里不识别变量 - 单引号里不能出现单独的单引号使用转义符也不行但可成对出现作为字符串拼接使用。双引号的特点 - 双引号里识别变量 - 双引号里可以出现转义字符
综上推荐使用双引号。
拼接字符串
# 使用单引号拼接
name1white
str1hello, ${name1}
str2hello, ${name1}
echo ${str1}_${str2}
# Output:
# hello, white_hello, ${name1}# 使用双引号拼接
name2black
str3hello, ${name2}
str4hello, ${name2}
echo ${str3}_${str4}
# Output:
# hello, black_hello, black获取字符串长度
text12345
echo ${#text}
# Output:
# 5截取子字符串
text12345
echo ${text:2:2}
# Output:
# 34从第 3 个字符开始截取 2 个字符。
查找子字符串
#!/usr/bin/env bashtexthello
echo expr index ${text} ll# Execute: ./str-demo5.sh
# Output:
# 3查找 ll 子字符在 hello 字符串中的起始位置。 “示例源码”
#!/usr/bin/env bash################### 使用单引号拼接字符串 ###################
name1white
str1hello, ${name1}
str2hello, ${name1}
echo ${str1}_${str2}
# Output:
# hello, white_hello, ${name1}################### 使用双引号拼接字符串 ###################
name2black
str3hello, ${name2}
str4hello, ${name2}
echo ${str3}_${str4}
# Output:
# hello, black_hello, black################### 获取字符串长度 ###################
text12345
echo ${text} length is: ${#text}
# Output:
# 12345 length is: 5# 获取子字符串
text12345
echo ${text:2:2}
# Output:
# 34################### 查找子字符串 ###################
texthello
echo expr index ${text} ll
# Output:
# 3################### 判断字符串中是否包含子字符串 ###################
result$(echo ${str} | grep feature/)
if [[ $result ! ]]; thenecho feature/ 是 ${str} 的子字符串
elseecho feature/ 不是 ${str} 的子字符串
fi################### 截取关键字左边内容 ###################
full_branchfeature/1.0.0
branchecho ${full_branch#feature/}
echo branch is ${branch}################### 截取关键字右边内容 ###################
full_version0.0.1-SNAPSHOT
versionecho ${full_version%-SNAPSHOT}
echo version is ${version}################### 字符串分割成数组 ###################
str0.0.0.1
OLD_IFS$IFS
IFS.
array( ${str} )
IFS$OLD_IFS
size${#array[*]}
lastIndexexpr ${size} - 1
echo 数组长度${size}
echo 最后一个数组元素${array[${lastIndex}]}
for item in ${array[]}
doecho $item
done################### 判断字符串是否为空 ###################
#-n 判断长度是否非零
#-z 判断长度是否为零strtesting
str2
if [[ -n $str ]]
thenecho The string $str is not empty
elseecho The string $str is empty
fiif [[ -n $str2 ]]
thenecho The string $str2 is not empty
elseecho The string $str2 is empty
fi# Output:
# The string testing is not empty
# The string is empty################### 字符串比较 ###################
strhello
str2world
if [[ $str hello ]]; thenecho str equals hello
elseecho str not equals hello
fiif [[ $str2 hello ]]; thenecho str2 equals hello
elseecho str2 not equals hello
fi数组
bash 只支持一维数组。
数组下标从 0 开始下标可以是整数或算术表达式其值应大于或等于 0。
创建数组
# 创建数组的不同方式
nums([2]2 [0]0 [1]1)
colors(red yellow dark blue)访问数组元素
访问数组的单个元素
echo ${nums[1]}
# Output: 1访问数组的所有元素
echo ${colors[*]}
# Output: red yellow dark blueecho ${colors[]}
# Output: red yellow dark blue上面两行有很重要也很微妙的区别
为了将数组中每个元素单独一行输出我们用 printf 命令
printf %s\n ${colors[*]}
# Output:
# red
# yellow
# dark
# blue为什么 dark 和 blue 各占了一行尝试用引号包起来
printf %s\n ${colors[*]}
# Output:
# red yellow dark blue现在所有的元素都在一行输出 —— 这不是我们想要的让我们试试 ${colors[]}
printf %s\n ${colors[]}
# Output:
# red
# yellow
# dark blue在引号内${colors[]}将数组中的每个元素扩展为一个单独的参数数组元素中的空格得以保留。
访问数组的部分元素
echo ${nums[]:0:2}
# Output:
# 0 1在上面的例子中${array[]} 扩展为整个数组:0:2 取出了数组中从 0 开始长度为 2 的元素。
访问数组长度
echo ${#nums[*]}
# Output:
# 3向数组中添加元素
向数组中添加元素也非常简单
colors(white ${colors[]} green black)
echo ${colors[]}
# Output:
# white red yellow dark blue green black上面的例子中${colors[]} 扩展为整个数组并被置换到复合赋值语句中接着对数组 colors 的赋值覆盖了它原来的值。
从数组中删除元素
用 unset 命令来从数组中删除一个元素
unset nums[0]
echo ${nums[]}
# Output:
# 1 2“示例源码”
#!/usr/bin/env bash################### 创建数组 ###################
nums( [ 2 ] 2 [ 0 ] 0 [ 1 ] 1 )
colors( red yellow dark blue )################### 访问数组的单个元素 ###################
echo ${nums[1]}
# Output: 1################### 访问数组的所有元素 ###################
echo ${colors[*]}
# Output: red yellow dark blueecho ${colors[]}
# Output: red yellow dark blueprintf %s\n ${colors[*]}
# Output:
# red
# yellow
# dark
# blueprintf %s\n ${colors[*]}
# Output:
# red yellow dark blueprintf %s\n ${colors[]}
# Output:
# red
# yellow
# dark blue################### 访问数组的部分元素 ###################
echo ${nums[]:0:2}
# Output:
# 0 1################### 获取数组长度 ###################
echo ${#nums[*]}
# Output:
# 3################### 向数组中添加元素 ###################
colors( white ${colors[]} green black )
echo ${colors[]}
# Output:
# white red yellow dark blue green black################### 从数组中删除元素 ###################
unset nums[ 0 ]
echo ${nums[]}
# Output:
# 1 2运算符
算术运算符
下表列出了常用的算术运算符假定变量 x 为 10变量 y 为 20
运算符说明举例加法expr $x $y 结果为 30。-减法expr $x - $y 结果为 -10。*乘法expr $x * $y 结果为 200。/除法expr $y / $x 结果为 2。%取余expr $y % $x 结果为 0。赋值x$y 将把变量 y 的值赋给 x。相等。用于比较两个数字相同则返回 true。[ $x $y ] 返回 false。!不相等。用于比较两个数字不相同则返回 true。[ $x ! $y ] 返回 true。
注意条件表达式要放在方括号之间并且要有空格例如: [ x x xy] 是错误的必须写成 [ $x $y ]。 “示例源码”
x10
y20echo x${x}, y${y}valexpr ${x} ${y}
echo ${x} ${y} $valvalexpr ${x} - ${y}
echo ${x} - ${y} $valvalexpr ${x} \* ${y}
echo ${x} * ${y} $valvalexpr ${y} / ${x}
echo ${y} / ${x} $valvalexpr ${y} % ${x}
echo ${y} % ${x} $valif [[ ${x} ${y} ]]
thenecho ${x} ${y}
fi
if [[ ${x} ! ${y} ]]
thenecho ${x} ! ${y}
fi# Output:
# x10, y20
# 10 20 30
# 10 - 20 -10
# 10 * 20 200
# 20 / 10 2
# 20 % 10 0
# 10 ! 20关系运算符
关系运算符只支持数字不支持字符串除非字符串的值是数字。
下表列出了常用的关系运算符假定变量 x 为 10变量 y 为 20
运算符说明举例-eq检测两个数是否相等相等返回 true。[ $a -eq $b ] 返回 false。-ne检测两个数是否相等不相等返回 true。[ $a -ne $b ] 返回 true。-gt检测左边的数是否大于右边的如果是则返回 true。[ $a -gt $b ] 返回 false。-lt检测左边的数是否小于右边的如果是则返回 true。[ $a -lt $b ] 返回 true。-ge检测左边的数是否大于等于右边的如果是则返回 true。[ $a -ge $b ] 返回 false。-le检测左边的数是否小于等于右边的如果是则返回 true。[ $a -le $b ] 返回 true。 “示例源码”
x10
y20echo x${x}, y${y}if [[ ${x} -eq ${y} ]]; thenecho ${x} -eq ${y} : x 等于 y
elseecho ${x} -eq ${y}: x 不等于 y
fiif [[ ${x} -ne ${y} ]]; thenecho ${x} -ne ${y}: x 不等于 y
elseecho ${x} -ne ${y}: x 等于 y
fiif [[ ${x} -gt ${y} ]]; thenecho ${x} -gt ${y}: x 大于 y
elseecho ${x} -gt ${y}: x 不大于 y
fiif [[ ${x} -lt ${y} ]]; thenecho ${x} -lt ${y}: x 小于 y
elseecho ${x} -lt ${y}: x 不小于 y
fiif [[ ${x} -ge ${y} ]]; thenecho ${x} -ge ${y}: x 大于或等于 y
elseecho ${x} -ge ${y}: x 小于 y
fiif [[ ${x} -le ${y} ]]; thenecho ${x} -le ${y}: x 小于或等于 y
elseecho ${x} -le ${y}: x 大于 y
fi# Output:
# x10, y20
# 10 -eq 20: x 不等于 y
# 10 -ne 20: x 不等于 y
# 10 -gt 20: x 不大于 y
# 10 -lt 20: x 小于 y
# 10 -ge 20: x 小于 y
# 10 -le 20: x 小于或等于 y布尔运算符
下表列出了常用的布尔运算符假定变量 x 为 10变量 y 为 20
运算符说明举例!非运算表达式为 true 则返回 false否则返回 true。[ ! false ] 返回 true。-o或运算有一个表达式为 true 则返回 true。[ $a -lt 20 -o $b -gt 100 ] 返回 true。-a与运算两个表达式都为 true 才返回 true。[ $a -lt 20 -a $b -gt 100 ] 返回 false。 “示例源码”
x10
y20echo x${x}, y${y}if [[ ${x} ! ${y} ]]; thenecho ${x} ! ${y} : x 不等于 y
elseecho ${x} ! ${y}: x 等于 y
fiif [[ ${x} -lt 100 ${y} -gt 15 ]]; thenecho ${x} 小于 100 且 ${y} 大于 15 : 返回 true
elseecho ${x} 小于 100 且 ${y} 大于 15 : 返回 false
fiif [[ ${x} -lt 100 || ${y} -gt 100 ]]; thenecho ${x} 小于 100 或 ${y} 大于 100 : 返回 true
elseecho ${x} 小于 100 或 ${y} 大于 100 : 返回 false
fiif [[ ${x} -lt 5 || ${y} -gt 100 ]]; thenecho ${x} 小于 5 或 ${y} 大于 100 : 返回 true
elseecho ${x} 小于 5 或 ${y} 大于 100 : 返回 false
fi# Output:
# x10, y20
# 10 ! 20 : x 不等于 y
# 10 小于 100 且 20 大于 15 : 返回 true
# 10 小于 100 或 20 大于 100 : 返回 true
# 10 小于 5 或 20 大于 100 : 返回 false逻辑运算符
以下介绍 Shell 的逻辑运算符假定变量 x 为 10变量 y 为 20:
运算符说明举例逻辑的 AND[[ ${x} -lt 100 ${y} -gt 100 ]] 返回 false “示例源码”
x10
y20echo x${x}, y${y}if [[ ${x} -lt 100 ${y} -gt 100 ]]
thenecho ${x} -lt 100 ${y} -gt 100 返回 true
elseecho ${x} -lt 100 ${y} -gt 100 返回 false
fiif [[ ${x} -lt 100 || ${y} -gt 100 ]]
thenecho ${x} -lt 100 || ${y} -gt 100 返回 true
elseecho ${x} -lt 100 || ${y} -gt 100 返回 false
fi# Output:
# x10, y20
# 10 -lt 100 20 -gt 100 返回 false
# 10 -lt 100 || 20 -gt 100 返回 true字符串运算符
下表列出了常用的字符串运算符假定变量 a 为 “abc”变量 b 为 “efg”
运算符说明举例检测两个字符串是否相等相等返回 true。[ $a $b ] 返回 false。!检测两个字符串是否相等不相等返回 true。[ $a ! $b ] 返回 true。-z检测字符串长度是否为 0为 0 返回 true。[ -z $a ] 返回 false。-n检测字符串长度是否为 0不为 0 返回 true。[ -n $a ] 返回 true。str检测字符串是否为空不为空返回 true。注这可能是一个误解因为str不是标准的 shell 测试运算符。正确的可能是 -n 或 [[ ]] 测试。[ $a ] 返回 true。 “示例源码”
xabc
yxyzecho x${x}, y${y}if [[ ${x} ${y} ]]; thenecho ${x} ${y} : x 等于 y
elseecho ${x} ${y}: x 不等于 y
fiif [[ ${x} ! ${y} ]]; thenecho ${x} ! ${y} : x 不等于 y
elseecho ${x} ! ${y}: x 等于 y
fiif [[ -z ${x} ]]; thenecho -z ${x} : 字符串长度为 0
elseecho -z ${x} : 字符串长度不为 0
fiif [[ -n ${x} ]]; thenecho -n ${x} : 字符串长度不为 0
elseecho -n ${x} : 字符串长度为 0
fiif [[ ${x} ]]; thenecho ${x} : 字符串不为空
elseecho ${x} : 字符串为空
fi# Output:
# xabc, yxyz
# abc xyz: x 不等于 y
# abc ! xyz : x 不等于 y
# -z abc : 字符串长度不为 0
# -n abc : 字符串长度不为 0
# abc : 字符串不为空文件测试运算符
文件测试运算符用于检测 Unix 文件的各种属性。
属性检测描述如下
操作符说明举例-b检测文件是否是块设备文件如果是则返回 true。[ -b $file ] 返回 false。-c检测文件是否是字符设备文件如果是则返回 true。[ -c $file ] 返回 false。-d检测文件是否是目录如果是则返回 true。[ -d $file ] 返回 false。-f检测文件是否是普通文件既不是目录也不是设备文件如果是则返回 true。[ -f $file ] 返回 true。-g检测文件是否设置了 SGID 位如果是则返回 true。[ -g $file ] 返回 false。-k检测文件是否设置了粘着位(Sticky Bit)如果是则返回 true。[ -k $file ] 返回 false。-p检测文件是否是有名管道如果是则返回 true。[ -p $file ] 返回 false。-u检测文件是否设置了 SUID 位如果是则返回 true。[ -u $file ] 返回 false。-r检测文件是否可读如果是则返回 true。[ -r $file ] 返回 true。-w检测文件是否可写如果是则返回 true。[ -w $file ] 返回 true。-x检测文件是否可执行如果是则返回 true。[ -x $file ] 返回 true。-s检测文件是否为空文件大小是否大于 0不为空返回 true。[ -s $file ] 返回 true。-e检测文件包括目录是否存在如果是则返回 true。[ -e $file ] 返回 true。 “示例源码”
file/etc/hostsif [[ -r ${file} ]]; thenecho ${file} 文件可读
elseecho ${file} 文件不可读
fi
if [[ -w ${file} ]]; thenecho ${file} 文件可写
elseecho ${file} 文件不可写
fi
if [[ -x ${file} ]]; thenecho ${file} 文件可执行
elseecho ${file} 文件不可执行
fi
if [[ -f ${file} ]]; thenecho ${file} 文件为普通文件
elseecho ${file} 文件为特殊文件
fi
if [[ -d ${file} ]]; thenecho ${file} 文件是个目录
elseecho ${file} 文件不是个目录
fi
if [[ -s ${file} ]]; thenecho ${file} 文件不为空
elseecho ${file} 文件为空
fi
if [[ -e ${file} ]]; thenecho ${file} 文件存在
elseecho ${file} 文件不存在
fi# Output:(根据文件的实际情况输出结果可能不同)
# /etc/hosts 文件可读
# /etc/hosts 文件可写
# /etc/hosts 文件不可执行
# /etc/hosts 文件为普通文件
# /etc/hosts 文件不是个目录
# /etc/hosts 文件不为空
# /etc/hosts 文件存在控制语句
条件语句
跟其它程序设计语言一样Bash 中的条件语句让我们可以决定一个操作是否被执行。结果取决于一个包在[[ ]]里的表达式。
由[[ ]]sh 中是[ ]包起来的表达式被称作 检测命令 或 基元。这些表达式帮助我们检测一个条件的结果。这里可以找到有关 bash 中单双中括号区别的答案。
共有两个不同的条件表达式if 和 case。
if
1if 语句
if 在使用上跟其它语言相同。如果中括号里的表达式为真那么 then 和 fi 之间的代码会被执行。fi 标志着条件代码块的结束。
# 写成一行
if [[ 1 -eq 1 ]]; then echo 1 -eq 1 result is: true; fi
# Output: 1 -eq 1 result is: true# 写成多行
if [[ abc -eq abc ]]
thenecho abc -eq abc result is: true
fi
# Output: abc -eq abc result is: true2if else 语句
同样我们可以使用 if…else 语句例如
if [[ 2 -ne 1 ]]; thenecho true
elseecho false
fi
# Output: true3if elif else 语句
有些时候if…else 不能满足我们的要求。别忘了 if…elif…else使用起来也很方便。 “示例源码”
x10
y20
if [[ ${x} ${y} ]]; thenecho ${x} ${y}
elif [[ ${x} ${y} ]]; thenecho ${x} ${y}
elseecho ${x} ${y}
fi
# Output: 10 20case
如果你需要面对很多情况分别要采取不同的措施那么使用 case 会比嵌套的 if 更有用。使用 case 来解决复杂的条件判断看起来像下面这样 “示例源码”
exec
case ${oper} in)valexpr ${x} ${y}echo ${x} ${y} ${val};;-)valexpr ${x} - ${y}echo ${x} - ${y} ${val};;*)valexpr ${x} \* ${y}echo ${x} * ${y} ${val};;/)valexpr ${x} / ${y}echo ${x} / ${y} ${val};;*)echo Unknown oper!;;
esac每种情况都是匹配了某个模式的表达式。|用来分割多个模式)用来结束一个模式序列。第一个匹配上的模式对应的命令将会被执行。*代表任何不匹配以上给定模式的模式。命令块儿之间要用;;分隔。
循环语句
循环其实不足为奇。跟其它程序设计语言一样bash 中的循环也是只要控制条件为真就一直迭代执行的代码块。
Bash 中有四种循环
forwhileuntilselect
for 循环
for 与它在 C 语言中的姊妹非常像。看起来是这样
for arg in elem1 elem2 ... elemN
do### 语句
done在每次循环的过程中arg 依次被赋值为从 elem1 到 elemN。这些值还可以是通配符或者大括号扩展。
当然我们还可以把 for 循环写在一行但这要求 do 之前要有一个分号就像下面这样
for i in {1..5}; do echo $i; done还有如果你觉得 for…in…do 对你来说有点奇怪那么你也可以像 C 语言那样使用 for比如
for (( i 0; i 10; i )); doecho $i
done当我们想对一个目录下的所有文件做同样的操作时for 就很方便了。举个例子如果我们想把所有的.bash 文件移动到 script 文件夹中并给它们可执行权限我们的脚本可以这样写 “示例源码”
DIR/home/zp
for FILE in ${DIR}/*.sh; domv $FILE ${DIR}/scripts
done
# 将 /home/zp 目录下所有 sh 文件拷贝到 /home/zp/scriptswhile 循环
while 循环检测一个条件只要这个条件为 真就执行一段命令。被检测的条件跟 if…then 中使用的基元并无二异。因此一个 while 循环看起来会是这样
while [[ condition ]]
do### 语句
done跟 for 循环一样如果我们把 do 和被检测的条件写到一行那么必须要在 do 之前加一个分号。 “示例源码”
### 0到9之间每个数的平方
x0
while [[ ${x} -lt 10 ]]; doecho $((x * x))x$((x 1))
done
# Output:
# 0
# 1
# 4
# 9
# 16
# 25
# 36
# 49
# 64
# 81until 循环
until 循环跟 while 循环正好相反。它跟 while 一样也需要检测一个测试条件但不同的是只要该条件为 假 就一直执行循环 “示例源码”
x0
until [[ ${x} -ge 5 ]]; doecho ${x}xexpr ${x} 1
done
# Output:
# 0
# 1
# 2
# 3
# 4select 循环
select 循环帮助我们组织一个用户菜单。它的语法几乎跟 for 循环一致
select answer in elem1 elem2 ... elemN
do### 语句
doneselect 会打印 elem1…elemN 以及它们的序列号到屏幕上之后会提示用户输入。通常看到的是 $?PS3 变量。用户的选择结果会被保存到 answer 中。如果 answer 是一个在 1…N 之间的数字那么语句会被执行紧接着会进行下一次迭代 —— 如果不想这样的话我们可以使用 break 语句。 “示例源码”
#!/usr/bin/env bashPS3Choose the package manager:
select ITEM in bower npm gem pip
do
echo -n Enter the package name: read PACKAGE
case ${ITEM} inbower) bower install ${PACKAGE} ;;npm) npm install ${PACKAGE} ;;gem) gem install ${PACKAGE} ;;pip) pip install ${PACKAGE} ;;
esac
break # 避免无限循环
done这个例子先询问用户他想使用什么包管理器。接着又询问了想安装什么包最后执行安装操作。
运行这个脚本会得到如下输出
$ ./my_script
1) bower
2) npm
3) gem
4) pip
Choose the package manager: 2
Enter the package name: gitbook-clibreak 和 continue
如果想提前结束一个循环或跳过某次循环执行可以使用 shell 的 break 和 continue 语句来实现。它们可以在任何循环中使用。
break 语句用来提前结束当前循环。
continue 语句用来跳过某次迭代。 “示例源码”
# 查找 10 以内第一个能整除 2 和 3 的正整数
i1
while [[ ${i} -lt 10 ]]; doif [[ $((i % 3)) -eq 0 ]] [[ $((i % 2)) -eq 0 ]]; thenecho ${i}break;fiiexpr ${i} 1
done
# Output: 6“示例源码”
# 打印10以内的奇数
for (( i 0; i 10; i )); doif [[ $((i % 2)) -eq 0 ]]; thencontinue;fiecho ${i}
done
# Output:
# 1
# 3
# 5
# 7
# 9函数
bash 函数定义语法如下
[ function ] funname [()] {action;[return int;]
}说明 函数定义时function 关键字可有可无。 函数返回值 - return 返回函数返回值返回值类型只能为整数0-255。如果不加 return 语句shell 默认将以最后一条命令的运行结果作为函数返回值。 函数返回值在调用该函数后通过 $? 来获得。 所有函数在使用前必须定义。这意味着必须将函数放在脚本开始部分直至 shell 解释器首次发现它时才可以使用。调用函数仅使用其函数名即可。 “示例源码”
#!/usr/bin/env bashcalc(){PS3choose the oper: select oper in - \* / # 生成操作符选择菜单doecho -n enter first num: read x # 读取输入参数echo -n enter second num: read y # 读取输入参数execcase ${oper} in)return $((${x} ${y}));;-)return $((${x} - ${y}));;*)return $((${x} * ${y}));;/)return $((${x} / ${y}));;*)echo ${oper} is not support!return 0;;esacbreakdone
}
calc
echo the result is: $? # $? 获取 calc 函数返回值执行结果
$ ./function-demo.sh
1)
2) -
3) *
4) /
choose the oper: 3
enter first num: 10
enter second num: 10
the result is: 100位置参数
位置参数是在调用一个函数并传给它参数时创建的变量。
位置参数变量表
变量描述$0脚本名称$1 … $9第 1 个到第 9 个参数列表${10} … ${N}第 10 个到 N 个参数列表N 是一个正整数$* 或 $除了 $0 外的所有位置参数$#不包括 $0 在内的位置参数的个数$FUNCNAME函数名称仅在函数内部有值 “示例源码”
#!/usr/bin/env bashx0
if [[ -n $1 ]]; thenecho 第一个参数为$1x$1
elseecho 第一个参数为空
fiy0
if [[ -n $2 ]]; thenecho 第二个参数为$2y$2
elseecho 第二个参数为空
fiparamsFunction(){echo 函数第一个入参$1echo 函数第二个入参$2
}
paramsFunction ${x} ${y}执行结果
$ ./function-demo2.sh
第一个参数为空
第二个参数为空
函数第一个入参0
函数第二个入参0$ ./function-demo2.sh 10 20
第一个参数为10
第二个参数为20
函数第一个入参10
函数第二个入参20执行 ./variable-demo4.sh hello world 然后在脚本中通过 $1、$2 … 读取第 1 个参数、第 2 个参数。。。
函数处理参数
另外还有几个特殊字符用来处理参数
参数处理说明$#返回参数个数$*返回所有参数$$脚本运行的当前进程 ID 号$!后台运行的最后一个进程的 ID 号$返回所有参数与 $* 相同$-返回 Shell 使用的当前选项与 set 命令功能相同。$?函数返回值或上一个命令的退出状态 “示例源码”
runner() {return 0
}namezp
paramsFunction(){echo 函数第一个入参$1echo 函数第二个入参$2echo 传递到脚本的参数个数$#echo 所有参数printf %s\n $*echo 脚本运行的当前进程 ID 号$$echo 后台运行的最后一个进程的 ID 号$!echo 所有参数printf %s\n $echo Shell 使用的当前选项$-runnerecho runner 函数的返回值$?
}
paramsFunction 1 abc hello, \zp\
# Output:
# 函数第一个入参1
# 函数第二个入参abc
# 传递到脚本的参数个数3
# 所有参数
# 1 abc hello, zp
# 脚本运行的当前进程 ID 号26400
# 后台运行的最后一个进程的 ID 号
# 所有参数
# 1
# abc
# hello, zp
# Shell 使用的当前选项hB
# runner 函数的返回值0Shell 扩展
扩展 发生在一行命令被分成一个个的 记号tokens 之后。换言之扩展是一种执行数学运算的机制还可以用来保存命令的执行结果等等。
感兴趣的话可以阅读关于 shell 扩展的更多细节。
大括号扩展
大括号扩展让生成任意的字符串成为可能。它跟 文件名扩展 很类似举个例子
echo beg{i,a,u}n ### begin began begun大括号扩展还可以用来创建一个可被循环迭代的区间。
echo {0..5} ### 0 1 2 3 4 5
echo {00..8..2} ### 00 02 04 06 08命令置换
命令置换允许我们对一个命令求值并将其值置换到另一个命令或者变量赋值表达式中。当一个命令被或 $()包围时命令置换将会执行。举个例子
nowdate %T
### or
now$(date %T)echo $now ### 19:08:26算数扩展
在 bash 中执行算数运算是非常方便的。算数表达式必须包在 $(( ))中。算数扩展的格式为
result$(( ((10 5*3) - 7) / 2 ))
echo $result ### 9在算数表达式中使用变量无需带上 $ 前缀
x4
y7
echo $(( x y )) ### 11
echo $(( x y )) ### 12
echo $(( x y )) ### 13单引号和双引号
单引号和双引号之间有很重要的区别。在双引号中变量引用或者命令置换是会被展开的。在单引号中是不会的。举个例子
echo Your home: $HOME ### Your home: /Users/username
echo Your home: $HOME ### Your home: $HOME当局部变量和环境变量包含空格时它们在引号中的扩展要格外注意。随便举个例子假如我们用 echo 来输出用户的输入
INPUTA string with strange whitespace.
echo $INPUT ### A string with strange whitespace.
echo $INPUT ### A string with strange whitespace.调用第一个 echo 时给了它 5 个单独的参数 —— $INPUT 被分成了单独的词echo 在每个词之间打印了一个空格。第二种情况调用 echo 时只给了它一个参数整个 $INPUT 的值包括其中的空格。
来看一个更严肃的例子
FILEFavorite Things.txt
cat $FILE ### 尝试输出两个文件: Favorite 和 Things.txt
cat $FILE ### 输出一个文件: Favorite Things.txt尽管这个问题可以通过把 FILE 重命名成 Favorite-Things.txt 来解决但是假如这个值来自某个环境变量来自一个位置参数或者来自其它命令find, cat, 等等呢。因此如果输入 可能 包含空格务必要用引号把表达式包起来。
流和重定向
Bash 有很强大的工具来处理程序之间的协同工作。使用流我们能将一个程序的输出发送到另一个程序或文件因此我们能方便地记录日志或做一些其它我们想做的事。
管道给了我们创建传送带的机会控制程序的执行成为可能。
学习如何使用这些强大的、高级的工具是非常非常重要的。
输入、输出流
Bash 接收输入并以字符序列或 字符流 的形式产生输出。这些流能被重定向到文件或另一个流中。
有三个文件描述符
代码描述符描述0stdin标准输入1stdout标准输出2stderr标准错误输出
重定向
重定向让我们可以控制一个命令的输入来自哪里输出结果到什么地方。这些运算符在控制流的重定向时会被用到
OperatorDescription重定向输出重定向输出和错误输出以附加的形式重定向输出和错误输出重定向输入Here 文档语法Here 字符串
以下是一些使用重定向的例子
### ls的结果将会被写到list.txt中
ls -l list.txt### 将输出附加到list.txt中
ls -a list.txt### 所有的错误信息会被写到errors.txt中
grep da * 2 errors.txt### 从errors.txt中读取输入
less errors.txt/dev/null 文件
如果希望执行某个命令但又不希望在屏幕上显示输出结果那么可以将输出重定向到 /dev/null
$ command /dev/null/dev/null 是一个特殊的文件写入到它的内容都会被丢弃如果尝试从该文件读取内容那么什么也读不到。但是 /dev/null 文件非常有用将命令的输出重定向到它会起到”禁止输出”的效果。
如果希望屏蔽 stdout 和 stderr可以这样写
$ command /dev/null 21Debug
shell 提供了用于 debug 脚本的工具。
如果想采用 debug 模式运行某脚本可以在其 shebang 中使用一个特殊的选项
#!/bin/bash optionsoptions 是一些可以改变 shell 行为的选项。下表是一些可能对你有用的选项
ShortNameDescription-fnoglob禁止文件名展开globbing-iinteractive让脚本以交互模式运行-nnoexec读取命令但不执行语法检查-t—执行完第一条命令后退出-vverbose在执行每条命令前向 stderr 输出该命令-xxtrace在执行每条命令前向 stderr 输出该命令以及该命令的扩展参数
举个例子如果我们在脚本中指定了 -x 例如
#!/bin/bash -xfor (( i 0; i 3; i )); doecho $i
done这会向 stdout 打印出变量的值和一些其它有用的信息
$ ./my_script(( i 0 ))(( i 3 ))echo 0
0(( i ))(( i 3 ))echo 1
1(( i ))(( i 3 ))echo 2
2(( i ))(( i 3 ))有时我们值需要 debug 脚本的一部分。这种情况下使用 set 命令会很方便。这个命令可以启用或禁用选项。使用-启用选项禁用选项 “示例源码”
# 开启 debug
set -x
for (( i 0; i 3; i )); doprintf ${i}
done
# 关闭 debug
set x
# Output:
# (( i 0 ))
# (( i 3 ))
# printf 0
# 0 (( i ))
# (( i 3 ))
# printf 1
# 1 (( i ))
# (( i 3 ))
# printf 2
# 2 (( i ))
# (( i 3 ))
# set xfor i in {1..5}; do printf ${i}; done
printf \n
# Output: 12345往期精彩文章 Oracle 一键巡检自动生成 Word 报告 Oracle 一键安装合集 Oracle一键安装脚本的 21 个疑问与解答 Oracle一键巡检脚本的 21 个疑问与解答 全网首发Oracle 23ai 一键安装脚本非 RPM Oracle 19C 最新 RU 补丁 19.24 一键安装 Oracle Linux 7.9 一键安装 Oracle 19C RedHat 9.4(aarch64) 一键安装 Oracle 19C openEuler 22.03 LTS SP4 一键安装 Oracle 19C RAC RHEL 7.9 一键安装 Oracle 19C 19.23 RAC Oracle DataGuard GAP 修复手册 优化 Oracle最佳实践与开发规范 DBA 必备Linux 软件源配置全攻略 Linux 一键配置时钟同步全攻略 感谢您的阅读这里是 Lucifer三思而后行欢迎点赞关注我会持续分享数据库知识、运维技巧。 文章转载自: http://www.morning.ygwyt.cn.gov.cn.ygwyt.cn http://www.morning.ckwrn.cn.gov.cn.ckwrn.cn http://www.morning.jydky.cn.gov.cn.jydky.cn http://www.morning.jrhmh.cn.gov.cn.jrhmh.cn http://www.morning.rqqct.cn.gov.cn.rqqct.cn http://www.morning.dkcpt.cn.gov.cn.dkcpt.cn http://www.morning.mflhr.cn.gov.cn.mflhr.cn http://www.morning.fdhwh.cn.gov.cn.fdhwh.cn http://www.morning.wslpk.cn.gov.cn.wslpk.cn http://www.morning.wslr.cn.gov.cn.wslr.cn http://www.morning.bzqnp.cn.gov.cn.bzqnp.cn http://www.morning.nslwj.cn.gov.cn.nslwj.cn http://www.morning.rcmcw.cn.gov.cn.rcmcw.cn http://www.morning.fnywn.cn.gov.cn.fnywn.cn http://www.morning.mtsgx.cn.gov.cn.mtsgx.cn http://www.morning.pcrzf.cn.gov.cn.pcrzf.cn http://www.morning.xqkjp.cn.gov.cn.xqkjp.cn http://www.morning.sqhlx.cn.gov.cn.sqhlx.cn http://www.morning.wdlg.cn.gov.cn.wdlg.cn http://www.morning.qcygd.cn.gov.cn.qcygd.cn http://www.morning.xdmsq.cn.gov.cn.xdmsq.cn http://www.morning.bxbnf.cn.gov.cn.bxbnf.cn http://www.morning.wchsx.cn.gov.cn.wchsx.cn http://www.morning.kbgzj.cn.gov.cn.kbgzj.cn http://www.morning.rxtxf.cn.gov.cn.rxtxf.cn http://www.morning.jfsbs.cn.gov.cn.jfsbs.cn http://www.morning.kryn.cn.gov.cn.kryn.cn http://www.morning.prddj.cn.gov.cn.prddj.cn http://www.morning.zlhcw.cn.gov.cn.zlhcw.cn http://www.morning.tdldh.cn.gov.cn.tdldh.cn http://www.morning.mdlqf.cn.gov.cn.mdlqf.cn http://www.morning.dbsch.cn.gov.cn.dbsch.cn http://www.morning.sgmis.com.gov.cn.sgmis.com http://www.morning.dansj.com.gov.cn.dansj.com http://www.morning.wgbsm.cn.gov.cn.wgbsm.cn http://www.morning.psdsk.cn.gov.cn.psdsk.cn http://www.morning.llllcc.com.gov.cn.llllcc.com http://www.morning.sqqds.cn.gov.cn.sqqds.cn http://www.morning.wjlbb.cn.gov.cn.wjlbb.cn http://www.morning.bqrd.cn.gov.cn.bqrd.cn http://www.morning.ykrkb.cn.gov.cn.ykrkb.cn http://www.morning.kqkmx.cn.gov.cn.kqkmx.cn http://www.morning.qxlxs.cn.gov.cn.qxlxs.cn http://www.morning.rhkgz.cn.gov.cn.rhkgz.cn http://www.morning.rqfkh.cn.gov.cn.rqfkh.cn http://www.morning.mnwsy.cn.gov.cn.mnwsy.cn http://www.morning.nbybb.cn.gov.cn.nbybb.cn http://www.morning.hfbtt.cn.gov.cn.hfbtt.cn http://www.morning.24vy.com.gov.cn.24vy.com http://www.morning.qkxnw.cn.gov.cn.qkxnw.cn http://www.morning.dpdr.cn.gov.cn.dpdr.cn http://www.morning.qqklk.cn.gov.cn.qqklk.cn http://www.morning.mnqg.cn.gov.cn.mnqg.cn http://www.morning.rkyw.cn.gov.cn.rkyw.cn http://www.morning.wiitw.com.gov.cn.wiitw.com http://www.morning.thwcg.cn.gov.cn.thwcg.cn http://www.morning.hxmqb.cn.gov.cn.hxmqb.cn http://www.morning.mhlsx.cn.gov.cn.mhlsx.cn http://www.morning.dbfwq.cn.gov.cn.dbfwq.cn http://www.morning.rhlhk.cn.gov.cn.rhlhk.cn http://www.morning.rqckh.cn.gov.cn.rqckh.cn http://www.morning.bgkk.cn.gov.cn.bgkk.cn http://www.morning.frpb.cn.gov.cn.frpb.cn http://www.morning.cfocyfa.cn.gov.cn.cfocyfa.cn http://www.morning.ghjln.cn.gov.cn.ghjln.cn http://www.morning.dkbgg.cn.gov.cn.dkbgg.cn http://www.morning.fthcq.cn.gov.cn.fthcq.cn http://www.morning.lhxkl.cn.gov.cn.lhxkl.cn http://www.morning.tpfny.cn.gov.cn.tpfny.cn http://www.morning.xjqhh.cn.gov.cn.xjqhh.cn http://www.morning.sgbss.cn.gov.cn.sgbss.cn http://www.morning.qbmpb.cn.gov.cn.qbmpb.cn http://www.morning.njpny.cn.gov.cn.njpny.cn http://www.morning.lgsqy.cn.gov.cn.lgsqy.cn http://www.morning.dkzrs.cn.gov.cn.dkzrs.cn http://www.morning.jcbjy.cn.gov.cn.jcbjy.cn http://www.morning.tnyanzou.com.gov.cn.tnyanzou.com http://www.morning.qlkzl.cn.gov.cn.qlkzl.cn http://www.morning.jtrqn.cn.gov.cn.jtrqn.cn http://www.morning.rzrbw.cn.gov.cn.rzrbw.cn