1.变量中字符的长度: ${#VARNAME}
2.变量赋值等:
${parameter:-word}:如果parameter为空或未定义,则变量展开为"word";否则,展开为parameter的值;
${parameter:+word}:如果parameter为空或未定义,不做任何操作;否则,则展开为"word"值;
${parameter:=word}:如果parameter为空或未定义,则变量展开为"word",并将展开后的值赋值给parameter;
${parameter:offset}
${parameter:offset:length}:取子串,从offset处的后一个字符开始,取length长的子串;
cross compile:交叉编译
使用当前主机编译符合目标主机特征的编译方式,叫做交叉编译。
make ARCH=
mktemp 命令
创建临时文件或目录
mktemp /tmp/file.XX # 创建一个临时文件,XX的个数就是生成随机数的个数,不重复;
mktemp -d /tmp/file.XXXX # 创建一个临时目录
trap命令
EXIT:在shell退出前执行trap设置的命令,也可以指定为0
RETURN:在函数返回时,或者.和source执行其他脚本返回时,执行trap设置的命令
DEBUG:在任何命令执行前执行trap设置的命令,但对于函数仅在函数的第一条命令前执行一次
trap -l:列出所有信号的数值和名字,类似于kill -l
trap -p:列出通过trap设置的信号处理命令。
trap可以在收到信号前的任意位置设置,并非需要在脚本的第一行,但是shell是按照顺序执行语句的,不会优先执行trap
kill -SIGNAL PID
1:HUP
2:INT
9:KILL
15:TERM
脚本中,能实现信号捕捉,但9和15无法捕捉
Ctrl+c: SIGINT
trap命令:
trap 'COMMAND' 信号列表
#!/bin/bash
#
NET=192.168.1
FILE=`mktemp /tmp/file.XXXX`
clearup() {
echo "quit..."
exit 1
}
trap 'clearup' INT # trap 'clearup;exit 1' INT 一行执行多个语句,多个与巨剑用分号分隔。
for I in {0..20};do
if ping -c 1 -W 3 $NET.$I &> /dev/null;then
echo "$NET.$I is up." | tee >>$FILE
else
echo "$NET.$I is down."
fi
done
任务计划
at和batch
1.再未来的某个时间点执行一次某任务
安装at: yum install -y at
systemctl start atd
at 时间
at> COMMAND
at> Ctrl+d # 提交任务
指定时间:
绝对时间:HH:MM, DD.MM.YY MM/DD/YY
相对时间: now+# # now+3minutes
模糊时间:noon,midnight,teatime(1600)
命令的执行结果:将以邮件的形式发送给安排任务的用户
at -l =atq # 查看当前任务列表
at -d AT_JOB_ID = atrm AT_JOB_ID
batch: 自动选择机器在较空间的时间执行任务,因此不需要指定时间。其他用法和at一样。
可以对用户设定使用at任务计划的权限,具体参照 man at.allow
cron
周期性地执行某任务
cron:自身是一个不间断运行的服务
anacron:cron的补充,能够实现让cron因为各种原因在过去的时间该执行而未执行的任务在恢复正常执行一次;
cron:
系统cron任务:和用户没有关系,是系统为了周期性地维护或运行某个任务而安排的,比如清理/tmp目录、locate命令的执行。
/etc/crontab # 一共有7个段,5个段指时间,1一个段指用户,1个段指要运行的任务。每个段用空格隔开
分钟 小时 天 月 周 用户 任务
用户cron任务:
/var/spool/cron/USERNAME # 一共有6个段,5个段指时间,1个段指要运行的任务,不需要指用户
分钟 小时 天 月 周 任务
时间的有效取值范围:
分钟:0-59
小时:0-23
天:1-31
月:1-12
周:0-7,0和7都表示周日
时间通配表示:
*:对应的所有有效取值
3 * * * * # 表示每个小时的第3分钟
3 * * * 7 # 每个礼拜日每个小时的第3分钟
13 12 * * 5 # 表示每周五的12点13分钟
13 12 6 * * # 表示每月的6号中午12点13分钟执行
13 12 6 * 3 # 表示每月的6号 必须是周三的12点13分钟。 一般日和周单独使用
13 12 6 7 * # 表示每年的7月6号中午的12点13分
,:离散时间点:
10,40 * * * * # 表示每小时的第10分钟和第40分钟各执行一次,即半小时任务
10,40 * * 2,5 # 表示每周二和周五每小时的第10分钟和第40分钟各执行一次
10,40 02 * 2,5 # 表示每周二和周五的凌晨两点的第10分钟和第40分钟各执行一次
-:连续时间点:
10 02 * * 1-5 # 表示每周的周一到周五的陵城两点的第10分钟各执行一次
/#:对应取值范围内每多久一次
*/3 * * * * # 表示每3分钟一次的任务
每两小时执行一次:
08 */2 * * *
每两天执行一次:
10 04 */2 * *
与at一样,执行结果将以邮件形式发送给管理员;任务的执行结果有错误才发邮件。
*/3 * * * * cat /etc/fstab > /dev/null 2>out.txt
cron的环境变量:cron执行所有命令都去PATH环境变量指定的路径下去找。
PATH /bin:/sbin://usr/bin:/usr/sbin
在使用cron执行周期性任务的时候,可能用户没有登录,就不能以用户的身份运行周期性任务,此时就不能使用用户下的环境变量,所以在执行脚本时,可以使用命令的绝对路径去导出环境变量:
#!/bin/bash
#
export PATH=
周期任务列表:
# 系统cron任务
vim /etc/crontab
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
HOME=/
# run-parts 如果希望run-parts 对以下目录中中的任务有先后次序的执行,在创建文件时在文件名的前面加数字表示先后次序 比如: 0anacron 01logwatch
01 * * * * root run-parts /etc/cron.hourly
02 4 * * * root run-parts /etc/cron.daily
22 4 * * 0 root run-parts /etc/cron.weekly
42 4 1 * * root run-parts /etc/cron.monthly
# 用户cron任务
crontab:
-l # 列出当前用户所有的计划任务
-e # 编辑任务 专门编辑crontab任务,会在当前目录中生成一个当前登录用户名同名的文件,也可以vim 用户名,进去再编辑crontab任务,但是容易出错。建议 crontab -e
-u USERNAME # 管理其他用户
crontab -u hadoop -e # 以hadoop用户的身份编辑定时任务
cd /var/spool/cron
crontab -e #
*/3 * * * * /bin/echo "how are you?"
crontab -r # 删除/var/spool/cron 目录中的所有任务,文件将被删除。
anacron:
cat /etc/anacrontab
[root@zhang ~]# cat /etc/anacrontab
# /etc/anacrontab: configuration file for anacron
# See anacron(8) and anacrontab(5) for details.
SHELL=/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
# the maximal random delay added to the base delay of the jobs
RANDOM_DELAY=45
# the jobs will be started during the following hours only
START_HOURS_RANGE=3-22
#period in days delay in minutes job-identifier command
1 5 cron.daily nice run-parts /etc/cron.daily
7 25 cron.weekly nice run-parts /etc/cron.weekly
@monthly 45 cron.monthly nice run-parts /etc/cron.monthly
1,7,@monthly:表示过去一天没有执行了,7代表七天没执行过了,@monthly表示过去一个月没有执行过了
5,25,45:表示在开机以后第多少分钟执行
anacron任务最小精确到天,而cron任务能精确到分钟。无论是cron还是anacron任务,都务必确保cron服务(crond systemctl status crond)或anacron服务是运行的
小系统制作
which run-parts
/usr/bin/run-parts
cat `which run-parts`
#!/bin/bash
# run-parts - concept taken from Debian
# keep going when something fails
set +e # 表示在执行脚本的过程中如果出现异常时(return 1),自动退出。
if [ $# -lt 1 ]; then
echo "Usage: run-parts [--list | --test] <dir>"
exit 1
fi
while [ $# -gt 1 ]; do
case $1 in
--list)
list=1
shift
break
;;
--test)
test=1
shift
break
;;
--)
# -- end of options
shift
break
;;
*)
# directory
break
;;
esac
done
if [ ! -d $1 ]; then
echo "Not a directory: $1"
exit 1
fi
if [ -f /etc/sysconfig/run-parts ]; then
. /etc/sysconfig/run-parts
fi
# Ignore *~ and *, scripts
for i in $(LC_ALL=C; echo ${1%/}/*[^~,]) ; do
[ -d $i ] && continue
# Don't run *.{rpmsave,rpmorig,rpmnew,swp,cfsaved} scripts
[ "${i%.cfsaved}" != "${i}" ] && continue
[ "${i%.rpmsave}" != "${i}" ] && continue
[ "${i%.rpmorig}" != "${i}" ] && continue
[ "${i%.rpmnew}" != "${i}" ] && continue
[ "${i%.swp}" != "${i}" ] && continue
[ "${i%,v}" != "${i}" ] && continue
# jobs.deny prevents specific files from being executed
# jobs.allow prohibits all non-named jobs from being run.
# can be used in conjunction but there's no reason to do so.
if [ -r $1/jobs.deny ]; then
grep -q "^$(basename $i)$" $1/jobs.deny && continue
fi
if [ -r $1/jobs.allow ]; then
grep -q "^$(basename $i)$" $1/jobs.allow || continue
fi
if [ -e $i ]; then
if [ -r $1/whitelist ]; then
grep -q "^$(basename $i)$" $1/whitelist && continue
fi
if [ ${list:-0} = 1 ]; then
echo $i;
elif [ -x $i ]; then
if [ ${test:-0} = 1 ]; then
echo $i;
continue
fi
if [ "$RANDOMIZE" != "" ]; then
let "rtime = $RANDOM"
if [ "$RANDOMTIME" != "" ]; then
let "rtime %= $RANDOMTIME"
else
let "rtime %= 300"
fi
sleep $rtime
fi
# run executable files
logger -p cron.notice -t "run-parts($1)[$$]" "starting $(basename $i)"
$i 2>&1 | awk -v "progname=$i" \
'progname {
print progname ":\n"
progname="";
}
{ print; }'
logger -i -p cron.notice -t "run-parts($1)" "finished $(basename $i)"
fi
fi
done
exit 0
Kernel + initrd(busybox制作,提供ext3文件系统模块) + ROOTFS(busybox制作)
make arch/
arch/x86/boot/bzImage
硬件驱动:initrd
initrd:仅需要提供黑河访问真正的根文件系统所在设备需要的驱动
存储设备和文件系统相关的模块
系统初始化rc.sysinit:初始其它硬件驱动程序;
ROOTFS:busybox,init不支持运行级别
/etc/inittab:格式也不尽相同
vim init
#!/bin/sh
#
echo "mounting proc and sys..."
mount -t proc proc /proc
mount -t sysfs sysfs /sys
echo "Load ext3 module..."
insmod /lib/modules/jbd.ko
insmod /lib/modules/ext3.ko
echo "Detect and export hardware information"
mdev -s
echo "Mount real rootfs to /mnt/sysroot..."
mount -t ext3 /dev/hda2 /mnt/sysroot
echo "Switch to read rootfs..."
exec switch_root /mnt/sysroot /sbin/init
chmod +x init
modinfo jbd
/lib/modules/2.6.18-308.el5/kernel/fs/jbd/jbd.ko
modinfo ext3
/lib/modules/2.6.18-308.el5/kernel/fs/ext3/ext3.ko
cp /lib/modules/2.6.18-308.el5/kernel/fs/jbd/jbd.ko lib/modules # 模块的版本一定要和内核版本一致,即使用内核编译之后的模块
cp /lib/modules/2.6.18-308.el5/kernel/fs/ext3/ext3.ko lib/modules
find . | cpio -H newc --quiet -o | gzip -9 > /mnt/boot/initrd.gz
vim /mnt/boot/grub/grub.conf
default=0
timeout=3
title ChaoZhang Tiny Linux (2.6.18)
root(hd0,0)
kernel /vmlinuz ro root=/dev/hda2
initrd /initrd.gz
cp -a busybox-1.20.2/_install/* /mnt/sysroot/ # /mnt/sysroot是制作的系统的真正的根
cd /mnt/sysroot
ls
bin linuxrc sbin usr
rm linuxrc
mkdir boot root etc/rc.d/init.d var/{log,lock,run} proc sys dev lib/modules tmp home mnt media -pv
mknod dev/console c 5 1
mknod dev/null c 1 3
vim etc/inittab
::sysinit:/etc/rc.d/rc.sysinit
console::respawn:-/bin/sh
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
vim etc/rc.d/rc.sysinit
#!/bin/bash
#
echo -e "\tWelcome to \033[34mChaoZhang Tiny\033[0m Linux"
echo "Remount the rootfs..."
mount -t ext3 -o remount,rw /dev/hda2 /
echo "Mount the other filesystem..."
mount -a
chmod +x etc/rc.d/rc.sysinit
vim /etc/fstab
sysfs /sys sysfs defaults 0 0
proc /proc proc defaults 0 0
/dev/hda1 /boot ext3 defaults 0 0
/dev/hda2 / ext3 defaults 1 1
sync
启动小系统
报错:
mount:mounting /dev/hda1 on /boot failed:No such file or directory.
ls /dev
console null
实际上 /boot目录我们在/mnt/sysroot已经创建,说明没有hda1,我们真正的根没有切换过来。小系统上的/dev没有切换过来,所以在 vim etc/rc.d/rc.sysinit 时,mdev -s 这一步不能少。
vim etc/rc.d/rc.sysinit
#!/bin/bash
#
echo -e "\tWelcome to \033[34mChaoZhang Tiny\033[0m Linux"
echo "Remount the rootfs..."
mount -t ext3 -o remount,rw /dev/hda2 /
echo -e "Creating the files of device..."
mdev -s
echo "Mount the other filesystem..."
mount -a
启动小系统
报错:
mount:mounting /dev/hda1 on /boot failed:No such file or directory.
说明busybox提供的switch-root命令和红帽提供的根切换的命令不一样,这个命令没办法将小系统的proc、dev和sys目录都搬过来,但是红帽的可以。所以还需要重新挂载proc、dev、sys
vim etc/rc.d/rc.sysinit
#!/bin/bash
#
echo -e "\tWelcome to \033[34mChaoZhang Tiny\033[0m Linux"
echo "mount proc and sys..."
mount -t proc proc /proc
mount -t sysfs sysfs /sys
echo "Remount the rootfs..."
mount -t ext3 -o remount,rw /dev/hda2 /
echo "Mount the other filesystem..."
mount -a
sync
重启小系统
正常
ls /dev # 都是mdev自动创建的
ls /proc
ls /sys
更换sh到bash
./bincp.sh
bash
chroot /mnt/sysroot
cd bin/
查看到
sh-->busybox
我们需要将bash-->busybox , 但是一般不要更改busybox默认的sh,我们可以修改 etc/inittab:
console::respawn:-/bin/sh --> console::respawn:-/bin/bash
给小系统提供账号密码:
grep -E "^root:" /etc/passwd >/mnt/sysroot/etc/passwd
grep -E "^root:" /etc/shadow >/mnt/sysroot/etc/shadow
grep -E "^root:" /etc/group >/mnt/sysroot/etc/group
ls /mnt/sysroot/etc/
chmod 400 /mnt/sysroot/etc/shadow
查看/mnt/sysroot/etc/passwd文件中root用户使用的shell:
root:x:0:0:root:/root:/bin/bash
如果小系统没有移植bash,那这里就需要改成/bin/sh,不然用户登录不了
sync
vim /etc/inittab # 删除console行 并编辑两个虚拟终端 tty
::sysinit:/etc/rc.d/rc.sysinit
::respawn:/sbin/getty 9600 tty1
::respawn:/sbin/getty 9600 tty2
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
sync
希望登录的时候有主机名:
vim /mnt/sysroot/etc/hostname
HOSTNAME=tiny.ChaoZhang.com
vim /mnt/sysroot/etc/inittab
echo "Set the hostname..."
[ -f /etc/hostname ] && . /etc/hostname
[ -z "$HOSTNAME" -o "$HOSTNAME" == '(none)' ] && HOSTNAME=localhost
hostname=$HOSTNAME
vim /mnt/sysroot/etc/issue # 启动系统终端最先显示的信息
cp /etc/issue /mnt/sysroot/etc
sync
find . | cpio -H newc --quiet -o | gzip > /root/tiny.1.gz
du -sh /root/tiny.1.gz # 压缩后就几兆的大小
报错:
EXT3-fs error (device hda2):ext3_lookup:unlinked inode 76917 in dir #76917 ext3_abort called.
EXT3-fs error (device hda2):ext3_journal_start_sb:Detected aborted journal Remounting filesystem read-only
umount /mnt/sysroot
mke2fss -j /dev/hda2
mount /dev/hda2 /mnt/sysroot
cd /mnt/sysroot
zcat /root/tiny.1.gz cpio -id
sync
# 能够装载网卡,提供网卡驱动,提供IP
cd /mnt/sysroot
modinfo mii
/lib/modules/2.6.18-308.el5/kernel/drivers/net/mii.ko
modinfo pcnet32
/lib/modules/2.6.18-308.el5/kernel/drivers/net/pcnet32.ko
cp /lib/modules/2.6.18-308.el5/kernel/drivers/net/mii.ko
modinfo pcnet32 lib/modules
cp /lib/modules/2.6.18-308.el5/kernel/drivers/net/pcnet32.ko lib/modules
vim etc/inittab
# 在所有设备都探测好以后,再装载驱动
echo "Load ethernet card module..."
insmod /lib/modules/mii.ko
insmod /lib/modules/pcnet32.ko
ifconfig ens1 172.16.100.13/16
ifconfig lo 127.0.0.1/8