收藏 分享(赏)

shell教程.doc

上传人:tangtianxu1 文档编号:3129804 上传时间:2018-10-04 格式:DOC 页数:196 大小:1.48MB
下载 相关 举报
shell教程.doc_第1页
第1页 / 共196页
shell教程.doc_第2页
第2页 / 共196页
shell教程.doc_第3页
第3页 / 共196页
shell教程.doc_第4页
第4页 / 共196页
shell教程.doc_第5页
第5页 / 共196页
点击查看更多>>
资源描述

1、1.5. 开发优良脚本 1.5.1. 优良脚本的要素 本指南只要是关于上面的 shell 构成部分,脚本。在继续之前我们应该考虑一些东西:1. 一个脚本应该无错运行。2. 它应该完成他要完成的任务。3. 程序的逻辑结构定义清晰而且明显。4. 一个脚本不做不必要的工作。5. 脚本可以重用。1.5.2. 结构 shell 脚本的结构非常具有灵活性。即使在 Bash 中有很大的自由度,你必须保证正确的逻辑,流控制和效率,这样,用户才能执行脚本能做到简单和正确。当开始一个新的脚本的时候,问自己以下几个问题: 需要从用户或者用户环境来取得任何信息吗? 怎么样来存放那些信息? 需要创建文件吗?哪里和文件需

2、要拥有什么样的权限和所有权? 我将用到什么命令?当在一个不同的系统使用脚本的时候,所有这些系统在要求的版本下有这些命令吗? 用户需要什么提示吗?什么时候和为什么?1.5.3. 术语 下表给出了你需要熟悉的编程条款的概览:表 1.1. 编程条款的概览术语 含义命令控制 测试一个命令的退出状态来决定应该执行哪部分的程序。条件分支 在程序中条件决定接下来该怎么办的逻辑点。逻辑流程程序的总体设计。决定任务的逻辑顺序,使得结果是成功的且是可以控制的。循环 程序执行 0 次或者多次的部分。术语 含义用户输入 程序运行的时候外部源提供的信息,可以在需要的被存储和回调。1.5.4. 关于顺序和逻辑 为了加速开

3、发的进程,程序的逻辑顺序应该在实现思考好。这是你开发脚本的第一步。由很多方法可以使用;最常用的就是使用列表。逐条列记和一个程序相关的任务列表允许你描述每个进程。单个任务可以用他们的项目编号来引用。使用你自己的口语来制定你的程序会执行的任务将帮助你建立易于理解的框架。之后,你可以用 shell 语言和结构来替换它们。下面的例子现实了这样一个逻辑流程设计。描述了日志文件的轮换。例子显示了一个可能的重复循环,以你想轮换的基本日志文件的数量来控制:1. Do you want to rotate logs?a. If yes:i. Enter directory name containing the

4、 logs to be rotated.ii. Enter base name of the log file.iii. Enter number of days logs should be kept.iv. Make settings permanent in users crontab file.b. If no, go to step 3.2. Do you want to rotate another set of logs?a. If yes: repeat step 1.b. If no: go to step 3.3. Exit用户应该提供信息给程序来运行。必须得到并储存来自用

5、户的输入。用户应该注意到她的 crontab 会发生改变。1.5.5. 一个 Bash 脚本的例子:mysystem.sh mysystem.sh 脚本执行了一些熟悉的命令,(date, w, uname, uptime) 来显示你和你机器的信息。 tom: cat -n mysystem.sh1 #!/bin/bash2 clear3 echo “This is information provided by mysystem.sh. Program starts now.“45 echo “Hello, $USER“6 echo78 echo “Todays date is date, t

6、his is week date +“%V“.“9 echo1011 echo “These users are currently connected:“12 w | cut -d “ “ -f 1 - | grep -v USER | sort -u13 echo1415 echo “This is uname -s running on a uname -m processor.“16 echo1718 echo “This is the uptime information:“19 uptime20 echo2122 echo “Thats all folks!“脚本总是以相同的 2

7、个字符开始,“#!”。之后,shell 会执行定义在第一行之后的命令。脚本在第 1 行清除屏幕内容。第 2 行打印一条语句,通知用户将要发生的事情。第 5 行问候用户。第 6,9,13,16 和 20 行是为了按顺序输出显示。第 8 行打印了当前的日期和周数。第 11 行市又一个提示信息,和第3,8,22 行一样。第 12 行格式化 w 的输出;第 15 行显示了操作系统和 CPU信息。第 19 行给出了 uptime 和 load 信息。 echo 和 printf 都是 Bash 内建命令。第一个总是以状态 0 退出,且简单地把参数在标准输出打印出来,而后者允许定义一个格式化字符串且在失败

8、后返回一个非零的退出状态。 这是一个相同的使用 printf 内建命令的脚本: tom: cat mysystem.sh#!/bin/bashclearprintf “This is information provided by mysystem.sh. Program starts now.“printf “Hello, $USER.nn“printf “Todays date is date, this is week date +“%V“.nn“printf “These users are currently connected:n“w | cut -d “ “ -f 1 - | g

9、rep -v USER | sort -uprintf “n“printf “This is uname -s running on a uname -m processor.nn“printf “This is the uptime information:n“uptimeprintf “n“printf “Thats all folks!n“依靠插入信息来建立友好的脚本将在 第 8 章 编写交互脚本 详细讲解。 Bourne Again shell 的标准位置意味着 bash 程序安装在 /bin。 如果 stdout 不存在如果你从 cron 执行脚本,提供完整的路径名字和重定向输出和错

10、误。既然shell 在非交互模式运行,如果你考虑这些任何错误将导致脚本过早的退出。以下章节将会具体讨论上面的脚本。1.5.6. init 脚本例子 一个 init 脚本启动在 UNIX 和 Linux 机器上的系统服务。通常例子有系统日志守护程序,电源管理守护程序,名字和邮件守护程序。这些脚本,也被称作启动脚本,存储在系统的特定位置,比如 /etc/rc.d/init.d 或者 /etc/init.d。Init,初始化进程,读取它的配置文件来决定在某些运行等级哪些服务来启动或者停止,比如,为了进行管理任务,系统要尽可能设置成非使用状态,比如从备份中恢复一个危急的文件系统。重启动和关闭的运行等级

11、通常也是配置好的。 在启动一个服务或者停止它的时候需要执行的任务纪录在启动脚本中。配置 init 是系统管理员的一项任务,由此服务可以在正确的时刻运行和停止。当面临这样的任务,你需要对你系统的启动和停止程序有着良好的理解。我们因此建议在开始着手你的初始化脚本之前阅读 init 和 inittab 的 man 页面。 这里是一个很简单的例子,当起动和关闭你的机器的时候会播放一个声音:#!/bin/bash# This script is for /etc/rc.d/init.d# Link in rc3.d/S99audio-greeting and rc0.d/K01audio-greetin

12、gcase “$1“ instart)cat /usr/share/audio/at_your_service.au /dev/audio;stop)cat /usr/share/audio/oh_no_not_again.au /dev/audio;esacexit 0case 语句经常使用在这类脚本当中,在第 7.2.5 节 “使用 exit 语句和 if”中会解释。 1.6. 总结 Bash 是 GNU shell,兼容 sh 以及其他 shell 里的许多有用的特性。当 shell 启动的时候,它读取它自己的配置文件。最重要的几个如下所示: /etc/profile /.bash_pr

13、ofile /.bashrcBash 在交互模式下,遵循 POSIX 标准的时候和限制模式下的行为会有所不同。shell 命令可以分成为 3 个种类:shell 的功能命令,shell 内建命令和你系统里某个目录里的命令。Bash 支持额外的 sh 不包含的内建命令。Shell 脚本把那些命令组成 shell 语法命令。脚本读取一行执行一行且应该有逻辑结构。Shell 脚本把那些命令组成 shell 语法命令。脚本读取一行执行一行且应该有逻辑结构。1.7. 练习 这里有些联系可以让你在进入下一章节之前进行下热身:1. bash 程序位于你系统的什么位置? 2. 使用 -version 选项来找

14、到你正在运行的版本。 3. 当使用图形用户界面进入系统然后打开终端窗口时哪个 shell 配置文件会被读取?4. 以下 shell 是交互 shell 吗?它们是登陆 shell 吗? 一个 shell 通过你的图形桌面打开,从菜单选择类似 “Terminal” 。 一个你执行 ssh localhost 命令之后得到的 shell。 一个在你以文本模式登陆进控制台得到的 shell。 一个通过命令 xterm w在更高级的脚本中, echo 可以插入到在不同的阶段显示变量表,因此可以检查到错误: echo “Variable VARNAME is now set to $VARNAME.“2

15、.4. 总结 shell 脚本是一个放在可执行文本文件中的一组可以重用的命令。任何文本编辑器都可以用来编写脚本。脚本以 #! 开头,后面紧跟执行脚本的 shell 的路径。在脚本中加入注释是为了将来的参考,同样也使得其他人能理解脚本。解释多肯定比少要好。 使用选项可以用来调试脚本。shell 选项可以用来部分或者扫描整个脚本。善用 echo 你某些位置也是一种常用的排错技术。2.5. 练习 这个练习将帮助你建立尼的第一个脚本。1. 使用你喜爱的编辑器来写一个脚本。这个脚本应该显示你的 home 目录的路径和你正在使用终端的类型。此外现实你系统上 runlevel 是 3 的所有服务。(提示:

16、使用 HOME, TERM 和 ls /etc/rc3.d/S*) 2. 在你的脚本中加入注释。3. 在你的脚本中加入用户的信息。4. 改变脚本的权限来运行它。5. 在正常模式和调试模式运行脚本。脚本应该没有错误地运行。6. 在你的脚本中制造错误:看看如果你命令拼写错误会发生什么,比如省略第一行或者加入某些莫名其妙的东西,或者如果把变量名拼写错误或者在变量用大写声明后以小写来使用。检查调试信息会怎样说明。第 3 章 Bash 环境 目录3.1. Shell 初始化文件 3.1.1. 跨系统配置文件 3.1.2. 单独用户配置文件 3.1.3. 改变 shell 配置文件 3.2. 变量 3.2

17、.1. 变量的类型 3.2.2. 建立变量 3.2.3. 导出变量 Exporting variables 3.2.4. 保留变量 3.2.5. 特殊参数 3.2.6. 脚本借助变量的循环使用 3.3. 引用字符 3.3.1. Why? 3.3.2. 转义字符 3.3.3. 单引号 3.3.4. 双引号 3.3.5. ANSI-C 引用 3.3.6. 场合 3.4. Shell 扩展 3.4.1. 概要 3.4.2. 括号扩展 3.4.3. 扩展 3.4.4. Shell 参数和变量扩展 3.4.5. 命令替换 3.4.6. 算术扩展 3.4.7. 过程替换 Process substitut

18、ion 3.4.8. 字分割 3.4.9. 文件名扩展 3.5. 别名 3.5.1. 什么是别名? 3.5.2. 建立和移除别名 3.6. 更多 Bash 选项 3.6.1. 显示选项 3.6.2. 改变选项 3.7. 总结 3.8. 练习 摘要本章我们讨论几种能影响 Bash 环境的不同方法: 编辑 shell 初始化文件 使用变量 使用不同引用风格 实现算术运算 指派别名 使用扩充和替换3.1. Shell 初始化文件 3.1.1. 跨系统配置文件 3.1.1.1. /etc/profile 当用 -login 选项或者以 sh 来调用交互模式时,Bash 读取 /etc/profile

19、的指令。通常是一些设置 shell 变量 PATH, USER, MAIL, HOSTNAME 和 HISTSIZE。 在某些系统上, umask 的值在 /etc/profile 中配置;其他的一些系统中这个文件包含了指向了其他配置文件的指针: /etc/inputrc, 可以配置命令行响铃风格的跨系统的行读取初始化文件。 /etc/profile.d 包含了配置特别程序的跨系统行为的文件。 你想应用到所有用户环境的所有设置都必须在这个文件中,这个文件看上去可能像这样:# /etc/profile# System wide environment and startup programs,

20、for login setupPATH=$PATH:/usr/X11R6/bin# No core files by defaultulimit -S -c 0 /dev/null 2 thenINPUTRC=/etc/inputrcfiPS1=“uh W“export PATH USER LOGNAME MAIL HOSTNAME HISTSIZE INPUTRC PS1# Source initialization files for specific programs (ls, vim, less, .)for i in /etc/profile.d/*.sh ; doif -r “$i

21、“ ; then. $ifidone# Settings for program initializationsource /etc/java.confexport NPX_PLUGIN_PATH=“$JRE_HOME/plugin/ns4plugin/:/usr/lib/netscape/plugins“PAGER=“/usr/bin/less“unset i这个配置文件设置了一些基本 shell 环境变量和一些用户需要在 web 浏览器中运行 Java 和/或 Java 应用程序的一些变量。参见 第 3.2 节 “变量”. 参见 第 7 章 条件语句 得到更多关于条件 if 如何使用在这些

22、文件中; 第 9章 重复性任务 讨论诸如 for 的循环结构。 Bash 的源代码包含了用于普通和单独使用的 profile 文件例子。这些和上面这个例子需要做某些改变才能在你的环境中工作! 3.1.1.2. /etc/bashrc 在提供多种类型 shell 的系统中,因为 /etc/profile 也会被诸如 Bourne shell 的其他 shell 读取,最好把 Bash 特殊配置文件放到 /etc/profile 中。shell 产生的错误 Errors generated by shells that dont understand the Bash syntax are pre

23、vented by splitting the configuration files for the different types of shells. 由于这样的情况,用户的 /.bashrc 可能指向 /etc/bashrc 以便于在登陆 shell 的初始化进程中包含它。 你也可能发现你系统中的 /etc/profile 只存放了 shell 环境和程序启动设置,尽管 /etc/bashrc 包含了为 shell 函数和别名的跨系统定义。/etc/bashrc 文件可能指向 /etc/profile 或者单用户 shell 初始化文件。 源代码包含了 bashrc 例子文件,或者你可

24、能在 /usr/share/doc/bash-2.05b/startup-files 找到一份拷贝。这是和 Bash 文档一起提供的 bashrc 一个部分: alias ll=ls -lalias dir=ls -baalias c=clearalias ls=ls -coloralias mroe=morealias pdw=pwdalias sl=ls -colorpskill()local pidpid=$(ps -ax | grep $1 | grep -v grep | gawk print $1 )echo -n “killing $1 (process $pid).“kill

25、-9 $pidecho “slaughtered.“除了普通的别名之外,它还包含了更有用的别名甚至在你拼写错误的时候仍然能够让它工作。我们会在 第 3.5.2 节 “建立和移除别名”讨论别名。这个文件包含了一个函数,pskill;函数会在 第 11 章 函数 中具体学习。 3.1.2. 单独用户配置文件 我没有这些文件?!默认情况下这些文件可能在你的主目录中,需要的话也可以建立他们。3.1.2.1. /.bash_profile 这是个别地为配置用户环境的首选的配置文件。在这个文件中,用户可以增加额外的配置选项或者改变默认设置:franky cat .bash_profile# # .bash

26、_profile file # # Executed from the bash shell when you log in. # #source /.bashrcsource /.bash_logincase “$OS“ inIRIX)stty sane decstty erase;# SunOS)# stty erase# ;*)stty sane;esac这个用户配置了登陆到不同操作系统的退格字符。除此之外,读取用户的 .bashrc 和 .bash_login 文件。 3.1.2.2. /.bash_login 这个文件包含了只有在你登陆进系统的才执行的特殊的设置。在这个例子中,我用它

27、来配置 umask 的值来显示一个当前连接的用户列表。该用户也得到了当前月的日历: # # Bash_login file # # commands to perform from the bash shell at login time # (sourced from .bash_profile) # # file protectionumask 002 # all to me, read to group and others# miscellaneouswcal date +“%m“ date +“%Y“在没有 /.bash_profile 的情况下,这个文件就被读取。 3.1.2.3.

28、 /.profile 在没有 /.bash_profile 和 /.bash_login 文件的情况下,/.profile 就被读取。他能保存一些可以被其它的 shell 访问的配置。注意其他的 shell 可能不能识别 Bash 的语法。 3.1.2.4. /.bashrc 如今,更加普遍的是使用一个非登陆 shell,比如使用 X 终端窗口登陆进图形模式的时候。打开一个这样的窗口之后,用户不需要提供用户名和密码;无需认证。此时 Bash 会搜索 /.bashrc ,所以也指向登陆时读取的文件,同时也意味着你不需要在多个文件中输入相同的设置。 在这个用户的.bashrc 里,在读取了跨系统的

29、 /etc/bashrc 之后定义了一些别名和为特定的程序使用的变量: franky cat .bashrc# /home/franky/.bashrc# Source global definitionsif -f /etc/bashrc ; then. /etc/bashrcfi# shell optionsset -o noclobber# my shell variablesexport PS1=“0331;44mu w0330m “export PATH=“$PATH:/bin:/scripts“# my aliasesalias cdrecord=cdrecord -dev 0,0

30、,0 -speed=8alias ss=ssh octarinealias ll=ls -la# mozilla fixMOZILLA_FIVE_HOME=/usr/lib/mozillaLD_LIBRARY_PATH=/usr/lib/mozilla:/usr/lib/mozilla/pluginsMOZ_DIST_BIN=/usr/lib/mozillaMOZ_PROGRAM=/usr/lib/mozilla/mozilla-binexport MOZILLA_FIVE_HOME LD_LIBRARY_PATH MOZ_DIST_BIN MOZ_PROGRAM# font fixalias

31、 xt=xterm -bg black -fg white 34:ln=01;36:pi=40;33:so=01;35:bd=40;33;01:cd=40;33;01:or=01;05;37;41:mi=01;05;37;41:ex=01;32:*.cmd=01;32:*.exe=01;32:*.com=01;32:*.btm=01;32:*.bat=01;32:*.sh=01;32:*.csh=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.

32、gz=01;31:*.bz2=01;31:*.bz=01;31:*.tz=01;31:*.rpm=01;31:*.cpio=01;31:*.jpg=01;35:*.gif=01;35:*.bmp=01;35:*.xbm=01;35:*.xpm=01;35:*.png=01;35:*.tif=01;35:MACHINES=octarineMAILCHECK=60MAIL=/var/mail/frankyMANPATH=/usr/man:/usr/share/man/:/usr/local/man:/usr/X11R6/manMEAN_MACHINES=octarineMOZ_DIST_BIN=/

33、usr/lib/mozillaMOZILLA_FIVE_HOME=/usr/lib/mozillaMOZ_PROGRAM=/usr/lib/mozilla/mozilla-binMTOOLS_FAT_COMPATIBILITY=1MYMALLOC=0NNTPPORT=119NNTPSERVER=newsNPX_PLUGIN_PATH=/plugin/ns4plugin/:/usr/lib/netscape/pluginsOLDPWD=/nethome/frankyOS=LinuxPAGER=lessPATH=/nethome/franky/bin.Linux:/nethome/franky/b

34、in:/usr/local/bin:/usr/local/sbin:/usr/X11R6/bin:/usr/bin:/usr/sbin:/bin:/sbin:.PS1=0331;44mfranky is in w0330mPS2=More inputPWD=/nethome/frankySESSION_MANAGER=local/:/tmp/.ICE-unix/22106SHELL=/bin/bashSHELL_LOGIN=-loginSHLVL=2SSH_AGENT_PID=22161SSH_ASKPASS=/usr/libexec/openssh/gnome-ssh-askpassSSH_

35、AUTH_SOCK=/tmp/ssh-XXmhQ4fC/agent.22106START_WM=twmTERM=xtermTYPE=typeUSERNAME=frankyUSER=franky_=/usr/bin/printenvVISUAL=viWINDOWID=20971661XAPPLRESDIR=/nethome/franky/app-defaultsXAUTHORITY=/nethome/franky/.XauthorityXENVIRONMENT=/nethome/franky/.XdefaultsXFILESEARCHPATH=/usr/X11R6/lib/X11/%L/%T/%

36、N%C%S:/usr/X11R6/lib/X11/%l/%T/%N%C%S:/usr/X11R6/lib/X11/%T/%N%C%S:/usr/X11R6/lib/X11/%L/%T/%N%S:/usr/X11R6/lib/X11/%l/%T/%N%S:/usr/X11R6/lib/X11/%T/%N%SXKEYSYMDB=/usr/X11R6/lib/X11/XKeysymDBXMODIFIERS=im=noneXTERMID=XWINHOME=/usr/X11R6X=X11R6YACC=bison -y3.2.1.2. 本地变量 本地变量只存在于当前 shell。使用内建的不带选项的 se

37、t 命令将显示所有变量的列表(包括环境变量)和函数。输出会根据当前的设置排列而且以可以重用的方式显示。 以下是在退出了同样被 set 命令显示的函数之后,比较 printenv 和 set 的输出的文件: franky diff set.sorted printenv.sorted | grep “ export 1number=1bash: export: 1number=1: not a valid identifier在 shell 中设置一个变量,使用VARNAME=“value“ 在等号周围放置空格会造成错误。在对变量赋值得时候把内容字符串用引号引起来是一个良好的习惯:这样会降低出错

38、的机会。一些实用大小写,数字和空格的例子:franky MYVAR1=“2“franky 7gt; echo $MYVAR12franky first_name=“Franky“franky echo $first_nameFrankyfranky full_name=“Franky M. Singh“franky echo $full_nameFranky M. Singhfranky MYVAR-2=“2“bash: MYVAR-2=2: command not foundfranky MYVAR1 =“2“bash: MYVAR1: command not foundfranky MYV

39、AR1= “2“bash: 2: command not foundfranky unset MYVAR1 first_name full_namefranky echo $MYVAR1 $first_name $full_namefranky 3.2.3. 导出变量 Exporting variables 一个变量的建立后就像上面的例子那样仅仅存在于当前 shell。它是本地变量:当前 shell 的子进程不会意识到这个的存在。为了把变量传递到子 shell,我们需要使用内建的 export 命令把他们 输出 出来。被输出出来的变量就像环境变量一样,设置和输出变量通常用下面一步来完成: ex

40、port VARNAME=“value“ 一个子 shell 能够改变从父 shell 变量继承过来的变量,但是在子 shell 所作的改变对父 shell 也没有影响。下面的例子来证明这个:franky full_name=“Franky M. Singh“franky bashfranky echo $full_namefranky exitfranky export full_namefranky bashfranky echo $full_nameFranky M. Singhfranky export full_name=“Charles the Great“franky echo

41、$full_nameCharles the Greatfranky exitfranky echo $full_nameFranky M. Singhfranky 当第一次尝试在子 shell 里面读取 full_name 的值时,它并不存在(echo 显示了一个空字符串)。子 shell 退出,然后 full_name 在父 shell 里面export,一个变量在赋值后仍然可以被 export。然后一个新的子 shell 开始运行,从父 shell 那里 export 出来的变量是可见的。这个变量被修改来存放其他名字,但是在父 shell 中放置变量的值还是一样的。那么一个新的子 shel

42、l 启动后,从父 shell 那里 export 来的变量是可见的。当变量修改以存放一个其它的名字时,在父 shell 中这个变量的值仍然是原来的值。 3.2.4. 保留变量 3.2.4.1. Bourne shell 保留变量 Bash 和 Bourne shell 以同一种方法来使用特定的 shell 变量。某些情况下,Bash 为变量分配一个默认的值。下表给出一个简单的 shell 变量的概览:表 3.1. 保留的 Bourne shell 变量变量名字 定义CDPATH 一个由冒号分割的目录列表作为内建命令 cd 的搜索路径。 HOME 当前用户的 home 目录;默认为内建命令 cd 。这个变量的值同样被扩展使用。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 实用文档 > 简明教程

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报