由于最近找工作不是那么顺利,所以反思了一下可能是因为自己的知识也熟练程序还不够吧,所以决定一切从头再来,就像当初决定好好的学习一下Linux系统的基础知识一样。于是就将日常用的Windows换到Ubuntu下了,因为之前也已经在物理机上装了Linux系统,所以就 直接修改Grub就行了,这样就可以自动进入Linux系统了。
刚开始时,还不习惯,因为不知道要干什么,所以就不知道自己该怎么做了。于是就像往常一样浏览网页,更新系统(sudo apt-get update && sudo apt-get upgrade)。后来就发现输入法不是很好用(ibus不习惯),就装上了Fcitx,后来发现Fcitx可以用了,但有时网页的右键与工具栏却不能用了,所以到网上查找,得知是Fcix与Firfox的兼容性问题,主要出现在使用中文,日语等地区等也不太清楚。
刚开始时还是有点想回到Windows下,还在找一些Win7的主题(主要是看见Angle Beats 的主题太好了),所以就在网上下载了一些文件,可是这些文件下载后都得手动移动一下,当然了现在有GUI了,要方便些了,但我还是觉得这亲不是很方便,想自己写一个开机自启动的脚本文件,让我每次开机都可以自动挂载Windows下的一个经常用来存放下载文件的目录,到Linux下经常用来下载文件的、目录下的一个子目录中,于是就决心这样干了。。。。
于是问题就来了:由于之前还没写过一个像样的shell脚本文件,所以不知道格式,于是就参照了一下/etc/init.d/rc.locale的写法,内容大致如下:(Windows下的下载目录在另一个扩展分区中,Ubuntu也安装扩展分区中)
#! /bin/sh
### BEGIN INIT INFO
# Provides: filename
# Required-Start:
# Required-Stop:
# Default-Start: 3 5
# Default-Stop: 0 1 2 4 6
# Short-Description: mount a directory to a new place in Linux
# Description: mount / remount / umount the firectory. We mount the device firstly
# and then mount --rbind the directory ,the last we umount the device,so we can
# mount the directory to the download foldery not the hole partion.
### END INIT INFO
# mount the windows formate parttion to the linux,this directory store the things
# we download form the internet in Linux not in windows,maybe sometimes we need
# do this.
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin
. /lib/init/vars.sh
# . /lib/lsb/init-functions
# the vars we will use in the below functions
DEST_DEVICE=/mnt # the destination directory in the linux,not a device
DEST_DIR=/home/username/download_files/windows
SCR_DEVICE=/dev/sda5
SCR_DIR="$DEST_DEVICE"/TDDOWNLOAD/Linux-download
do_mount()
{
# echo "mounting ..../Linux_download to ~/download_files/windows" >&2
# test if the vars we defined correctly
# echo "vars:dest_device = ($DEST_DEVICE) dest_dir = ($DEST_DIR) \
# scr_device = ($SCR_DEVICE) scr_dir = ($SCR_DIR)"
mount -t ntfs "$SCR_DEVICE" "$DEST_DEVICE"
mount --bind "$SCR_DIR" "$DEST_DIR"
umount $DEST_DEVICE 2>/dev/null
}
do_remount()
{
# echo "remount ..../Linux_download to ~/download_files/windows" >&2
umount "$DEST_DIR" 2>/dev/null
umount "$DEST_DEVICE" 2>/dev/null
do_mount
}
do_unmount()
{
umount "$DEST_DIR" >/dev/null 2>&1
umount "$DEST_DEVICE" >/dev/null 2>&1
}
case $1 in
start)
do_mount
# to test if this script running at setup
# echo "my_auto.... running" >/home/username/abc
;;
restart)
do_remount
# echo "auto setup running again...." >/home/username/abc
;;
stop)
do_unmount
# rm -rf /home/username/abc >/dev/null 2>&1
exit 1
;;
reload|staue)
echo "Usage: $0 not surpot $1...using (start | restart | stop)" >&2
exit 2
;;
*)
echo "Usage: $0 start|restart|stop" >&2
exit 3
;;
esac
脚本的大致内容就是这样了,其实基于Debian 的系统的Init Script 都有一个固定的格式,也可以说是一个标准吧,毕竟如果没有一个统一的标准大家写的不一亲,可能对于系统维护人员可就难了。标准格式在这:LSB Init Scripts。在这篇文章中也有几个链接,这些链接都是与LSB相关的,也可以去看了一下,顺便就把英文给学习了一下。
上面代码中的一些注释可以用于测试用,如果遇到了一些不知道的问题,可以通过这些测试代码找到一些可能的原因,当初我就遇到脚本始终不运行的现象,后面会有原因说明与解决办法的。
Init script 它的格式大概是这样的:第一行以:#! /bash/sh开始。然后以下面的形式开始一些必要的描述(LSB要求的):
### BEGIN INIT INFO
# Provides: filename
# Required-Start:
# Required-Stop:
# Default-Start: start runlevel
# Default-Stop: stop runlevel
# Short-Description: short description
# Description: multiline description
# more decription.
### END INIT INFO
除了 Description 行可以有多行外,其它的行LSB建议只用一行(Description从第二行注释开始要求以“#”开始,紧随其后至少有2个空格或1个TAB)。然后就是LSB要求该脚本至少要提供:start, stop, restart, force-reload, status 这几个行为。当然也可以根据自己需要减少一些,但一般建议不要这么做。如果要用到一些变量可以将 /lib/init/vars.sh 包含进来(用:. /lib/init/vars.sh ),如果要使用一些函数可以将 /lib/lsb/init-functions 包含进来。
/lib/init/vars.sh 的大致内容如下:
#
# Set rcS vars
#
[ -f /etc/default/rcS ] && . /etc/default/rcS || true
# check for bootoption 'noswap' and do not activate swap
# partitions/files when it is set.
if [ -r /proc/cmdline ] && grep -qw 'noswap' /proc/cmdline ; then
NOSWAP=yes
else
NOSWAP=no
fi
# Accept the same 'quiet' option as the kernel
if [ ! -e /proc/cmdline ] || egrep -qw 'quiet' /proc/cmdline ; then
VERBOSE="no"
fi
# But allow both rcS and the kernel options 'quiet' to be overrided
# when INIT_VERBOSE=yes is used as well.
[ "$INIT_VERBOSE" ] && VERBOSE="$INIT_VERBOSE" || true
/lib/lsb/init-functions 的大致内容如下:
# /lib/lsb/init-functions for Debian -*- shell-script -*-
#
#Copyright (c) 2002-08 Chris Lawrence
#All rights reserved.
#
#Redistribution and use in source and binary forms, with or without
#modification, are permitted provided that the following conditions
#are met:
#1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#3. Neither the name of the author nor the names of other contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
#THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
#IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
#WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
#ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
#LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
#CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
#SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
#BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
#WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
#OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
#EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
start_daemon () {
local force nice pidfile exec i args
force=0
nice=0
pidfile=/dev/null
OPTIND=1
while getopts fn:p: opt ; do
case "$opt" in
f) force=1;;
n) nice="$OPTARG";;
p) pidfile="$OPTARG";;
esac
done
shift $(($OPTIND - 1))
if [ "$1" = '--' ]; then
shift
fi
exec="$1"; shift
args="--start --nicelevel $nice --quiet --oknodo"
if [ $force = 1 ]; then
/sbin/start-stop-daemon $args --chdir "$PWD" --startas $exec --pidfile /dev/null -- "$@"
elif [ $pidfile ]; then
/sbin/start-stop-daemon $args --chdir "$PWD" --exec $exec --oknodo --pidfile "$pidfile" -- "$@"
else
/sbin/start-stop-daemon $args --chdir "$PWD" --exec $exec -- "$@"
fi
}
pidofproc () {
local pidfile line i pids= status specified pid
pidfile=
specified=
OPTIND=1
while getopts p: opt ; do
case "$opt" in
p) pidfile="$OPTARG"; specified=1;;
esac
done
shift $(($OPTIND - 1))
base=${1##*/}
if [ ! "$specified" ]; then
pidfile="/var/run/$base.pid"
fi
if [ -n "${pidfile:-}" -a -r "$pidfile" ]; then
read pid < "$pidfile"
if [ -n "${pid:-}" ]; then
if $(kill -0 "${pid:-}" 2> /dev/null); then
echo "$pid"
return 0
elif ps "${pid:-}" >/dev/null 2>&1; then
echo "$pid"
return 0 # program is running, but not owned by this user
else
return 1 # program is dead and /var/run pid file exists
fi
fi
fi
if [ "$specified" = 1 ]; then
if [ -e "$pidfile" -a ! -r "$pidfile" ]; then
return 4 # pidfile exists, but unreadable, return unknown
else
return 3 # pidfile specified, but contains no PID to test
fi
fi
if [ -x /bin/pidof ]; then
status="0"
/bin/pidof -o %PPID -x $1 || status="$?"
if [ "$status" = 1 ]; then
return 3 # program is not running
fi
return 0
fi
return 4 # Unable to determine status
}
# start-stop-daemon uses the same algorithm as "pidofproc" above.
killproc () {
local pidfile sig status base i name_param is_term_sig
pidfile=
name_param=
is_term_sig=no
OPTIND=1
while getopts p: opt ; do
case "$opt" in
p) pidfile="$OPTARG";;
esac
done
shift $(($OPTIND - 1))
base=${1##*/}
if [ ! $pidfile ]; then
name_param="--name $base --pidfile /var/run/$base.pid"
else
name_param="--pidfile $pidfile"
fi
sig=$(echo ${2:-} | sed -e 's/^-\(.*\)/\1/')
sig=$(echo $sig | sed -e 's/^SIG\(.*\)/\1/')
if [ -z "$sig" -o "$sig" = 15 -o "$sig" = TERM ]; then
is_term_sig=yes
fi
status=0
if [ ! "$is_term_sig" = yes ]; then
if [ -n "$sig" ]; then
/sbin/start-stop-daemon --stop --signal "$sig" --quiet $name_param || status="$?"
else
/sbin/start-stop-daemon --stop --quiet $name_param || status="$?"
fi
else
/sbin/start-stop-daemon --stop --quiet --oknodo $name_param || status="$?"
fi
if [ "$status" = 1 ]; then
if [ -n "$sig" ]; then
return 0
fi
return 3 # program is not running
fi
if [ "$status" = 0 -a "$is_term_sig" = yes -a "$pidfile" ]; then
pidofproc -p "$pidfile" "$1" >/dev/null || rm -f "$pidfile"
fi
return 0
}
# Return LSB status
status_of_proc () {
local pidfile daemon name status
pidfile=
OPTIND=1
while getopts p: opt ; do
case "$opt" in
p) pidfile="$OPTARG";;
esac
done
shift $(($OPTIND - 1))
if [ -n "$pidfile" ]; then
pidfile="-p $pidfile"
fi
daemon="$1"
name="$2"
status="0"
pidofproc $pidfile $daemon >/dev/null || status="$?"
if [ "$status" = 0 ]; then
log_success_msg "$name is running"
return 0
elif [ "$status" = 4 ]; then
log_failure_msg "could not access PID file for $name"
return $status
else
log_failure_msg "$name is not running"
return $status
fi
}
log_use_fancy_output () {
TPUT=/usr/bin/tput
EXPR=/usr/bin/expr
if [ -t 1 ] && [ "x${TERM:-}" != "x" ] && [ "x${TERM:-}" != "xdumb" ] && [ -x $TPUT ] && [ -x $EXPR ] && $TPUT hpa 60 >/dev/null 2>&1 && $TPUT setaf 1 >/dev/null 2>&1; then
[ -z $FANCYTTY ] && FANCYTTY=1 || true
else
FANCYTTY=0
fi
case "$FANCYTTY" in
1|Y|yes|true) true;;
*) false;;
esac
}
log_success_msg () {
if [ -n "${1:-}" ]; then
log_begin_msg $@
fi
log_end_msg 0
}
log_failure_msg () {
if [ -n "${1:-}" ]; then
log_begin_msg $@ "..."
fi
log_end_msg 1 || true
}
log_warning_msg () {
if [ -n "${1:-}" ]; then
log_begin_msg $@ "..."
fi
log_end_msg 255 || true
}
#
# NON-LSB HELPER FUNCTIONS
#
# int get_lsb_header_val (char *scriptpathname, char *key)
get_lsb_header_val () {
if [ ! -f "$1" ] || [ -z "${2:-}" ]; then
return 1
fi
LSB_S="### BEGIN INIT INFO"
LSB_E="### END INIT INFO"
sed -n "/$LSB_S/,/$LSB_E/ s/# $2: \(.*\)/\1/p" $1
}
# int log_begin_message (char *message)
log_begin_msg () {
if [ -z "${1:-}" ]; then
return 1
fi
echo -n "$@"
}
# Sample usage:
# log_daemon_msg "Starting GNOME Login Manager" "gdm"
#
# On Debian, would output "Starting GNOME Login Manager: gdm"
# On Ubuntu, would output " * Starting GNOME Login Manager..."
#
# If the second argument is omitted, logging suitable for use with
# log_progress_msg() is used:
#
# log_daemon_msg "Starting remote filesystem services"
#
# On Debian, would output "Starting remote filesystem services:"
# On Ubuntu, would output " * Starting remote filesystem services..."
log_daemon_msg () {
if [ -z "${1:-}" ]; then
return 1
fi
log_daemon_msg_pre "$@"
if [ -z "${2:-}" ]; then
echo -n "$1:"
return
fi
echo -n "$1: $2"
log_daemon_msg_post "$@"
}
# #319739
#
# Per policy docs:
#
# log_daemon_msg "Starting remote file system services"
# log_progress_msg "nfsd"; start-stop-daemon --start --quiet nfsd
# log_progress_msg "mountd"; start-stop-daemon --start --quiet mountd
# log_progress_msg "ugidd"; start-stop-daemon --start --quiet ugidd
# log_end_msg 0
#
# You could also do something fancy with log_end_msg here based on the
# return values of start-stop-daemon; this is left as an exercise for
# the reader...
#
# On Ubuntu, one would expect log_progress_msg to be a no-op.
log_progress_msg () {
if [ -z "${1:-}" ]; then
return 1
fi
echo -n " $@"
}
# int log_end_message (int exitstatus)
log_end_msg () {
# If no arguments were passed, return
if [ -z "${1:-}" ]; then
return 1
fi
retval=$1
log_end_msg_pre "$@"
# Only do the fancy stuff if we have an appropriate terminal
# and if /usr is already mounted
if log_use_fancy_output; then
RED=`$TPUT setaf 1`
YELLOW=`$TPUT setaf 3`
NORMAL=`$TPUT op`
else
RED=''
YELLOW=''
NORMAL=''
fi
if [ $1 -eq 0 ]; then
echo "."
elif [ $1 -eq 255 ]; then
/bin/echo -e " ${YELLOW}(warning).${NORMAL}"
else
/bin/echo -e " ${RED}failed!${NORMAL}"
fi
log_end_msg_post "$@"
return $retval
}
log_action_msg () {
echo "$@."
}
log_action_begin_msg () {
echo -n "$@..."
}
log_action_cont_msg () {
echo -n "$@..."
}
log_action_end_msg () {
log_action_end_msg_pre "$@"
if [ -z "${2:-}" ]; then
end="."
else
end=" ($2)."
fi
if [ $1 -eq 0 ]; then
echo "done${end}"
else
if log_use_fancy_output; then
RED=`$TPUT setaf 1`
NORMAL=`$TPUT op`
/bin/echo -e "${RED}failed${end}${NORMAL}"
else
echo "failed${end}"
fi
fi
log_action_end_msg_post "$@"
}
# Hooks for /etc/lsb-base-logging.sh
log_daemon_msg_pre () { :; }
log_daemon_msg_post () { :; }
log_end_msg_pre () { :; }
log_end_msg_post () { :; }
log_action_end_msg_pre () { :; }
log_action_end_msg_post () { :; }
FANCYTTY=
[ -e /etc/lsb-base-logging.sh ] && . /etc/lsb-base-logging.sh || true
如果用不到里面的东西可以不包含这两个文件,一般为了防止不知为什么的错误还是可以包含进来的,当然适合才是最好的。
最后是最关键的就是写自己的实现过程中,这里面一般都是用 case ... esac 来实现功能,而在这个循环中,又一般的用前面我们已经定义好的一些诸如: do_start, process_options之类的函数进行实现,函数名一般都是:动作_动词 或动作_状态 等能说明目的的名称,就像C语言中的函数命名一样。
一个Init script 大概的内容就是这样的了。当然复杂的脚本文件一般都是有安全性检查与文件存在性的测试等,我这个脚本只是实现一个简单的挂载目录功能,完全可以手动完成的。。^_^。所以就方便了。
假设我们现在已经写好了一个 shell 脚本,保存,在终端中运行 :sh -n filename试运行一下,看一下有没有语法上的错误,如果没有,可以再次运行命令:shell -v filename 看一下脚本执行的一个大致过程与我们预想的是不是一样的。如果不一样那么就要修改了。
假设现在我们的脚本文件没有语法上的问题,也满足我们的要求了,也就是一切都是正常的,那么现在就可以将它“安装”到系统中了。利用 ubuntu 下的 update-rc.d 命令可以将我们写的脚本文件“安装”到正确的位置(注:因为我不知道其它的系统下是否提供 update-rc.d 的命令,所以这里先这样做)。Ubuntu 系统下以 root 身份运行 "update-rc.d filename start NN runlevels . stop NN runlevels ."或运行:“sudo update-rc.d filename start NN runlevels . stop NN runlevels .”。注意里面的点号,前后都要有一个空格,一共有两个点号。其中NN为启动时的顺序,数字越小就越早运行。runlevels可以是多个运行级别,多个运行级时之间用空格分开。如果是在基于Debian 的系统,这里要特点注意一下:基于Debian 的系统运行级别:2~5都是一样的,都是有GUI的多用户的环境,这与Linux 标准不完全一样,所以在决定脚本在哪个运行级别下启动或停止时要特点注意运行级别。之前我的系统(ubuntu 10.04)的运行级别就是2,不管我怎么修改都不能实现脚本的功能,后来将其加入到 rc.local 中就可以,但也没有满足我的需求啊。(注:可以用:who -r命令查看系统的运行级别也可以用 runlevel)。于是我就将运行级别改为5(利用:sudo init 5 可以马上临时修改运行级别,如果要“永久性”的修改运行级别可以修改:/etc/init/rc-sysinit.conf中的第14行的:env DEFAULT_RUNLEVEL=2 将2改为5即可,其它系统可以先查看:/etc/inittab文件中是否有:id:3:initdefault:之类的描述,将3改为想运行的运行级别即可),然后呢就成功了。。^_^
运行 update-rc.d 后会出现警告消息,大致意思是说:你的脚本文件与LSB的标准不是完全相同,主要就是在运行级别上。比如前面我的这个脚本只在运行级别为3与5的情况下运行,而不是2,3,4,5所以它会给出警告消息。不用管也不会存在什么 问题。
如果系统中没有 update-rc.d 命令可以手动用 ln -s建立软链接到相应的目录(具体用法查看 man手册。)。比如:
cd /etc/rc5.d
sudo ln -s ../init.d/filename S99filename
这样也可以达到我们的目的(让系统帮我们启动脚本运行,^_^),只是现在我还不知道在其它系统上有没有 update-rc.d 的命令,如果没有除了前面用的那个命令外,我就不知道其它的比较方便的方法了。^@^。
由于现在才开始学习 Linux 的一些基础的东西 ,所以难免文章里面有很多地方写的不是很好,希望知道的朋友斧正。。。^_^.……
学习新东西并不难,难于在不愿意去尝试,只要愿意去尝试,就有可能自己解决问题,如果没有尝试就认为会失败或是 完成不了,那么就真的完成不了。。