#!/bin/sh
# dtree: Usage: dtree [any directory]
dir=${1:-.}
(cd $dir; pwd)
find $dir -type d -print | sort -f | sed -e "s,^$1,," -e "/^$/d" -e "s,[^/]*/([^/]*)$,`----1," -e "s,[^/]*/,| ,g"
2 while中使用read (file是一个文件)
cat file | while read line
do
echo $line
echo " :: Please input any key(s):c"
str4read=""
while true
do
chr4read=`dd if=/dev/tty bs=1 count=1 2>/dev/null`
str4read=$str4read$chr4read
if [ "$chr4read" = "" ] ;then break; fi
done
echo " :: |$str4read|"
done
3 将多个空格替换为字符
sed 's/[ ][ ]*/ /g'
如果空格与tab共存时用
sed -e 's/[[:space:]][[:space:]]*/ /g' filename
4用脚本实现分割文件
#!/bin/bash
if [ $# -ne 2 ]; then
echo 'Usage: split file size(in bytes)'
exit
fi
file=$1
size=$2
if [ ! -f $file ]; then
echo "$file doesn't exist"
exit
fi
#TODO: test if $size is a valid integer
filesize=`/bin/ls -l $file | awk '{print $5}'`
echo filesize: $filesize
let pieces=$filesize/$size
let remain=$filesize-$pieces*$size
if [ $remain -gt 0 ]; then
let pieces=$pieces+1
fi
echo pieces: $pieces
i=0
while [ $i -lt $pieces ];
do
echo split: $file.$i:
dd if=$file of=$file.$i bs=$size count=1 skip=$i
let i=$i+1
done
echo "#!/bin/bash" > merge
echo "i=0" >> merge
echo "while [ $i -lt $pieces ];" >> merge
echo "do" >> merge
echo " echo merge: $file.$i" >> merge
echo " if [ ! -f $file.$i ]; then" >> merge
echo " echo merge: $file.$i missed" >> merge
echo " rm -f $file.merged" >> merge
echo " exit" >> merge
echo " fi" >> merge
echo " dd if=$file.$i of=$file.merged bs=$size count=1 seek=$i" >> merge
echo " let i=$i+1" >> merge
echo "done" >> merge
chmod u+x merge'
5得到上月未日期,格式为YYYYMMDD
get_lastday_of_lastmonth()
{
yy=`date +%Y`
mm=`date +%m-1|bc`
[ $mm -lt 1 ] && mm=12;yy=`expr $yy - 1`
aaa=`cal $mm $yy`
dd=`echo $aaa|awk '{print $NF}'`
echo $yy$mm$dd
}
print $NF的$NF是打印最后一个列。因为awk的内置变量NF是列的总数,而$NF就代表着最后一列
6 实现用backup或tar命令来做目录备份
需要保持两个目录当中的文件以及属组关系不变。子目录结构不变,通过管道控制tar和backup命令,不需要中间的archive,(考虑到速度以及空间的关系)
(cd /source && tar cf - .) |(cd /dest && tar zxfp -)
偶没有 backup 命令,但是 tar 用管道可以,
tar -cf - dir1 | ( cd dir2; tar -xvf - )
搬移大法
more aaa.sh
#计算两个日期间有多少天
#date1,date2:yyyymmdd
#Usage:command date1 date2
str=$1
yy1=`echo $str|cut -c 1-4`
mm1=`echo $str|cut -c 5-6`
dd1=`echo $str|cut -c 7-8`
str=$2
yy2=`echo $str|cut -c 1-4`
mm2=`echo $str|cut -c 5-6`
dd2=`echo $str|cut -c 7-8`
count_day=`expr $dd2 - $dd1`
while [ $yy2 -ne $yy1 -o $mm2 -ne $mm1 ]
do
mm2=`expr $mm2 - 1`
[ $mm2 -eq 0 ] && mm2=12 && yy2=`expr $yy2 - 1`
aaa=`cal $mm2 $yy2`
bbb=`echo $aaa|awk '{print $NF}'`
count_day=`expr $count_day + $bbb`
done
echo $count_day
7 编写一个只允许用户执行telnet的shell
为了监视用户网络操作行为,指定unxi主机给设备管理员登陆,然后用shell控制他。只可以使用telnet命令,其他一概不许,包括cd,ls等。就是一个用来远程登陆的管理平台。我对shell不熟,请指导。
.profile中加入:
read addr
telnet $addr
exit
8 判断文件的访问权限是不是600
ls -l filename | awk '{ if($1 ~ "-rw-------") ..... }'
ls -l filename | grep "^-rw------" -c
#!/usr/bin/bash
#showmod
[ $# -eq 0 ] && { echo "Usage: $0 filelist ... "; exit ;}
show()
{
{ [ -d $1 ] && ls -ld $1 ; [ -f $1 ] && ls -la $1 ;} | awk '{
umask=0
umask_=""
for(i=1;i<length($1);i++)
{
if(substr($1,i+1,1)=="r")
umask+=4;
if(substr($1,i+1,1)=="w")
umask+=2;
if(substr($1,i+1,1)=="x")
umask+=1;
if(i%3==0)
{
umask_=sprintf("%s%d",umask_,umask);
umask=0;
}
}
printf("%-20.20s: %-10.10s --> %s ",$9,$1,umask_);
}';
}
for file_dir in $*
do
show $file_dir
done
9 算青蛙的脚本
maxcount=$1;
count=1;
if [ $# -eq 1 ]
then
while [ $count -le $maxcount ]
do echo $count 只青蛙 $count 张嘴, `expr $count * 2`只眼睛,`expr $count * 4`条腿;
count=`expr $count + 1`;
done;
else
echo "usage: sendos count"
fi
10 在SHELL程序中实现‘按任意键继续’
在写一个SHELL程序,可是遇到了一个难题,在READ接受输入时,必须按回车键才能确认,而我需要只要按一个键就能得到用户的输入,无须按回车键!有什么好办法呢
#!/bin/sh
get_char()
{
SAVEDSTTY=`stty -g`
stty -echo
stty raw
dd if=/dev/tty bs=1 count=1 2> /dev/null
stty -raw
stty echo
stty $SAVEDSTTY
}
echo "Press any key to continue..."
char=`get_char`
如果你的机器上不认stty raw那么把函数中两处出现的raw换成cbreak。
11 在linux环境下启动时打开numlock
想在系统启动时自动打开NumLock,可以在/etc/rc.d/rc.local中加入以下内容:
for t in 1 2 3 4 5 6 7 8
do
setleds +num
$t>/dev/null
done
12 在shell里如何限制输入的长度
举个例子,比如用户输入用户名时只能给他输入8个字符,如果超过了8个字符光标就停止在第八个字符那儿,不继续,一直等待回车只怕要自己来另写一个SHELL了。
我现在可以实现到如果输入超出的话光标就停在最后一个字符,但是对于那些输入小于规定位数的那些就没折了,举个例子,比如用户域最长不能超过8位,我输入了6位然后回车,就不会结束,一定要输入完8位按回车才可以结束
文件名: input.sh 用法:input.sh 限制的长度
例:input.sh 8 即限制输入8位。
#!/bin/ksh
# Program Name : input.sh
trap '' 1 2 3 5 7 9 15 13
getcon(){
stty raw -echo
conchar=`dd if=/dev/tty bs=1 count=1 2>/dev/null`
stty sane
echo "$conchar"
}
while
i=0;clear >/dev/tty
echo "
13 双机(多机)自动互备份方案
问 题:
公司有两台LINUX服务器,每个服务器只有一个硬盘。所以备份的问题就显得特别重要。我们装有MySQL数据库。当然同时也要解决MySQL备份的问题。
目 的:
host 机器最终所有备份都在其上留备份,ship机器保存host机器备份
方 法:
通过shell脚本,打包相关要备份的文件。然后通过ftp操作下载,上载完成解决方案。
两台机器root 通过crontab 让脚本在各自机器定时执行。
建议host 每天早上3点执行。
建议ship 每天早上6点执行。
注意点:
两台服务器系统时间最好相差不要超过1小时。
此脚本是每周礼拜6执行备份的。当然你也可以修改成每月或每天备份。
当然也可以修改成一个增量备份脚本。
具体脚本:
以下为host机器脚本
#//////////////host机器脚本///////////////
#! /bin/sh
HOST="abc.com"
USER="backup_use" #ship机器backup_use用户
PASSWORD="backup_use" #ship机器对应用户密码
BACKUPDIR="/home/backup_use/ship" #host机器backup_use用户目录
BACKUPDIR2="/home/backup_use/host" #host机器backup_use用户目录
MYSQLPASS="abc" #ship 机器MySQL root 用户密码
PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/nusphere/MySQL/bin
DOW=`date +%a`
DM=`date +%Y%b%d`
FILE1=ship-virtual-$DM.tar.gz
FILE2=ship-MySQLdata-$DM.tar.gz
FILE3=ship-szeasy-$DM.tar.gz
FILE4=ship-other-$DM.tar.gz
#
FIL1=$BACKUPDIR2/host-main-$DM.tar.gz
FIL2=$BACKUPDIR2/host-MySQLdata-$DM.tar.gz
FIL3=$BACKUPDIR2/host-other-$DM.tar.gz
#
DIRECTORIE1="/www /home/jjd" # 要备份的目录1
DIRECTORIE2="/etc /var/named /usr/local/nusphere/apache/conf" # 要备份的目录2
#
if [ $DOW = "Sat" ]; then # 每个礼拜六完全备份
tar -zcpf $FIL1 $DIRECTORIE1
tar -zcpf $FIL3 $DIRECTORIE2
MySQLdump --all-databases -q -uroot -p$MYSQLPASS |gzip > $FIL2
ftp -i -n < $BACKUPDIR/$COMPUTER-MySQLdata-$DM.tar.gz
fi
14 文件序列a1,a2,a3...a11,a12...a1000改成a0001,a0002...a1000?
$cat test
ls a* > tempfile1
sed 's/a//' tempfile1 > tempfile2
awk '{printf("mv a%s a%04s ", $0, $0)}' tempfile2 > tempfile3
chmod 700 tempfile3
./tempfile3
rm tempfile*
$chmod test
----------------------------------------------------------------
ls a*|awk '{
num=substr($1,2,length($1)-1);
printf "mv %s a%04d ",$1,num
}'>rename.sh
sh rename.sh
----------------------------------------------------------------
for file in a*
do
newfile=`echo $file | awk '{printf "a%04d", substr($1, 2, length($1)-1)}'`
mv $file $newfile
done
给个不用awk的,效率会低一点
ls -1 a*|while read j
do
num=`echo $j|cut -b 2-`
num=`printf a%04s $num`
mv $j $num
done
-----------------------------------------------------------------
稍微缩减一下:
for file in a*
do
mv $file `echo $file|awk '{printf "a%04d", substr($1,2,length($1)-1)}'`
done
如果a1,a2,a3...等文件是各自有不同的扩展名呢?就像a1.pxx,a2,baa,a3.tga...
这样是不是可以呢:
for file in a*
do
nam=`echo $file|cut -d. -f1`
exe=`echo $file|cut -d. -f2`
mv $file `echo $nam|awk '{printf "a%04d", substr($1,2,length($1)-1)}'`.$exe
done
15 禁止从一个IP登录的shell
解决方案0:
用shell完全可以解决,如果有tcpwrapper的系统,可以直接加/etc/hosts.deny
解决方案1:
在/etc/profile里加一段shell就可以了(sco openserver)
这是我写的只要求本C段登陆的shell,改改就可以了.
who=`who am i|awk '{print $1}'`
myterm=`who am i|awk '{print substr($2,4,2)}'`
if [ "x"$who = "xroot" ]
then
subnet=`finger|grep $myterm|awk '{print substr($8,1,8)}'`
else
subnet=`finger|grep $myterm|awk '{print substr($7,1,8)}'`
fi
test x$subnet != x && test x$who != xroot && test "x"$subnet != "x46.8.44." &&
echo " Please login from local network " && exit
16 eval用法三例
## shell:/bin/sh ##
#例一:
#寻找符合条件的变量名,然后将该变量的值赋予另一变量
v1=aaa
v2=bbb
c=1
if [ $c -eq 1 ]
then
vname=v$c #找到符合条件的变量名为v1
eval vvv="$"$vname ; echo vvv: $vvv #将变量v1的值赋予vvv,即,使vvv=aaa
eval vvv='$'$vname ; echo vvv: $vvv #将变量v1的值赋予vvv,即,使vvv=aaa
#eval vvv=$$vname ; echo vvv: $vvv #错误用法
fi
#例二:#以变量v1的值aaa作为变量名,将变量vaaa的值赋予这一新定义的变量aaa
v1=aaa ; vaaa="This is aaa"
#eval $v1=$vaaa ; echo aaa: $aaa #错误用法
#eval $v1="$vaaa" ; echo aaa: $aaa #错误用法
eval $v1='$vaaa' ; echo aaa: $aaa
#例三:
#以变量v1的值aaa作为变量名,并将变量名字串作为值赋予自身
v1=aaa ; vaaa="This is aaa"
eval $v1=$v1 ; echo aaa: $aaa #与例二的错误用法不同,这一用法是正确的
eval $v1="$v1" ; echo aaa: $aaa #与例二的错误用法不同,这一用法是正确的
#区别在于,例二中的vaaa的值中间有空格
eval $v1='$v1' ; echo aaa: $aaa
17 改变UNIX终端颜色
a. 用echo"<ctrl-v><escape>[31m测试<ctrl-v><escape>[37m"
echo "^[[Xm YourChar"
(X=30,31...36?)
请注意这个转义系列的敲法是,<ctrl-v><escape>[30m
echo "<ctrl-v><escape>[<代码>;<代码>;<代码>m"
注意,语句必须要在""之间,属性分隔符为";",如闪烁红色
echo "<ctrl-v><escape>[31;5m测试"
b. 前景 背景 颜色
---------------------------------------
30 40 黑色
31 41 紅色
32 42 綠色
33 43 黃色
34 44 藍色
35 45 紫紅色
36 46 青藍色
37 47 白色
代码 意义
-------------------------
0 OFF
1 高亮显示
4 underline
5 闪烁
7 反白显示
8 不可见
c. 产生颜色(黑色背景加绿色前景色):
sco: setcolor red; echo "abcd"; setcolorwhite
export PS1="[u@h W]$ "
19 grep/awk/sed的多条件查询
# cat gt
one two three
four five six
one two
one seven three
# grep one three gt
grep: three: No such file or directory
gt:one two three
gt:one two
gt:one seven three
截取同时出现one和three的行,结果应该是:
one two three
one seven three
a. 用grep
cat gt | grep one | grep three
b. 用awk
awk '/one/&&/three/' gt
c. 用sed
sed -ne '/one/{/three/p}' gt
完!!!!