最新文章专题视频专题问答1问答10问答100问答1000问答2000关键字专题1关键字专题50关键字专题500关键字专题1500TAG最新视频文章推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37视频文章20视频文章30视频文章40视频文章50视频文章60 视频文章70视频文章80视频文章90视频文章100视频文章120视频文章140 视频2关键字专题关键字专题tag2tag3文章专题文章专题2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章专题3
当前位置: 首页 - 正文

shell基础,变量,参数,函数,调试

来源:动视网 责编:小OO 时间:2025-10-02 07:30:28
文档

shell基础,变量,参数,函数,调试

SHELL编程序:我们现在使用的是什么shell?一.shell分类几种常见shell简介Linux系统提供多种不同的Shell以供选择。常用的有BourneShell(简称sh)、C-Shelll(简称csh)、KornShell(简称ksh)和BourneAgainShell(简称bash)。(1)BourneShell是AT&TBell实验室的StevenBourne为AT&T的Unix开发的,它是Unix的默认Shell,也是其它Shell的开发基础。BourneShell在编程方面相
推荐度:
导读SHELL编程序:我们现在使用的是什么shell?一.shell分类几种常见shell简介Linux系统提供多种不同的Shell以供选择。常用的有BourneShell(简称sh)、C-Shelll(简称csh)、KornShell(简称ksh)和BourneAgainShell(简称bash)。(1)BourneShell是AT&TBell实验室的StevenBourne为AT&T的Unix开发的,它是Unix的默认Shell,也是其它Shell的开发基础。BourneShell在编程方面相
SHELL 编程

序:我们现在使用的是什么shell?

一. shell分类

几种常见shell简介

Linux系统提供多种不同的Shell以供选择。常用的有Bourne Shell(简称sh)、C-Shelll(简称csh)、Korn Shell(简称ksh)和Bourne Again Shell (简称bash)。

(1)Bourne Shell是AT&T Bell实验室的 Steven Bourne为AT&T的Unix开发的,它是Unix的默认Shell,也是其它Shell的开发基础。Bourne Shell在编程方面相当优秀,但在处理与用户的交互方面不如其它几种Shell。  

  (2)C Shell是加州伯克利大学的Bill Joy为BSD Unix开发的,与sh不同,它的语法与C语言很相似。它提供了Bourne Shell所不能处理的用户交互特征,如命令补全、命令别名、历史命令替换等。但是,C Shell与BourneShell并不兼容。  

  (3)Korn Shell是AT&T Bell实验室的David Korn开发的,它集合了C Shell和Bourne Shell的优点,并且与Bourne Shell向下完全兼容。Korn Shell的效率很高,其命令交互界面和编程交互界面都很好。  

  (4)Bourne Again Shell (即bash)是自由软件基金会(GNU)开发的一个Shell,它是Linux系统中一个默认的Shell。Bash不但与Bourne Shell兼容,还继承了C Shell、Korn Shell等优点。

二. 一个Bash例程

1. 编写并保存以下代码

例程 1.1  清空日志文件

#!/bin/bash 

# 一个Bash脚本的正确的开头部分. 

LOG_DIR=/var/log 

# 如果使用变量,当然比把代码写死的好. 

cd $LOG_DIR 

cat /dev/null > messages 

cat /dev/null > wtmp 

echo "Logs cleaned up." 

exit # 这个命令是一种正确并且合适的退出脚本的方法.

例程 1.2  以下是上面例程的改进代码段

1 #!/bin/bash 

2 # 清除, 版本 3 

4 # 警告: 

5 # ----- 

6 # 这个脚本有好多特征, 

7 #+ 这些特征是在后边章节进行解释的. 

8 # 大概是进行到本书的一半的时候, 

9 #+ 你就会觉得它没有什么神秘的了. 

10 

11 

12 

13 LOG_DIR=/var/log 

14 ROOT_UID=0 # $UID为0的时候,用户才具有root用户的权限 

15 LINES=50 # 默认的保存行数 

16 E_XCD=66 # 不能修改目录? 

17 E_NOTROOT=67 # 非root用户将以error退出 

18 

19 

20 # 当然要使用root用户来运行. 

21 if [ "$UID" -ne "$ROOT_UID" ] 

22 then 

23 echo "Must be root to run this script." 

24 exit $E_NOTROOT 

25 fi 

26 

27 if [ -n "$1" ] 

28 # 测试是否有命令行参数(非空). 

29 then 

30 lines=$1 

31 else 

32 lines=$LINES # 默认,如果不在命令行中指定. 

33 fi 

34 

35 

36 # Stephane Chazelas 建议使用下边 

37 #+ 的更好方法来检测命令行参数. 

38 #+ 但对于这章来说还是有点超前. 

39 # 

40 # E_WRONGARGS=65 # 非数值参数(错误的参数格式) 

41 # 

42 # case "$1" in 

43 # "" ) lines=50;; 

44 # *[!0-9]*) echo "Usage: `basename $0` file-to-cleanup"; exit $E_WRONGARGS;; 

45 # * ) lines=$1;; 

46 # esac 

47 # 

48 #* 直到"Loops"的章节才会对上边的内容进行详细的描述. 

49 

50 

51 cd $LOG_DIR 

52 

53 if [ `pwd` != "$LOG_DIR" ] # 或者 if[ "$PWD" != "$LOG_DIR" ] 

54 # 不在 /var/log中? 

55 then 

56 echo "Can't change to $LOG_DIR." 

57 exit $E_XCD 

58 fi # 在处理log file之前,再确认一遍当前目录是否正确. 

59 

60 # 更有效率的做法是: 

61 # 

62 # cd /var/log || { 

63 # echo "Cannot change to necessary directory." >&2 

 # exit $E_XCD; 

65 # } 

66 

67 

68 

69 

70 tail -$lines messages > mesg.temp # 保存log file消息的最后部分. 

71 mv mesg.temp messages # 变为新的log目录. 

72 

73 

74 # cat /dev/null > messages 

75 #* 不再需要了,使用上边的方法更安全. 

76 

77 cat /dev/null > wtmp # ': > wtmp' 和 '> wtmp'具有相同的作用 

78 echo "Logs cleaned up." 

79 

80 exit 0 

81 # 退出之前返回0, 

82 #+ 返回0表示成功.

例程 1.3 显示日期、时间

1 #!/bin/bash

2 # 练习'date'命令

4 echo "The number of days since the year's beginning is `date +%j`."

5 # 需要在调用格式的前边加上一个'+'号.

6 # %j用来给出今天是本年度的第几天. 

8 echo "The number of seconds elapsed since 01/01/1970 is `date +%s`."

9 # %s将产生从"UNIX 元年"到现在为止的秒数,

10 #+ 但是这东西现在还有用么?

11 

12 prefix=temp

13 suffix=$(date +%s) # 'date'命令的"+%s"选项是GNU特性.

14 filename=$prefix.$suffix

15 echo $filename

16 # 这是一种非常好的产生"唯一"临时文件的办法,

17 #+ 甚至比使用$$都强.

18 

19 # 如果想了解'date'命令的更多选项, 请查阅这个命令的man页.

20 

21 exit 0

2. 执行

编写完脚本之后,你可以使用sh scriptname, [1] 或者bash scriptname来调用这个脚本. (不推荐使用sh 比如: 

chmod 555 scriptname (允许任何人都具有可读和执行权限) [2] 或者 chmod +rx scriptname (允许任何人都具有可读和执行权限) 

chmod u+rx scriptname (只给脚本的所有者可读和执行权限) 

既然脚本已经具有了可执行权限,现在你可以使用:

./scriptname 

来测试这个脚本了. 如果这个脚本以一个"#!"行开头, 那么脚本将会调用合适的命令解释器来运行. 

 

三. 一个TC Shell例程

例1:变量定义与从键盘输入变量的值

#!/bin/tcsh 

set var_new = "hahaha lolo"

echo vbvbvb  $var_new

set var_b=$<

echo "user input $var_b"......

注意:执行时应使用以下方式:

        /bin/tcsh scriptname

变量    输入/输出、重定向  使程序在后台/前台运行  内置参数 练习

一. 变量的定义、赋值、引用、删除

echo:显示变量的内容

env:显示系统所有环境变量

set:显示系统所有变量

export:导出变量使之在子进程中也可以使用

unset:删除变量

例2-1. 变量的赋值与替换

 #!/bin/bash

 # 变量赋值和替换

 a=375

 hello=$a

 #-------------------------------------------------------------------------

 # 强烈注意, 在赋值的的时候, 等号前后一定不要有空格.考虑如果出现空格会怎么样?

 #-------------------------------------------------------------------------

 echo hello # 没有变量引用, 只是个hello字符串.

 echo $hello

 echo ${hello} # 同上.

 echo "$hello"

 echo "${hello}"

 echo

 hello="A B C D"

 echo $hello # A B C D

 echo "$hello" # A B C D

 # 就象你看到的echo $hello 和 echo "$hello" 将给出不同的结果.

 echo '$hello'  # $hello

 # 全引用的作用将会导致"$"被解释为单独的字符,而不是变量前缀. 

 hello= # 设置为空值.

 echo "\\$hello (null value) = $hello"

 # 注意设置一个变量为null, 与unset这个变量, 并不是一回事,虽然最终的结果相同(具体见下边).

 # --------------------------------------------------------------

 echo; echo

 numbers="one two three"

 # ^ ^

 other_numbers="1 2 3"

 # ^ ^

 # 如果在变量值中存在空白, 那么就必须在赋值时加上引用.

 # other_numbers=1 2 3 # 将给出一个错误消息. 

 echo "numbers = $numbers"

 echo "other_numbers = $other_numbers" # other_numbers = 1 2 3

 echo "uninitialized_variable = $uninitialized_variable"

 # Uninitialized变量为null(就是没有值). 

 uninitialized_variable= # 声明, 但是没有初始化这个变量, 

 #其实和前边设置为空值的作用是一样的. 

 echo "uninitialized_variable = $uninitialized_variable"

 # 还是一个空值.

 uninitialized_variable=23         # 赋值.

 unset uninitialized_variable      # Unset这个变量.

 echo "uninitialized_variable = $uninitialized_variable"

 # 还是一个空值.

 echo

 exit 0

例2-2. 变量赋值

#!/bin/bash

# 等号赋值

a=879

echo "The value of \\"a\\" is $a."

# 使用'let'赋值

let a=16+5

echo "The value of \\"a\\" is now $a."

echo 'The value of \\'a\\' is now $a.'

# 在'for'循环中赋值(事实上, 这是一种伪赋值):

echo -n "Values of \\"a\\" in the loop are: "

#--------------------------------------------

for a in 7 8 9 11

 do

     echo -n "$a "

 done

echo

#--------------------------------------------

#使用'read'命令进行赋值(这也是一种赋值的类型):

echo -n "Enter \\"a:\\" "

read a

echo "The value of \\"a\\" is now $a."

#--------------------------------------------

b=$a

echo $b

# 现在让我们来点小变化(命令替换).

c=`echo Hello!`     # 把'echo'命令的结果传给变量'a'

echo $c

c=`ls -l`        # 把'ls -l'的结果赋值给'a'

echo $c          #然而, 如果没有引号的话将会删除ls结果中多余的tab和换行符.

echo "$c"        #如果加上引号的话, 那么就会保留ls结果中的空白符.

#命令替换也可以通过(  )实现

R=$(cat /etc/redhat-release)

arch=$(uname -m)

echo  $R; echo  $arch

exit 0

例2-3. 进行浮点运算

#!/bin/bash

echo -n "Inpute a:"

read a

echo -n "Input b:"

read b

#将文件afile中保存的运算交由bc执行

n=`bc < afile` #n=`cat afile | bc` 

echo $n

#计算a,b的乘积,包括浮点数

c=`echo "scale=3;$a*$b" | bc`

_____________________________________________

文件afile的内容就是bc可以接受的运算及处理

#cat afile

scale=3

for(i=1;i<5;i++){j=j+i}

二. 输入/输出、重定向: > 、 < 、 |  、 1> 、2>

1. 文件描述符:与某个打开的文件相关联的数字(相当于C语言是的文件号)

文件描述符代表的文件
0标准输入文件
1标准输出文件
2标准错误输入文件
n其它打开的文件
注:

1) 要关闭某文件描述符,使用: exec n>&-

2) 将数据同时输出到标准输出设备(屏幕) 和文件,需要使用tee.

tee的语法如下:

tee [option]... [file]... 

options: 

-a    --将输出追加到文件后

-i    --忽略中断信号

2.示例

$cat #cat把键盘看作标准输入,屏幕看作标准输出。按下CTRL+D结束键盘输入

$cat > sample.txt

$cat /dev/null > /var/log/messages

$cat x>hold

$cat x y>hold

$cat x y | tr "[a-z]" "[A-Z]"

$cat x y 1>hold1 2>hold2

$ls | lpr

$who | sort

$ls | less

$exec 1>fd1.out     #将以后所有命令的输出都定向到fd1.out

$cmd 1>file

$cmd 1>>file

$cmd 1>file1 2>file2 

$ln -s ch05.doc ./docs >> /tmp/ln.log 2>/dev/null

$rm -rf /tmp/my_tmp_dir > /dev/null 2>&1

$who | tee file.a | wc -l

例:2-4 将循环的输出重新排序

#!/bin/bash

for i in 7 9 2 4 5 12

do

 echo $i

done | sort -n

exit 0

例:2-5 输入重定向(利用read读入文件/etc/fstab的前两行)

#!/bin/bash

# 从/etc/fstab中读行.

File=/etc/fstab

{

  read line1

  read line2

} < $File

echo "First line in $File is:"

echo "$line1"

echo "Second line in $File is:"

echo "$line2"

exit 0

例2-6:每5分钟将将登录进入系统的用户列表追加到logfile文件中

#!/bin/bash

while :

do 

   date 

who

sleep 300

done >> logfile

例2-7:将一个文件描述符输出到另一个文件描述符

#!/bin/bash

exec 4>out.txt

exec 5>&4

date 1>&5

例2-8: 将所有查找到的文件(在工作目录下过去24小时内修改过的文件)打一个包

#!/bin/bash   

tar -zcvf lastmod.tar.gz `find . -mtime -1 -type f -print`

三. 变量置换

名称语法 描述
缺省值置换${param:-word}若param的值为空或未赋值, word取代param,否则返回param的值.但param的值不变

缺省值赋值${param:=word}若param的值为空或未赋值,word 值被赋给param,,否则保持不变

空值错误 

${param:?msg}

若param的值为空或未赋值,将msg 信息输出到STDERR,并且退出shell

有值置换 

${param:+word}若param有值,word取代param的值, 但param的值不变

提取子串${value:offset}

${value:offset:length}

从变量中提取子串,这里offset和length可以是算术表达式.

获得变量字符个数${#value}变量的字符个数 (变量的字符个数,并不是变量个数)

删除前部匹配${value#pattern}

${value##pattern}

去掉value中与pattern相匹配的部分,条件是value的开头与pattern相匹配, #与##的区别在于一个是最短匹配模式,一个是最长匹配模式.

删除尾部匹配${value%pattern}

${value%%pattern}

与#,##类似,只是是从value的尾部与pattern相匹配

变量内容的替换${value/pattern/string}

${value//pattern/string}

进行变量内容的替换,把与pattern匹配的部分替换为string的内容,/与//的区别与上同

例:

myfruit="pear"

fruit=${myfruit:-apple}

echo When myfruit is set ,fruit is :$fruit

unset myfruit

fruit=${myfruit:-apple}

echo When myfruit is unset ,fruit is :$fruit

--------------------------------------------------

unset var_x

echo When var_x is unset ,var_x is :$var_x

echo Now var_x is: ${var_x:=shalala}

-------------------------------------------------

unset var_x

${var_x:?"The var_x is undefined"}

${HOME:?"Your home directory is undefined"}

-------------------------------------------------

var_x="beijing 2008 "

echo ${var_x:+"aoyun beijing"}

echo var_x is :$var_x 

unset var_x 

echo ${var_x:+"aoyun beijing"}

echo var_x is :$var_x

练习:

1.如果变量MYPATH没有被赋值,那么下面两个命令会执行怎样的动作,有何不同

${MYPATH:=/usr/bin:/usr/sbin;/usr/ucb}

${MYPATH:-/usr/bin:/usr/sbin;/usr/ucb}

2.将当前目录下以某些字符开头的文件名,更改成以其它字符(参照Bash Shell编程手册之例9-19--修改文件扩展名)

3.若变量a="beijing 2008",请用变量内容替换的方法将beijing更换为paris,2008替换为2012

四. 在前台/后台运行程序(fg、bg)、显示当前作业列表(jobs)

教材 P235

例2-9:在后台运行某命令

$ls -l | lpr &

CONTROL+Z :将作业从前台移到后台

例2-10:将3号作业移到前台

$fg 3

例2-11:将3号作业移到后台

$bg 3

例2-12:终止某个作业

$ps | grep XXX   #找到作业的进程号PID

$kill n

五. BASH内部命令参考

$info bash

六. 位置参量和命令行参数

例2-13:命令行参数的简单示例

#!/bin/bash

echo "$0 $1 and $2"

echo "The number of para is $#"

set Jake Nicky Scott

echo "Para number is :$#All the para is :$*"

位置参量指代对象
$0代表脚本名
$#参数的个数
$*列出所有位置参数
$@同上
"$*"扩展为单个变量(例如:"$1$2$3")

"$@"扩展为多个单独的变量(例如:"$1

$1...${10} 
注: shift命令会重新分配位置参数, 其实就是把所有的位置参数都向左移动一个位置.

特殊参数:

$$: shell进程的PID号

$!: 后台运行的进程的PID号

$?: 退出状态 

例2-14:用shift移动参数

#!/bin/bash

until [ -z "$1" ] # 直到所有的位置参数都被存取完...

do

  echo -n "$1 "

  shift

done

echo 

exit 0

例 2-15 getopts处理命令行选项

#!/bin/bash

while getopts xy options 2>/dev/null

do

    case $options in

        x) echo "you entered x ";;

        y) echo "you entered y" ;;

        \\?) echo "only -x and -y are valid options "  1>&2 ;;

    esac

done

exit 0

例 2-16 getopts 与$OPTARG

#!/bin/bash

while getopts dq: options

do

    case $options in

        d) echo "you entered d ";;

        q) echo "the argument for -q is $OPTARG" ;;

        \\?) echo "Usage:opts3 -dq filename... "  1>&2 ;;

    esac

done

exit 0

. 课堂练习

2_1. 编写bash脚本:定义两个变量,从键盘给它们输入数字值,屏幕输出两个变量相加的结果。

2_2. 编写bash脚本:将前一天修改过的文件名按字母顺序保存在用户主目录的一个文件中;将当前目录下所有以a或A打头的文件设置为可运行(find ... -exec ...)。

2_3.编写脚本,用read逐行读取某文件,并输出.

2_4.利用脚本参数的方法,将执行脚本时指定的两个参数文件合并到第三个参数指定的文件中.(即通过./main a b c,能将文件a,文件b的内容合并输出到文件c中)

2_5.说明下一段代码的执行结果:

exec 4>o.txt

exec 5>&4

exec 1>&5

date

其它.

附:bash内置参数

PPID : 该bash的呼叫者process ID.

PWD : 目前的工作目录。

OLDPWD : 上一个工作目录。

REPLY : 当read命令没有参数时,直接设在REPLY上。

UID : User ID。

EUID : Effective User ID。

BASH : Bash的完整路径。

BASH_VERSION : Bash版本。

SHLVL : 每次有Bash执行时,数字加一。

RANDOM : 每次这个参数被用到时,就会产生一个乱数在RANDOM上。

SECONDS : 从这个Shell一开始启动後的时间。

LINENO : Script的行数。

HISTCMD : 历史记录数。

OPTARG : getopts处理的最後一个选项参数。

OPTIND : 下一个要由getopts所处理的参数号码。

HOSTTYPE : 机器种类。

OSTYPE : 作业系统名称。

IFS : Internal Field Separator。

PATH : 命令搜寻路径。

PATH="/usr/gnu/bin:/usr/local/bin:/usr/ucb:/bin:/usr/bin:."

HOME : 目前使用者的home directory;

CDPATH : cd命令的搜寻路径。

ENV : 如果这个参数被设定,每次有shell script被执行时,将会执行它所设定的档名做为环境设定。

MAIL : 如果这个参数被设定,而且MAILPATH没有被设定,那麽有信件进来时,bash会通知使用者。

MAILCHECK : 设定多久时间检查邮件一次。

MAILPATH : 一串的邮件检查路径。

MAIL_WARNING : 如果有设定的话,邮件被读取後,将会显示讯息。

PS1 : 提示讯息设定,内定为"bash$ "。(请详见提示讯息一节。)

PS2 : 第二提示讯息设定,内定为"> "。

PS3 : select命令所使用的提示讯息。

PS4 : 执行追踪时用的提示讯息设定,内定为"+ "。

HISTSIZE : 命令历史记录量,内定为500。

HISTFILE : 历史记录档,内定~/.bash_history。

HISTFILESIZE : 历史记录档行数最大值,内定500。

OPTERR : 如果设为1,bash会显示getopts的错误。

PROMPT_COMMAND : 如果设定的话,该值会在每次执行命令前都显示。

IGNOREEOF : 将EOF值当成输入,内定为10。

TMOUT : 如果设为大於零,该值被解译为输入等待秒数。若无输入,当成没有输入。

FCEDIT : fc命令的内定编辑器。

FIGNORE : 请详见READLINE。

INPUTRC : readline的startup file,内定~/.inputrc

notify : 如果设定了,bash立即报告被终结的背景程式。

history_control, HISTCONTROL : history使用。

command_oriented_history : 存入多行指令。

glob_dot_filenames : 如果设定了,bash将会把"."包含入档案路径中。

allow_null_glob_expansion : 如果设定了,bash允许路径明称为null string。

histchars : history使用。

nolinks : 如果设定了,执行指令时,不会跟随symbolic links。

hostname_completion_file, HOSTFILE : 包含与/etc/hosts相同格式的档名。

noclobber : 如果设定了,Bash不会覆写任何由">"、">&"及"<>"所操作的档案。

auto_resume : 请见任务控制一节。

no_exit_on_failed_exec : 如果该值存在,非互动的shell不会因为exec失败而跳出。

cdable_vars : 如果启动,而cd命令找不到目录,可切换到参数形态指定的目录下。

一.条件        返回

1. if语句

if ....; then 

    ....

elif ....; then

    ....

else

    ....

fi 

2.case 分支

case ... in 

...) do something here 

esac 

大多数情况下,可以使用测试命令来对条件进行测试。比如可以比较字符串、判断文件是否存在及是否可读等等...

通常用" [ ] "来表示条件测试。注意这里的空格很重要。要确保方括号的空格。  

[ -f "somefile" ] :判断是否是一个文件

[ -x "/bin/ls" ] :判断/bin/ls是否存在并有可执行权限

[ -n "$var" ] :判断$var变量是否有值

[ "$a" = "$b" ] :判断$a和$b是否相等 

[  ] :条件测试. 条件测试表达式放在[ ]中. 

[[  ]]:是一个扩展的"[   ]"命令,[[  ]]结构比[ ]结构更加通用. 使用[[ ... ]]条件判断结构, 而不是[ ... ], 能够防止脚本中的许多逻辑错误. 比如, &&, ||, <, 和> 操作符能够正常存在于[[ ]]条件判断结构中, 但是如果出现在[ ]结构中的话, 会报错.

(( )) :整数扩展. 扩展并计算在(( ))中的整数表达式. 双圆括号结构也被认为是在Bash中使用C语言风格操作变量的一种处理机制.

 

文件测试操作符

如果下面的条件成立将会返回真.

-e    文件存在

-a    文件存在,这个选项的效果与-e相同. 但是它已经被"弃用"了, 并且不鼓励使用.

-f    表示这个文件是一个一般文件(并不是目录或者设备文件)

-s    文件大小不为零

-d    表示这是一个目录

-b    表示这是一个块设备(软盘, 光驱, 等等.) 

-c    表示这是一个字符设备(键盘, modem, 声卡, 等等.)

-p    这个文件是一个管道

-h    这是一个符号链接

-L    这是一个符号链接

-S    表示这是一个socket

-t    文件(描述符)被关联到一个终端设备上,这个测试选项一般被用来检测脚本中的stdin([ -t 0 ]) 或者stdout([ -t 1 ])是否来自于一个终端. 

-r    文件是否具有可读权限(指的是正在运行这个测试命令的用户是否具有读权限)

-w    文件是否具有可写权限(指的是正在运行这个测试命令的用户是否具有写权限)

-x    文件是否具有可执行权限(指的是正在运行这个测试命令的用户是否具有可执行权限)

-g    set-group-id(sgid)标记被设置到文件或目录上,如果目录具有sgid标记的话, 那么在这个目录下所创建的文件将属于拥有这个目录的用户组, 而不必是创建这个文件的用户组. 这个特性对于在一个工作组享目录非常有用. 

-u    set-user-id (suid)标记被设置到文件上,如果一个root用户所拥有的二进制可执行文件设置了set-user-id标记位的话, 那么普通用户也会以root权限来运行这个文件. [1] 这对于需要访问系统硬件的执行程序(比如pppd和cdrecord)非常有用. 如果没有suid标志的话, 这些二进制执行程序是不能够被非root用户调用的.

-k    设置粘贴位 对于"粘贴位"的一般了解, save-text-mode标志是一个文件权限的特殊类型. 如果文件设置了这个标志, 那么这个文件将会被保存到缓存中, 这样可以提高访问速度. [2] 粘贴位如果设置在目录中, 那么它将写权限. 对于设置了粘贴位的文件或目录, 在它们的权限标记列中将会显示t.

-O    判断你是否是文件的拥有者

-G    文件的group-id是否与你的相同

-N    从文件上一次被读取到现在为止, 文件是否被修改过

f1 -nt f2    文件f1比文件f2新

f1 -ot f2    文件f1比文件f2旧

f1 -ef f2    文件f1和文件f2是相同文件的硬链接

!            "非" -- 反转上边所有测试的结果(如果没给出条件, 那么返回真).

 

整数比较操作符

-eq    等于    如:    if [ "$a" -eq "$b" ]

-ne    不等于    if [ "$a" -ne "$b" ]

-gt    大于    if [ "$a" -gt "$b" ]

-ge    大于等于    if [ "$a" -ge "$b" ]

-lt    小于    if [ "$a" -lt "$b" ]

-le    小于等于    if [ "$a" -le "$b" ]

<    小于(在双括号中使用)    (("$a" < "$b"))

<=    小于等于(在双括号中使用)    (("$a" <= "$b"))

>    大于(在双括号中使用)    (("$a" > "$b"))

>=    大于等于(在双括号中使用)    (("$a" >= "$b"))

字符串比较操作符

=    等于    if [ "$a" = "$b" ]

==    等于    if [ "$a" == "$b" ],与=等价.

!=    不等号    if [ "$a" != "$b" ],这个操作符将在[[ ... ]]结构中使用模式匹配. 

<    小于, 按照ASCII字符进行排序,if [[ "$a" < "$b" ]],if [ "$a" \\< "$b" ],注意"<"使用在[ ]结构中的时候需要被转义. 

>    大于, 按照ASCII字符进行排序    if [[ "$a" > "$b" ]],if [ "$a" \\> "$b" ],注意">"使用在[ ]结构中的时候需要被转义.

-z    字符串为"null", 意思就是字符串长度为零

-n    字符串不为"null".

 

例3-1:判断输入的用户名是否存在 

#!/bin/bash

echo -n "Please input user name:"

read name

grep "$name" /etc/passwd > /dev/null 2>&1

if [ $? -eq 0 ] ; then

echo $name exist

exit 0

else

echo $name not exist

exit 1

fi

例3-2:一个简单的条件例程

#!/bin/bash

echo -n "Are you ok?"

read ans

if [ "$ans" = "Y" -o "$ans" = "y" ]; then

echo "Glad to hear it"

elif [ "$ans" = "N" -o "$ans" = "n" ]; then

echo "then let us wait a minute"

else

echo "what is your mean?"

fi

exit 0

例3-3:查找30天以内修改过的、大小大于某值的文件

#!/bin/bash

if (( $# != 2 )); then

echo "Usage: $0 modi_days size " 1>&2

exit 1

fi

if (( $1 < 0 || $1 > 30 )) ; then

echo "modi_days is out of range"

exit 2

fi

if (( $2 <= 20 )) ; then

echo "The size is out of range"

exit 3

fi

find ~ -xdev -mtime $1 -size +$2

exit 0

例3-4:判断某个文件的属性 

#!/bin/bash

echo -n "Input file name:"

read file

if [ -d $file ]; then

echo "$file is a directory " 

elif [ -f $file ] ; then

    if [ -r $file -a -w $file -a -x $file ] ; then

        echo "you have read write and execute permission on $file."

    fi

else

echo "$file is neither a file nor a directory"

fi

exit 0

例3-5:下面的脚本可以自动解压bzip2, gzip 和zip 类型的压缩文件: 

#!/bin/sh 

ftype=`file "$1"` 

case "$ftype" in 

"$1: Zip archive"*) 

  unzip "$1" 

"$1: gzip compressed"*) 

  gunzip "$1" 

"$1: bzip2 compressed"*) 

  bunzip2 "$1" 

*) error "File $1 can not be uncompressed with smartzip";; 

esac 

二.循环            返回

需掌握以下内容:

for 结构循环

while 结构循环

untile 结构循环

select 结构循环

循环嵌套

break,continue 跳出循环,继续循环

例3-6:显示所有命令行参数 

#!/bin/bash

for i in "$@" #$*

do

echo $i

done

exit 0

例3-7:给多个人发送同一封信

$cat mylist

commy

patty

anny

jack

$cat mailer

#!/bin/bash

for person in $(cat mylist)

do

mail $person < letter

echo $person was sent a letter

done

exit 0

例3-8:为多个文件建立备份

#!/bin/bash

dir /home/jody/backupscripts

for file in memo[1-5]

do

if [ -f $file ] ; then

cp $file $dir/$file.bak

echo “$file in backed up in $dir”

fi

done

exit 0

例3-9. 在目录的所有文件中查找源字串

  #!/bin/bash

  # findstring.sh:

  # 在一个指定目录的所有文件中查找一个特定的字符串.

  directory=/usr/bin/

  fstring="Free Software Foundation"  # 查看哪个文件中包含FSF.

  for file in $( find $directory -type f -name '*' | sort )

   do

    strings -f $file | grep "$fstring" | sed -e "s%$directory%%"

   done  

  exit 0

例3-10: 生成菜单

#!/bin/bash

PS3="Select a program to execute:"

select program in "ld -F" pwd date

do

$program

done

exit 0

例3-11: 菜单与分支

#!/bin/bash

PS3="Please select one of the three boys:"

select choice in Tom dan guy "Exit loop"

do

    case $choice in

        Tom)

            echo $choice is good;;

        dan)

            echo $choice is normal;;

        guy)

            echo $choice is passed;;

        "Exit loop")

            echo $choice;break;;

        *)

            echo $choice is wrong

    esac

done

exit 0

例3-12: 在后台执行循环

#!/bin/bash

for person in bob jim sam smith

do

mail $person < memo

done &

exit 0

例3-13: 内部字段分隔符IFS与循环的例子

#!/bin/bash

names=Tome:Dick:Harry:John

oldifs="$IFS"

IFS=":"

for person in $names

do

    echo Hi $person

done

set Jill Jane Jolens

IFS="$oldifs"

for girl in $*

do

    echo Howdy $girl

done

exit 0

例3-14: 操作一组文件--复制到指定目录并更改文件权限

#!/bin/bash

for FILE in $HOME/.bash*

do

    cp $FILE ${HOME}/public_html

    chmod a+r ${HOME}/public_html/${FILE}

done

exit 0

例3-15: 逐行处理文件的几种方式

#!/bin/bash

echo -n "please input filename :"

read filename

if [ -f $filename ];then

while read LINE

do

echo $LINE

done < $filename

else

echo "$filename not exist"

fi

exit 0

#!/bin/bash

echo -n "please input filename :"

read filename

if [ -f $filename ];then

cat $filename | while read LINE

do

echo $LINE

done 

else

echo "$filename not exist"

fi

exit 0

#!/bin/bash

echo -n "please input filename :"

read filename

if [ -f $filename ];then

exec 3>&0

exec 0<$filename

while read LINE

do

echo $LINE

done 

exec 0<&3 

else

echo "$filename not exist"

fi

exit 0

 

 

 

练习            返回

3_1.编写脚本,能从键盘输入年龄,根据不同的年龄段,给出不同的提示信息。

3_2.编写脚本,能向httpd配置文件httpd.conf中添加一个虚拟主机的说明。

3_3.编写脚本addd,当执行./addd 4 5 6 7 8,能给出后面几个命令行参数4、5、6、7、8的和。

3_4.编写脚本,当执行脚本时,要求用户输入数据,只有输入”china”时,显示“输入正确”,并退出程序;输入其它数据,显示“输入错误”,并要求用户继续输入。

3_5.系统范围的脚本文件xinitrc可以用来启动X server. 这个文件包含了相当多的if/then条件测试, 下面是这个文件的部分节选.

if [ -f $HOME/.Xclients ]; then

    exec $HOME/.Xclients

elif [ -f /etc/X11/xinit/Xclients ]; then

    exec /etc/X11/xinit/Xclients

else

    xclock -geometry 100x100-5+5 &

    xterm -geometry 80x50-50+150 &

    if [ -f /usr/bin/netscape -a -f /usr/share/doc/HTML/index.html ]; then

        netscape /usr/share/doc/HTML/index.html &

    fi

fi

解释上边条件测试结构中的内容.

3_6.写脚本,能测试/usr/bin是一个目录还是一个符号链接

3_7.写一个select循环,列举出当前目录下的每个文件,并使用户通过选择文件序号来察看文件.除了列出每个文件,使用"Exit Program"作为退出循环的关键字.如果用户选择不是正规文件的选项,该程序应能发现问题.如果没有输入,该菜单应再次显示.

:附加练习

1. 列出当前目录中所有的符号链接.

2. 以C语言风格--"((  ))",判断从键盘输入的整数是奇数还是偶数.

3. 接上题,要求可以反复从键盘输入数据,只到输入"Exit"退出程序

函数

∙函数的定义 

∙执行函数 

∙函数参数 

∙全局变量、局部变量 

∙函数的链接,递归函数 

∙取消(清除)函数,导出函数 

函数在当前shell的环境中执行,也就是说,函数执行时并不派生一个子进程.

Bash shell先在别名中找,然后是函数,内置命令,最后才是可执行程序

一. 函数的定义

[function] func_name(){

...

}

二. 执行函数

通过函数名func_name来执行或调用函数

三. 函数参数

就象执行脚本时,可以附加参数一样,执行函数时也可以附加参数,并且也是通过$1、$2这样的形式访问的

四. 全局变量、局部变量

全局变量:有效范围是全局,即其值能在一个脚本的任何位置被访问。

局部变量:有效范围是局部,即其值只能在它被定义的函数(代码块)中使用,使用local或typeset来定义局部变量。

五. 函数的链接,递归函数

函数的链接:在一个函数中调用另一个函数。

递归函数:在函数中调用自己的函数。

六. 清除函数,导出函数

取消(清除)函数的定义,同删除变量一样,为:unset function_name

导出函数,为:export -f function_name

例 4-1:一个简单的带参函数

#!/bin/bash

printMsg()

{

echo "$1:$2"

}

printMsg aaaa bbbb

例 4-2: 函数链接(在一个函数中调用另一个函数)

#!/bin/bash

orange (){

echo "Now in orange"

banana

}

banana (){

echo "Now in banana"

}

orange

例 4-3 : 全局变量

#!/bin/bash

pearFunc () {

pear=2

echo "In pearFunc():pear is $pear"

}

pearFunc

echo "Outside of pearFunc():pear is $pear"

例 4-4 : 全局变量

#!/bin/bash

readPass () {

pass=""

echo  -n "Enter password:"

stty -echo

read pass

stty echo

echo

}

readPass

echo "password is: $pass"

例 4-5 : 局部变量

#!/bin/bash

pearFunc () {

typeset pear=2 # local pear=2

echo "In pearFunc():pear is $pear"

}

pearFunc

echo "Outside of pearFunc():pear is $pear"

例 4-6 :递归

#!/bin/bash

reverse () {

if [ $# -gt 0 ];then

    typeset arg="$1"  # local arg="$1"

    shift

    reverse "$@"

    echo "$arg"

fi

}

reverse "$@"

例 4-7 :递归2,求阶乘

#!/bin/bash

MAX_ARG=5

E_WRONG_ARGS=65

E_RANGE_ERR=66

if [ -z "$1" ];then

echo "Usage:`basename $0` number"

exit $E_WRONG_ARGS

fi

if [ "$1" -gt $MAX_ARG -o "$1" -lt "0" ];then

echo "Out of range (5 is maxmum)."

exit $E_RANGE_ERR

fi

function fact()

{

local number=$1

if [ "$1" -eq "0" ];then

r=1

else

let "n=$number-1"

fact $n

let "r=$number * $?"

fi

return $r

}

fact $1

echo "end of $1 is $?"

exit 0

例 4-8 :函数库应用

#!/bin/bash

#. ~/tysp2/appendixD/libtysp2.sh

source $HOME/tysp2/appendixD/libtysp2.sh

promptYESNO "If you want to call functions" "no"

if [[ $YESNO -eq "y" ]]; then

    echo Free Space of /var/www is `getSpaceFree "/var/www"`

    echo Space used in /var/www/htm `getSpaceUsed "/var/www/html"`

    promptRESPONSE "please input prog name" "named"

    if [ ! -z RESPONSE ] ;then

        echo $RESPONSE pid is `getPID $RESPONSE`

    fi

else

    echo "You dont want to do this"

fi

练习

1. 写一个函数,判断一个命令是否存在于$PATH中指定的目录中。这个命令将作为第一个参数。如果存在的话,函数就输出命令的绝对路径并返回0。否则,函数返回1,并打印错误信息。

2. 增强本章中给出的readPass函数,使它能读两次密码,并能确认两次密码是一样的。

3. 编写函数,求一个整数的平方.整数从键盘输入,然后再调用函数.

4. 将前面循环中逐行处理文件的代码用函数包装起来,通过调用该函数的方式来逐行显示文件.

调试

名称描述
bash -n 脚本名

解释但不执行脚本中的命令,通常用来进行语法检查

bash -v 脚本名

显示脚本中的所有行
bash -x 脚本名

在变量替换后(如果有的话),执行命令之前,显示该命令

set -x跟踪脚本的执行
set +x关闭脚本跟踪功能
练习

1. 检查某脚本的语法

2. 执行并检查脚本的语法 

3. 跟踪某段代码的执行

4. 跟踪递归函数的执行

文档

shell基础,变量,参数,函数,调试

SHELL编程序:我们现在使用的是什么shell?一.shell分类几种常见shell简介Linux系统提供多种不同的Shell以供选择。常用的有BourneShell(简称sh)、C-Shelll(简称csh)、KornShell(简称ksh)和BourneAgainShell(简称bash)。(1)BourneShell是AT&TBell实验室的StevenBourne为AT&T的Unix开发的,它是Unix的默认Shell,也是其它Shell的开发基础。BourneShell在编程方面相
推荐度:
  • 热门焦点

最新推荐

猜你喜欢

热门推荐

专题
Top