兰州网站运营,网站开发包括什么软件,河南龙王建设集团网站,搜索引擎推广试题原文链接#xff1a;https://blog.csdn.net/weixin_39844426/article/details/113422137
前几天读了下mysqld_safe脚本#xff0c;个人感觉还是收获蛮大的#xff0c;其中细致的交代了MySQL数据库的启动流程#xff0c;包括查找MySQL相关目录#xff0c;解析配置文件以及…原文链接https://blog.csdn.net/weixin_39844426/article/details/113422137
前几天读了下mysqld_safe脚本个人感觉还是收获蛮大的其中细致的交代了MySQL数据库的启动流程包括查找MySQL相关目录解析配置文件以及最后如何调用mysqld程序来启动实例等有着不错的参考价值与此同时脚本中涉及了很多shell编程中的小技巧像变量解析sed替换转义进程优先级的判断以及无处不在test结构等等当作Linux shell的学习素材还是非常合适的下面是我的环境
数据库版本: MySQL 5.1.45
操作系统版本 Red Hat Enterprise Linux AS release 4 (Nahant Update 3)
MySQL基目录 /usr/local/mysql3306
配置文件目录 /usr/local/mysql3306/etc
数据库是安装好了的代码如下
#!/bin/sh
# 一些状态变量的定义
KILL_MYSQLD1; # 试图kill多余的mysqld_safe程序1表示需要kill
MYSQLD # mysqld二进制可执行文件的名称
niceness0 # 进程的调度优先级标识
# 下面的变量主要用于标识不使用错误日志和syslog
logginginit # 日志记录状态init代表初始化
want_syslog0 # 标识是否要使用syslog
syslog_tag
usermysql # --user选项值
pid_file # pid文件的路径
err_log # 错误日志的路径
# 这两个都是定义的syslog中标志位在后面需要写入日志到syslog中时使用
syslog_tag_mysqldmysqld
syslog_tag_mysqld_safemysqld_safe
trap 1 2 3 15# 不允许程序在终端上被人打断(包括挂起中断退出系统终止的情形)
umask 007 # 默认权限770其他组用户对该程序创建的文件没有任何权限
# defaults变量记载使用的配置文件的信息
defaults
case $1 in
--no-defaults|--defaults-file*|--defaults-extra-file*)
defaults$1; shift
;;
esac
# usage()函数使用--help选项时输出的使用帮助信息
usage () {
cat
Usage: $0 [OPTIONS]
--no-defaults Dont read the system defaults file
--defaults-fileFILE Use the specified defaults file
--defaults-extra-fileFILE Also use defaults from the specified file
--ledirDIRECTORY Look for mysqld in the specified directory
--open-files-limitLIMIT Limit the number of open files
--core-file-sizeLIMIT Limit core files to the specified size
--timezoneTZ Set the system timezone
--mysqldFILE Use the specified file as mysqld
--mysqld-versionVERSION Use mysqld-VERSION as mysqld
--niceNICE Set the scheduling priority of mysqld
--skip-kill-mysqld Dont try to kill stray mysqld processes
--syslog Log messages to syslog with logger
--skip-syslog Log messages to error log (default)
--syslog-tagTAG Pass -t mysqld-TAG to logger
All other options are passed to the mysqld program.
EOF
exit 1
}
# my_which的作用相当于which通过检索$PATH中的路径打印出命令的全路径
# 这个函数就在后面一个地方用到了就是my_which logger意思等同于转换logger为/usr/bin/logger
my_which ()
{
save_ifs${IFS-UNSET} # 保存当前的内建分隔符用于后面重置IFS
IFS: # 使用 来分割PATH中的路径
ret0
for file # 这种写法等同于for file in *
do
for dir in $PATH
do
if [ -f $dir/$file ]
then
echo $dir/$file
continue 2 # continue 第 2 层, 这里就是跳出外层循环了
fi
done
ret1 # signal an error
break
done
# 将设置过的IFS重置回去
if [ $save_ifs UNSET ]
then
unset IFS
else
IFS$save_ifs
fi
return $ret # Success
}
# 日志输出函数这是个原型后面被log_error和log_notice函数引用
log_generic () {
# priority 代表日志信息的分类从后面的两个函数可知有daemon.error和daemon.notice两种类别
priority$1
shift
# 日志中记录的msg前缀格式 时间 mysqld_safe 类似于系统日志的记录格式
msgdate %y%m%d %H:%M:%S mysqld_safe $*
echo $msg
case $logging in
init) ;; # 初始化状态时只在命令行输出msg信息不记录日志
file) echo $msg $err_log ;; # 记录到err_log中
syslog) logger -t $syslog_tag_mysqld_safe -p $priority $* ;; # 使用logger记录到系统日志中
*)
echo Internal program error (non-fatal): \ unknown logging method $logging 2
;;
esac
}
# 下面两个函数是对log_generic函数中不同分类的引用
log_error () {
log_generic daemon.error $ 2
}
log_notice () {
log_generic daemon.notice $
}
# 后面就是用它启动的mysqld通过logging变量区分记录日志的类型分错误日志和系统日志syslog两种
# 最后的eval命令会解析 $cmd 中的值并执行命令
eval_log_error () {
cmd$1
case $logging in
file) cmd$cmd shell_quote_string $err_log 21 ;;
syslog)
cmd$cmd 21 | logger -t $syslog_tag_mysqld -p daemon.error
;;
*)
echo Internal program error (non-fatal): \ unknown logging method $logging 2
;;
esac
#echo Running mysqld: [$cmd]
eval $cmd
}
# 转义函数用于在非a-zA-Z09/_.-的特殊字符前加上一个\
# sed中的\1代表引用前面中匹配的值
shell_quote_string() {
echo $1 | sed -e s,[a−zA−Z0−9/.−],\\\1,g
}
# 该函数用于解析配置文件中的选项并赋值给相应的变量
parse_arguments() {
pick_args
if test $1 PICK-ARGS-FROM-ARGV
then
pick_args1
shift
fi
for arg do
# 取出参数值比如 --port3306 结果为 val 3306 注意这里sed中使用来分割等同于/
valecho $arg | sed -e s;--[^]*;;
case $arg in
# 将参数值传递给对应的变量
--basedir*) MY_BASEDIR_VERSION$val ;;
--datadir*) DATADIR$val ;;
--pid-file*) pid_file$val ;;
--user*) user$val; SET_USER1 ;;
# 有些值可能已经在my.cnf配置文件的[mysqld_safe]组下设置了
# 某些值会被命令行上指定的选项值覆盖
--log-error*) err_log$val ;;
--port*) mysql_tcp_port$val ;;
--socket*) mysql_unix_port$val ;;
# 接下来这几个特殊的选项在配置文件的[mysqld_safe]组中是必须设置的
# 我没配置这个组所以就用不到了(使用mysqld中的默认)
--core-file-size*) core_file_size$val ;;
--ledir*) ledir$val ;;
--mysqld*) MYSQLD$val ;;
--mysqld-version*)
if test -n $val
then
MYSQLDmysqld-$val
else
MYSQLDmysqld
fi
;;
--nice*) niceness$val ;;
--open-files-limit*) open_files$val ;;
--skip-kill-mysqld*) KILL_MYSQLD0 ;;
--syslog) want_syslog1 ;;
--skip-syslog) want_syslog0 ;;
--syslog-tag*) syslog_tag$val ;;
--timezone*) TZ$val; export TZ; ;; # 生效了一下时区设置
--help) usage ;; # 调用了usage函数输出帮助信息
*)
if test -n $pick_args
then
# 将其他命令行参数值附加到$arg的后面
append_arg_to_args $arg
fi
;;
esac
done
}
########################################
# 正式工作开始了
########################################
#
# 下面两段是在寻找基目录和mysqld所在目录
#
# 找到/usr/local/mysql3306/share/mysql目录使用relpkgdata来记录相对路径和绝对路径
# 这个grep其实应该是想判断一下share/mysql是不是显示的绝对路径不知道这么写的意义在哪里。
if echo /usr/local/mysql3306/share/mysql | grep ^/usr/local/mysql3306 /dev/null
then
# 一口气用了三个替换分别为
# 第一步将/usr/local/mysql3306转换为空
# 第二步将/share/mysql开头的/转换为空
# 第三步在share/mysql开头加上./结果即./share/mysql
relpkgdataecho /usr/local/mysql3306/share/mysql | sed -e s,^/usr/local/mysql3306,, -e s,^/,, -e s,^,./,
else
relpkgdata/usr/local/mysql3306/share/mysql
fi
# 这一段都是在找mysqld文件分别判断了libexec和bin目录
# 找不到就使用编译时的默认值
MY_PWDpwd
if test -n $MY_BASEDIR_VERSION -a -d $MY_BASEDIR_VERSION
then
if test -x $MY_BASEDIR_VERSION/libexec/mysqld
then
ledir$MY_BASEDIR_VERSION/libexec
else
ledir$MY_BASEDIR_VERSION/bin
fi
# 这里对errmsg.sys文件进行了判断个人认为这是为了确认当前目录为一个mysql安装基目录
elif test -f $relpkgdata/english/errmsg.sys -a -x $MY_PWD/bin/mysqld
then
MY_BASEDIR_VERSION$MY_PWD
ledir$MY_PWD/bin
elif test -f $relpkgdata/english/errmsg.sys -a -x $MY_PWD/libexec/mysqld
then
MY_BASEDIR_VERSION$MY_PWD
ledir$MY_PWD/libexec
else
MY_BASEDIR_VERSION/usr/local/mysql3306
ledir/usr/local/mysql3306/libexec
fi
#
# 接下来是找到配置文件和数据文件目录
#
# 找到配置文件目录
# 我的是放在了etc/目录下mysqld程序是会读取到的
#
# 可以从my_print_defaults脚本中获得默认的读取my.cnf顺序如下
# Default options are read from the following files in the given order:
# /etc/my.cnf /etc/mysql/my.cnf /home/mysql/mysql_master/etc/my.cnf ~/.my.cnf
# 或者可以使用strace -e open libexec/mysqld 21 | grep my.cnf查看
if test -d $MY_BASEDIR_VERSION/data/mysql
then
DATADIR$MY_BASEDIR_VERSION/data
if test -z $defaults -a -r $DATADIR/my.cnf
then
defaults--defaults-extra-file$DATADIR/my.cnf
fi
# 接下来找到数据文件的目录
elif test -d $MY_BASEDIR_VERSION/var/mysql
then
DATADIR$MY_BASEDIR_VERSION/var
# 找不到就用编译时指定的默认值
else
DATADIR/usr/local/mysql3306/var
fi
# 对存在两个配置文件情况进行冲突处理
if test -z $MYSQL_HOME
then
if test -r $MY_BASEDIR_VERSION/my.cnf test -r $DATADIR/my.cnf
then
# 优先考虑 $MY_BASEDIR_VERSION/my.cnf 文件
log_error WARNING: Found two instances of my.cnf -
$MY_BASEDIR_VERSION/my.cnf and
$DATADIR/my.cnf
IGNORING $DATADIR/my.cnf
MYSQL_HOME$MY_BASEDIR_VERSION
elif test -r $DATADIR/my.cnf
then
log_error WARNING: Found $DATADIR/my.cnf
The data directory is a deprecated location for my.cnf, please move it to
$MY_BASEDIR_VERSION/my.cnf
MYSQL_HOME$DATADIR
else
MYSQL_HOME$MY_BASEDIR_VERSION
fi
fi
export MYSQL_HOME
#
# 下面是使用bin/my_print_defaults读取my.cnf文件中的配置信息([mysqld] and [mysqld_safe])
# 并且和命令行中传入的参数进行合并
# 先是找到my_print_defaults执行文件 又是各种路径判断
if test -x $MY_BASEDIR_VERSION/bin/my_print_defaults
then
print_defaults$MY_BASEDIR_VERSION/bin/my_print_defaults
elif test -x ./bin/my_print_defaults
then
print_defaults./bin/my_print_defaults
elif test -x /usr/local/mysql3306/bin/my_print_defaults
then
print_defaults/usr/local/mysql3306/bin/my_print_defaults
elif test -x /usr/local/mysql3306/bin/mysql_print_defaults
then
print_defaults/usr/local/mysql3306/bin/mysql_print_defaults
else
print_defaultsmy_print_defaults
fi
# 这个函数可以将一个指定的参数附加到$arg中(在此同时执行了转义操作)
append_arg_to_args () {
args$args shell_quote_string $1
}
args
# 这里SET_USER2是针对下面一条parse_arguments来说的
# 因为如果在紧接着的parse_arugments函数中设置了--user的值那么SET_USER就会变为1表示--user以被配置
# 当然如果没有读取到--user的值就是说--user没有配置那么会在后面的if结构中设置SET_USER为0
# 这样在后面的判断结构中SET_USER的值 0代表没有配置--user的值1代表已经配置
SET_USER2
# 解析配置文件中的参数使用--loose-verbose来过滤[mysqld]和[server]组中的内容
parse_arguments $print_defaults $defaults --loose-verbose mysqld server
if test $SET_USER -eq 2
then
SET_USER0
fi
# 又对[safe_mysqld]和[mysqld_safe]组中的内容进行了过滤读取
# 在我的配置文件中已经没有这两个组了估计是为兼容旧版本的需要
parse_arguments $print_defaults $defaults --loose-verbose mysqld_safe safe_mysqld
# 用命令行输入选项 $ 来覆盖配置文件中的选项 机智
parse_arguments PICK-ARGS-FROM-ARGV $
#
# 下面是logging工具的使用
#
# 判断logger工具是否可用
if [ $want_syslog -eq 1 ]
then
my_which logger /dev/null 21
if [ $? -ne 0 ]
then
log_error --syslog requested, but no logger program found. Please ensure that logger is in your PATH, or do not specify the --syslog option to mysqld_safe.
exit 1
fi
fi
# 给err_log改名字。。。
if [ -n $err_log -o $want_syslog -eq 0 ]
then
if [ -n $err_log ]
then
# 下面是为err_log添加一个.err后缀(如果现在名字没有后缀)
# 如果不设置这个后缀mysqld_safe和mysqld程序会将日志写入不同的文件中
# 因为在 mysqld 程序中它将识别带有.的文件名为错误日志(脚本注释上说的)
# 这里的expr是识别文件名中“.”前面的字符总数量(包括.)如果没有设置后缀返回就是0了
if expr $err_log : .*\.[^/]*$ /dev/null
then
:
else
err_log$err_log.err
fi
case $err_log in
/* ) ;;
* ) err_log$DATADIR/$err_log ;;
esac
else
err_log$DATADIR//bin/hostname.err
fi
# 追加错误日志的位置选项
append_arg_to_args --log-error$err_log
# 发出错误提示不要使用syslog
if [ $want_syslog -eq 1 ]
then
log_error Cant log to error log and syslog at the same time. Remove all --log-error configuration options for --syslog to take effect.
fi
# Log to err_log file
log_notice Logging to $err_log.
loggingfiles # 正式把logging改成files 使用错误日志来记录日志
# 这个分支就是使用syslog的方法了
else
if [ -n $syslog_tag ]
then
# 设置各个syslog的使用标志位
syslog_tagecho $syslog_tag | sed -e s/[^a-zA-Z0-9_-]/_/g
syslog_tag_mysqld_safe${syslog_tag_mysqld_safe}-$syslog_tag
syslog_tag_mysqld${syslog_tag_mysqld}-$syslog_tag
fi
log_notice Logging to syslog.
loggingsyslog
fi
# 设置--user选项
USER_OPTION
if test -w / -o $USER root # 根目录是否可写或者当前用户为root
then
if test $user ! root -o $SET_USER 1
then
USER_OPTION--user$user
fi
# 创建错误日志并将日志授权给指定的用户
if [ $want_syslog -eq 0 ]; then
touch $err_log
chown $user $err_log
fi
# 这里它还对当前用户做了ulimit设置包括可以打开的文件数量--open_files-limit选项
if test -n $open_files
then
ulimit -n $open_files
append_arg_to_args --open-files-limit$open_files
fi
fi
safe_mysql_unix_port{mysql_unix_port:-${MYSQL_UNIX_PORT:-/usr/local/mysql3306/tmp/mysql.sock}}
# 确保 $safe_mysql_unix_port 目录是存在的
mysql_unix_port_dirdirname $safe_mysql_unix_port
if [ ! -d $mysql_unix_port_dir ]
then
mkdir $mysql_unix_port_dir
chown $user $mysql_unix_port_dir
chmod 755 $mysql_unix_port_dir
fi
# 如果用户没有制定mysqld程序的名称这里就默认赋值为mysqld
if test -z $MYSQLD
then
MYSQLDmysqld
fi
# 下面几段分别是对 mysqld pid port文件选项的检查和设置省略100个字
if test ! -x $ledir/$MYSQLD
then
log_error The file $ledir/$MYSQLD
does not exist or is not executable. Please cd to the mysql installation
directory and restart this script from there as follows:
./bin/mysqld_safe
See http://dev.mysql.com/doc/mysql/en/mysqld-safe.html for more information
exit 1
fi
if test -z $pid_file
then
pid_file$DATADIR//bin/hostname.pid
else
case $pid_file in
/* ) ;;
* ) pid_file$DATADIR/$pid_file ;;
esac
fi
append_arg_to_args --pid-file$pid_file
if test -n $mysql_unix_port
then
append_arg_to_args --socket$mysql_unix_port
fi
if test -n $mysql_tcp_port
then
append_arg_to_args --port$mysql_tcp_port
fi
#
# 接下来是关于优先级的设置
#
if test $niceness -eq 0
then
NOHUP_NICENESSnohup
else
NOHUP_NICENESSnohup nice -$niceness
fi
# 将当前的默认优先级设置为0
if nohup nice /dev/null 21
then
# normal_niceness记载默认的调度优先级
normal_nicenessnice
# nohup_niceness记载使用nohup执行方式的调度优先级
nohup_nicenessnohup nice 2/dev/null
numeric_nice_values1
# 这个for是为了检查$normal_niceness $nohup_niceness两个变量值的合法性
for val in $normal_niceness $nohup_niceness
do
case $val in
-[0-9] | -[0-9][0-9] | -[0-9][0-9][0-9] | \
[0-9] | [0-9][0-9] | [0-9][0-9][0-9] )
;;
* )
numeric_nice_values0 ;;
esac
done
# 这个判断结构很重要
# 它保证了使用nohup执行的mysqld程序在调度优先级上不会低于直接执行mysqld程序的方式
if test $numeric_nice_values -eq 1
then
nice_value_diffexpr $nohup_niceness - $normal_niceness
if test $? -eq 0 test $nice_value_diff -gt 0 \
nice --$nice_value_diff echo testing /dev/null 21
then
# 进入分支说明$nohup_niceness的值比$normal_niceness大即nohup执行方式调度优先级比正常执行方式低
# 这是不希望看到的所以下面就人为的提升了nohup的优先级(降低niceness的值)
nicenessexpr $niceness - $nice_value_diff
NOHUP_NICENESSnice -$niceness nohup
fi
fi
else
# 下面是测试nohup在当前系统中是否可用不可用的话就置空NOHUP_NICENESS
if nohup echo testing /dev/null 21
then
:
else
NOHUP_NICENESS
fi
fi
# 指定内核文件大小
if test -n $core_file_size
then
ulimit -c $core_file_size
fi
#
# 如果已经存在一个pid文件则检查是否有已经启动的mysqld_safe进程
if test -f $pid_file
then
PIDcat $pid_file
if /bin/kill -0 $PID /dev/null 2 /dev/null
then
if /bin/ps wwwp $PID | grep -v grep | grep -v mysqld_safe | grep -- $MYSQLD /dev/null
then
log_error A mysqld process already exists
exit 1
fi
fi
# 下面是处理办法删除旧的pid文件并报错
rm -f $pid_file
if test -f $pid_file
then
log_error Fatal error: Cant remove the pid file:
$pid_file
Please remove it manually and start $0 again;
mysqld daemon not started
exit 1
fi
fi
#
# 下面便是拼接执行语句运行了。
#
cmd$NOHUP_NICENESS
# 检查一下命令 并进行转义操作
for i in $ledir/$MYSQLD $defaults --basedir$MY_BASEDIR_VERSION \
--datadir$DATADIR $USER_OPTION
do
cmd$cmd shell_quote_string $i
done
cmd$cmd $args
# Avoid nohup: ignoring input warning
test -n $NOHUP_NICENESS cmd$cmd /dev/null
log_notice Starting $MYSQLD daemon with databases from $DATADIR
# 后台循环 执行mysqld
while true
do
rm -f $safe_mysql_unix_port $pid_file# 保险起见又删除了一次pid文件
# 调用eval_log_error函数传入$cmd参数的值最后使用eval命令执行了启动mysqld
eval_log_error $cmd
if test ! -f $pid_file# 没有成功创建pid文件则退出分支
then
break
fi
# mysqld_safe已经启动的处理方法保证只有一个mysqld_safe程序启动
if true test $KILL_MYSQLD -eq 1
then
# 统计启动的mysqld进程的数目
numofprocesps xaww | grep -v grep | grep $ledir/$MYSQLD\ | grep -c pid-file$pid_file
log_notice Number of processes running now: $numofproces
I1
while test $I -le $numofproces
do
# 这个PROC的数据即是ps mysqld_safe程序的输出 第一个数字即为进程ID
PROCps xaww | grep $ledir/$MYSQLD\ | grep -v grep | grep pid-file$pid_file | sed -n $p
# 使用T来获取进程ID
for T in $PROC
do
break
done
# kill掉该个mysqld_safe程序
if kill -9 $T
then
log_error $MYSQLD process hanging, pid $T - killed
else
break
fi
# 每干掉一个mysqld_safe就把I加一这样没有多余的mysqld_safe时就可以跳出循环了
Iexpr $I 1
done
fi
log_notice mysqld restarted
done
# 完结撒花
log_notice mysqld from pid file $pid_file ended 相关资源mysql基础:mysqld_safe启动执行流程详解_mysqld_safe--usermysql...