shell编程小记

来源:互联网 发布:怎么重置电脑网络设置 编辑:程序博客网 时间:2024/04/29 10:21
http://hi.baidu.com/smilewwh/blog/item/1d81d9190783f179dbb4bd14.html

shell编程小记

2007年11月27日 星期二 16:44
sh   bash   csh   tcsh   ksh
cat /etc/shells   可查看已知的shell
/bin/dash   更符合标准,向前兼容
/bin/sh->bash   执行脚本快,但交互弱些

脚本的执行方法:
1.sh ./script.sh
2.chmod +x script.sh; ./script.sh

脚本开头表明解释器:
#!/bin/sh
#!/usr/bin/sed
#!/usr/bin/perl
#!/usr/bin/python

非交互式的shell就是脚本,交互式的就是应答式的。
脚本执行用的机制是fork-and-exec,内建命令执行不需要fork新的进程
shell的内建命令可以用man bash-buildins查看,用which命令查不到的是内建命令

$ cd ..; ls
$ (cd ..; ls)   这不会改变当前路径,因为带()会创建子进程来运行

关于bash启动文件:
一.交互式意味着可以输入命令:
登录shell就是系统验证完用户名和密码后得到的shell
启动读取/etc/profile   ~/.bash_profile    or    ~/.bash_login    or    ~/.profile    or    /etc/bash.bashrc
非登录shell就是通过图标或菜单打开一个终端,如xterm,得到的shell
启动读取~/.bashrc
二.非交互式是为执行脚本而fork出来的shell
启动文件1.由变量BASH_ENV定义 2.以sh命令调用,读取的文件是/etc/profile或~/.profile

变量的类型:
环境变量->可以由当前shell传递给子进程使用,env或printenv可以查看,常用的有PATH,PWD,USER,SHELL等
本地变量->只存在于当前shell,使用内建命令set可显示所有变量(含环境变量)和函数

设置变量:
VARNAME="value"   本地变量
export VARNAME="value"   设为环境变量,子shell可以使用
shell中变量无需要特别声明,直接使用就可以了.??

删除变量:    使用内建命令unset VARNAME

读取变量:        
$echo $VAR
$echo $VARabc
$echo ${VAR}abc   {}用于这种场合


代换substitution

文件名代换globbing:   *   ?   []
$ls /dev/sda*
$ls tw?.doc
$ls tw[0-9].doc   在shell中完成替换,再传到命令ls

反引号backquote命令代换:
DATE=`date`   表示内部是条命令,而不是一个字串或变量
$echo $(date)   $()里面是命令,与`date`同

算术代换$((expression))
expression当中只能有 + - * / 和 () ,只能做整数运算

引用字符->用来去除字符或字的特殊含义
/   可用来去除单个字符的特殊意义
'   可用来保持'   '内所有字符的字面值
"   可用来保持" "内所有字符的字面值(其实与不加引号情况同),下列情况除外:
  •     `   反引号用于命令替换
  •     $VAR    显示变量内容 ?
  •     /$   /'   /"   //   分别用于表达$ ' " /这是个字符
  •     /用于其他情况,仅表示/
$'STRING'   当中STRING内容ANSI-C的转义序列解释
    如:$ echo $'a/tb'   结果显示:$ a   b

进程IO:
0表示标准输入,1表示标准输出,2表示标准错误输出
可以通过> < | 改变默认的输入输出方向
如:command > /dev/null 2>&1
/dev/null用于吸收数据并抛弃, 标准输出已经被改变了,因此&1已经指向了/dev/null,无任何信息输出

bash脚本编程:
参数与特殊变量:
$0   所执行脚本的路径名或函数名
$n   n>0,表示第n个参数
$#   参数的个数
$*   所有参数一起括起来组成"$1 $2 ... $n"
$@ 所有参数单独括起来组成"$1" "$2" ... "$n"
$?   上一条命令的退出状态
$$   当前shell的进程号
$!   上一条后台命令产生的进程的进程号

set用于把一个串作为当前脚本的参数,可用$n等进行提取,如
    set $(date)  
    echo month is $2
unset命令用于删除变量,如
    foo="hello"   
    unset foo
内建命令shift用于移动参数序列,如
    shift 2    后原来的$3成为了$1
eval   可将显示的内容当命令执行,如
    echo hello > out
    eval echo hello > out

函数:函数在被使用后保留,除非在他们被使用后进行unset,set可显示,which可显示;
function FUNCTION { COMMANDS; }

FUNCTION () { COMMANDS; }

FUNCTION abc    引用时,函数名后面跟的就是传递给函数的参数

函数调用可以传递参数,函数内可以使用$n等系列字符引用,函数内可设置变量,用内建命令local可设置局部变量,函数返回用return value
shell的结束用exit value返回值给父进程,如exit 1表示错误,成功时返回0;

if条件判断表达式,正确返回0:
[ -d FILE ] 判断是否为目录
[ -f FILE ] 判断是否文件存在
[ FILE1 -nt FILE2 ] 1比2新或1在2不在,为真    ot 相反   ef 相同的设备和节点号,为真
[ STRING1 == STRING2 ] 字符串比较,!=, <, >
[ ARG1 OP ARG2 ] 数字比较,OP为 -eq 等于, -ne不等, -lt小于, -le小等, -gt大于, -ge大等

[ ! EXPR ]
[ ( EXPR ) ]
[ EXPR1 -a EXPR2 ] 表示and
[ EXPR1 -o EXPR2 ] 表示or

if TEST-COMMANDS; then CONSEQUENT-COMMANDS; fi
if TEST1; then
CONSE1
elseif TEST2; then
CONSE2
esle CONSE3;
fi
其中空格不能少, ; 可以用回车取代; 若then 或 else 后面没有要执行的语句,则用 then : 或 else :

case EXPRESSION in
CASE1) COMMAND-LIST;;
CASE2) COMMAND-LIST;;
...
CASEn) COMMAND-LIST;;
esac

for NAME in LIST; do COMMANDS; done

while CONTROL-COMMAND; do CONSEQUENT-COMMANDS; done

经典:
LOOP=1
while read LINE
do
    echo "$LOOP: $LINE"
    LOOP=`expr $LOOP + 1 `
done < $FILENAME          可以从文件读入行,并显示行号

mkdir $DIRECTORY > /dev/null 2>&1         可以创建目录,并不显示任何信息

test COND1 && COMMANDS       short circuit   前面的条件成立,才执行后面
[ COND1 ] || COMMANDS          test与[ ]作用相同,前面的条件不成立,才执行后面
基于这个逻辑false && * = false      true || * = true

stop)
    echo -n "shutting down"
    kill `cat /var/run/sshd2_$PORT.pid`         直接获取cat出来的pid,让kill使用
    echo "done."
    ;;
restart)
    $0 stop                                                    直接调用shell本身作为命令
    $0 start
    ;;

一些实例:
#!/bin/sh
ls -la
pwd
exit 0

#!/bin/sh
echo "Is it morning? Please answer yes or n"
read timeofday
case "$timeofday" in
yes | y | Yes | YES)
echo "Good morning"
echo "Up bright and early this morning"
;;
[nN]*)
echo "Good afternoon"
;;
*)
echo "Sorry, answer not recognized"
echo "Please answer yes or no"
exit 1
;;
esac
exit 0

#!/bin/sh
OUTPUT="> out.file"
echo hello $OUTPUT

OUTPUT="> out.file"
eval echo hello $OUTPUT

#!/bin/sh
for foo in bar fud 43
do
echo $foo
done
for i in 1 2 3
do
echo $(($i+$i))
done
exit 0

#!/bin/sh
yes_or_no()
{
echo "Is your name $* ?"                  $*是传进函数的参数
while true                                          确保不输入或输入错误还有机会输入
do
echo -n "Enter yes or no: "                  -n表示不换行
     read x
case "$x" in
y | yes ) return 0;;
n | no ) return 1;;
* ) echo "Answer yes or no"               给输入错误用while提供足够机会
esac
done
}
#the main part of the program begins:
echo " Original parameters are $*"
if yes_or_no "$1"                                 把$1作为参数传给函数yes_or_no
then
echo "Hi $1, nice name"
else
echo "Never mind"
fi
exit 0

#!/bin/sh
if test -f /bin/bash;then echo "file /bin/bash exists";fi         ;分割符号也可用回车代替
if [ -d /bin/bash ];then echo "/bin/bash is a directory"
else echo "/bin/bash is NOT a directory";fi

#!/bin/sh
echo "Is it morning? Please answer yes or no"
read timeofday
if [ $timeofday = "yes" ];then echo "Good morning"
else echo "Good afternoon";fi
test "$(whoami)" != 'root' && (echo you are using a/
          non-privileged account;exit 1)
exit 0

#!/bin/sh
echo "every one:"
for i in $@
do echo $i
done
echo "total:"
echo $#
echo "the 1st:"
echo $1
echo "shift 1,show 1st"
shift 1
echo $1
exit 0

#!/bin/sh
foo=0
echo "Enter password"
read trythis
while [ $trythis != "secret" ];
do
echo "Sorry, try again"

foo=$(($foo+1))
if [ $foo -eq 3 ];then exit 1;fi

read trythis
done
exit 0

#!/bin/sh
# 一个自动登录ftp下载的shell程序

USER=anonymous
PASS=
ftp -i -n <<END
open xxx.xxx.xxx.xxx
user $USER $PASS
ls
get filename
close
END
 
原创粉丝点击