shell经典实例

1 列目录树的shell
#!/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 实现用backuptar命令来做目录备份

需要保持两个目录当中的文件以及属组关系不变。子目录结构不变,通过管道控制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 编写一个只允许用户执行telnetshell

为了监视用户网络操作行为,指定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

linux/BSD: /usr/bin/echo -e"

18 恢复缺省bash提示符

export PS1="[u@h W]$ "

保险起见,在~/.bashrc~/.bash_profile

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
完!!!!

猜你喜欢

转载自blog.csdn.net/xiaolong_4_2/article/details/80848562