unix培训教材-SHELL编程

更新时间:2024-04-17 19:19:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

UNIX培训教材-SHELL编程

(内部使用)

恒 生 在 您 身 边

杭州恒生电子股份有限公司

第一章 概述

shell是一个命令解释器,它会解释你在命令提示符下输入的命令。但是,你可能有一组想要多次执行的命令。shell提供了一种功能,让你将这组命令存放在一个文件中,然后你可以象UNIX系统提供的其他程序一样执行这个文件。这个命令文件就叫做shell程序或者shell脚本。当你运行这个文件,它会象你在命令行输入这些命令一样地执行这些命令。

shell 程序设计语言支持在高级语言里所能见到的绝大多数程序控制结构,比如循环,函数,变量和数组。shell 编程语言很易学,并且一旦掌握后它将成为你的得力工具。任何在提示符下能键入的命令也能放到一个可执行的shell程序里,这意味着用shell语言能简单地重复执行某一任务。

? shell的种类

在UNIX系统里可以使用多种不同的shell可以使用。最常用的几种是 Bourne shell (sh), C shell (csh), 和 Korn shell (ksh)。三种shell 都有它们的优点和缺点。Bourne shell 的作者是 Steven Bourne。它是 UNIX 最初使用的shell 并且在每种 UNIX 上都可以使用。本书将以Bourne shell为基础来介绍shell编程知识。

? shell程序中的注释

推荐在shell程序中提供注释语句来注明程序的内容。注释由一个#符号开始。shell不会去执行任何在#之后的语句。#能够出现在命令行的任何位置。

? shell程序的执行

执行一个shell程序的一种方法是: sh shell_program arguments

这种方式激活一个子shell并且指定这个子shell为执行这个程序的命令解释器。这个程序文件不是必须为可执行的。

也可以在shell程序的第一行前加入#!/usr/bin/ shell_name来指定命令行解释器。因此,如果你当前正在Bourne shell下工作,但是想要执行一个C shell的脚本,你的C shell程序的第一行应该为:

#!/usr/bin/csh

此时shell脚本的许可权限必须被设置为可读和可执行。为了让shell可以找到程序,可以选择输入shell脚本的完全路径名,或者将这个脚本的路径放在于PATH环境变量指定的路径列表中。许多的用户会在他们的HOME目录下创建一个bin目录来存放他们自己开发的script,然后将$HOME/bin加入到他们的PATH环境变量中。

第二章 变量

? 变量的定义及类型

shell变量是弱变量,即该变量不需定义就能使用。

shell变量都是字符串变量。其中数字字符串有双重特性,即是字符串又是整型数据。当数字字符串变量进行运算时,取其整数部分进行运算,且其符号保留。而且只有数字字符串变量才能进行+-运算。

variable表示的仅是变量(如同C语言中的指针变量),$variable表示的是变量的值(如同指针变量前加*),在使用shell命令时,应注意需要的是变量,还是变量的值。

? 系统缺省的变量

位置参数变量

位置参数:$0 表示命令本身;$1 表示第一个参数;$2 表示第二个参数;以此类推到$9,共十个。

进程变量 $# 表示传递给shell命令文件的参数个数(不包括命令文件名本身) 例: $ test a b c $ echo $# $ 3

$? 表示执行命令的退出状态,其值为0,1等。正常退出为0,异常退出为

非0 $$ 变量的值为当前进程的进程号 $* 该变量的值为命令行的所有变元 $! 在后台运行的最后一个进程的进程号 $- 变量的值为shell中当前设置的各执行标志之名称组成的串

? 标准shell变量

ENV FCEDIT HOME LINENO MAIL MAILCHECK 保存用来初启新shell的文件名 保存fc命令的默认的编辑器名字 保存当前用户的主目录 保存当前脚本或函数的当前序列行号,在脚本和函数的上下文以外其值没有意义 保存shell查看新邮件的文件名 保存两次信箱查看之间的秒数 OLDPWD OPTARG PATH PPID PS1 PS2 PS3 PWD RANDOM SECONDS TMOUT

保存先前由cd命令设置的工作目录 保存getopts命令最近处理的可选参数的值 保存命令搜索路径 父进程的ID号 Shell的主提示符 Shell的次提示符 保存select命令的提示符 当前工作目录 每次它使用时都保存一个随机数 保存当前shell实例被启动以来经历的时间,如给SECONDS赋值,则SECONDS为赋的值加经历的时间 显示主提示符之后等待输入的秒数,如在指定时间没输入,则shell终止 ? 变量的作用空间

在shell脚本中定义的变量仅在脚本中有效,但使用如下的一些命令可以改变其作用域或属性:

①export [option] [name[=value]]

-- -f -n -p 缺省

表明选项结束,所有后续参数都是实参。 表明在”名-值”对中的名字是函数名。

把全局变量转换成局部变量,即命名的变量不在传给子shell。 显示全局变量列表(全局变量,即在子shell中也有效的变量)。 把变量定义为全局变量

注:全局变量,在子shell中也有效的变量 局部变量,只在shell脚本中有效的变量 ②let expression

用于求整型表达式的值,如表达式中有空隔,则必须用双引号把表达式括起来,例如: let count=1+2 ③local [name[=value]]

用于创建不能传给子shell的变量,该命令仅在过程内部有效;如local后不跟参数,那么在当前已定义的局部变量列表就送往标准输出显示。 ④readonly [option][name[=value]]

用于显示或则设置只读变量和函数,如readonly后不跟参数,则在案标准输出上显示已定义的只读变量和函数.

-- -f

表明选项结束.所有后续参数都是实参 创建只读函数

⑤unset [option] name [name?]

用于取消变量和函数的定义(即删除变量),但PATH、IFS、PPID、PS1、PS2、UID、EUID等变量不能删除。

? 引号规则

①用单引号(')把该字符串引起来,shell对单引号中的任何特殊字符不做任何解释,而只是简单保持原状,例:

$TestString='$PATH * \\\\[a-x]? 2>&1' $echo $TestString $$PATH * \\\\[a-x]? 2>&1

②用双引号把字符串引起来,则$、\\、`、\四个字符有特殊含义,要对其进行特殊解释: $ \\ `

用其后的变量的值来代替这个变量和$

告诉shell不要对它后面的那个字符进行特殊处理,按本意来处理 告诉shell用两个反引号之间的命令的结果代替那个命令串(包括两个反

引号) \

会同前一个\批配

例: $TestString=\

$echo $TestString

$ .:/usr/bin:/bin \\\

例: $TestString=\

$echo $TestString $ /usr/home `pwd`

? 变量替换

简单的变量替换用$ + 变量名即可,复杂的变量替换如下: 表示形式 说明 ${variable} 基本变量替换,花括号限定变量名的开始与结束 ${varibale:-如变量variable没有值,则表达式返回default的值 default} ${variable:=def如变量variable没有值,则表达式返回default的值;ault} 如果variable没有设置,则把default的值赋予它 ${variable:+def如果variable被设置,则这种表示形式返回value,否ault} 则返回空串 ${#variable} 这种表示形式返回variable值的长度,除非variable是*或者@.在为*或者@的特殊情况下,则返回$@表示的元素的个数.$@保存的是传给该脚本的参数清单 ${variable:?mes如果variable没有值,则这种表示形式返回messagesage} 的值.shell也显示出variable的名字,这种形式对捕获错误很有效

例:PS1=${HOST:-`uname –n`} 这里的替换不影响HOST本身的值。

例:PS1=${HOST:=`uname –n`}

执行完该语句后,HOST和PS1都被赋值。

第三章 输出

常用如下两个命令用于向终端打印信息: echo printf

echo命令常用于需要进行简单格式化的字符串打印;printf命令是Shell版本的C语言函数printf,它为格式化输出提供了高度的灵活性。

echo命令

用于向终端输出信息的最常用命令是echo命令,用法为: echo string

这里,string是要向屏幕打印输出的字符串,如命令: echo Hi 产生如下输出: Hi

也可以将空格嵌入到输出中,例如: $echo Hello World! Hello World!

除了空格,还可以在string中嵌入格式化转义序列。

echo命令的常用转义序列

转义序列 描述 \\n 打印一个换行符 \\t 打印一个跳格符(tab符) \\c 打印字符串时不带换行符 \\ \打印一个双引号 不管什么时候,如果在echo命令的输入字符串中用到转义序列,必须在字符串前后加上双引号。

printf命令

printf命令类似于echo命令,最基本的使用与echo一样,以下echo命令: echo \

等同于

printf \

printf命令与C语言中的printf函数一样,还可以使用格式化串来实现复杂的格式化输出功能,语法如下: printf format argument 格式化序列的格式如下: %[-]m.nx

这里%用于标识格式化序列的开始,x标识格式化序列的类型,下表给出了x常用的值:

格式化序列类型

字母 s c d x f 描述 字符串 单个字符 十进制整数 十六进制整数 符点数 第四章 输入

在shell中使用read 命令接收变量输入, 语法:

read variable [variable......] 例:

$ cat color6

echo This program prompts for user input

echo “please enter your favorite two colors -> \\c” read color_a color_b

echo The colors you entered are: $color_b $color_a $ chmod +x color6 $ color6

This program prompts for user input

Please enter your favorite two colors -> red blue The colors you entered are: blue red $ color6

This program prompts for user input

Please enter you favorite two colors -> red blue tan The color you enterd are :blue tan red

用户使用命令行参数传递信息进程序,在命令执行之前,用户必须知道正确的语法。有一种情况,你想要在用户执行程序的时候提示他输入这些参数。read命令就是用来在程序执行的时候收集终端键入的信息。

通常使用echo命令来提供用户一个提示,让用户知道程序正在等待一些输入,同时通知用户应该输入的类型。因此,每一个read命令应该在echo命令前面。

read命令会给出一个变量名的列表,这些变量会被用户在提示符下输入的词赋值(以空格分隔)。如果read命令定义的变量比输入的词要多,剩余变量

会被赋空值。如果用户输入的词要比变量多,剩余的数据会赋给列表中的最后一个变量。

一旦被赋值,你就可以象其他的shell变量一样存取这些变量。

以下例子提示用户输入要被安装的文件名: $ cat my_install3

echo $0 will install files into your bin directory echo “Enter the names of the files -> \\c” read filenames

mv $filenames $HOME/bin echo Instllation is complete ctrl + d

$ chmod +x my_install13

$ my_install13

my_install13 will install files into your bin directory Enter the names of the files -> f1 f2 Installaton is complete

这个安装会提示用户输入chmod和移动到$HOME/bin的文件名。这个程序给用户更多的关于应该输入数据情况的指引。而不像install2中用户必须在命令行中提供文件名。用户使用程序不需要特殊的语法。程序让用户确切地知道要输入什么。所有的输入的文件名都会被赋值给变量filenames。

第五章 重定向

shell提供重定向一个命令的输入和输出的功能。大多数的命令的输出是输出到终端屏幕;比如date,ls,who等等,很多命令从键盘得到输入,命令包括mail、write、cat。

在UNIX系统中任何对象都是一个文件,包括终端和键盘都是一个文件。输出重定向 让你将一个命令的输出送到除终端以外的其他的文件中。而输入重定向让你从键盘以外的文件中得到输入。

输出重定向可以用来捕获一个命令的输出,作为日志记录记录下来,或者对其进行更进一步的处理。输入重定向可以让你可以使用一个编辑器创建一个文件,然后将这个文件送到一个命令,而来代替没有编辑的能力的交互式的输入方式(例如mail命令)。

这一章介绍输入输出重定向,然后介绍一些UNIX的过滤器。过滤器是一种特殊的工具,它能进一步处理一个文件的内容。 标准输入,标准输出,和标准错误

每一次系统启动的时候,都会自动建立三个文件,这三个文件叫做标准输入,标准输出,标准错误。

shell从标准输入文件得到输入。这个文件使用C语言的描述符“0”,来打开,通常指向你的键盘。所以,当shell需要输入的时候,必须使用键盘来输入数据。

一些命令,如mail,write,cat,从标准输入得到输入,其方式为输入命令和参数,回车,然后命令会等待你提供输入来进行处理。输入的结束标志是回车和ctrl+d

shell将输出写到这标准输出文件,这个文件使用C语言的描述符号“1”来打开,通常为你的终端。因此,当shell产生输出,这些输出数据通常显示在你的屏幕上

大多数的UNIX命令会产生标准输出,这些命令有date,ls,cat,who等等。

shell会将错误信息输出到标准错误文件,这个文件使用C语言的描述符“2”来打开。同标准输出一样,标准错误会输出到你的终端。标准错误可以重新定向输出到独立的标准错误文件中。

大多数UNIX系统命令在被不恰当调用的时候会产生一个错误信息。想要看一个标准错误的例子,输入:cp 然后回车。cp使用信息会显示在你的屏幕上,而这些信息实际上是通过标准错误流来传送的。

输入重定向<和<<

任何命令,只要能从标准输入得到的输入,都可以被重定向从另外一个文件得到输入

例子: $ cat remind

your mother’s birthday is November 29 $ mail user3 < remind $ mail

$ From user3 Mon July 15 11:30 EDT 1993 your mother ‘s birthday is November 29 ?d $

命令从标准输入得到它的输入,但是你可以重定向输入,使其能够从其他文件而不是从键盘得到输入。mail 命令常常和输入重定向一起使用。我们可以用一个编辑器创建一个文件,其中包含一些我们想要mail的文本,然后我们可以重定向mail命令的输入,使其可以使用这个文件中的文本。这种方式在你有一个非常长的mail信息。或者你想要保留这个邮件信息作为将来的参考的时候非常有用。

而命令从标准输入得到输入的方式为:输入命令和参数,回车,然后命令会等待你提供输入来进行处理。输入的结束标志是回车和ctrl+d。

许多命令接受标准输入同时也接受文件名作为参数。这个作为参数的文件会被这个命令处理。cat命令就是一个很好的例子。cat命令可以显示直接从键

盘输入的文本,显示作为参数的文件的内容,或者显示通过重定向的文件的内容。

从标准输入得到输入 使用命令行参数 重定向输入 $ cat回车 在此输入文本 ctrl + d 结束

输入的文本的内容在这里显示 $ cat file 显示文本的内容 $ cat < file 显示文本的内容

注意:输入重定向不会改变被输入文件的内容。

输出重定向 >和>>

所有的可以输出到标准输出的命令都能重定向输出到另外一个文件。 例子;

建立/覆盖 建立/增加

$ date> date.out $ ls >>ls.out $ date > who.log $ who >> who.log $cat >cat.out $ ls >> who.log 在此输入文本 ctrl + d

许多命令都会在屏幕上输出。输出重定向让你可以捕获这些输出,并且保存为一个文本文件。

如果在一个命令的后面加上一个输出重定向符号(>),这个命令产生的标准输出就会输出到这个文件中,而不是到输出到屏幕上。如果这个文件在命令执行的时候并不存在,它会被自动建立。如果这个文件存在,它的内容会被覆盖;

如果想要在文件后添加,而不是覆盖文件,可以使用输出重定向的附加的符号(>>),如果文件不存在,也会被创建。在两个>符号之间不能有空格。

注意:shell不能在同一时刻打开同一个文件作为输入重定向和输出重定向。所以,唯一的限制是输入文件和输出文件必须不同。否则会丢失文件的原始的内容,而输出重定向也会失败。

例子: cat f1 f2 >f1 会导致文件f1的内容丢失。

错误重定向-2>和2>>

任何命令,只要能产生错误信息到标准错误,都可以将错误信息重定向到其它的文件

例子:

$ cp 2> cp.err $ cp 2>> cp.err

创建/覆盖 创建/增加

第六章 控制结构

test语句

test命令被用来测试表达式并且产生返回值。它用参数组成逻辑表达式并且对表达式进行测试。test命令不会产生标准输出。你必须必须通过返回值来判断test命令的结果。如果表达式为真,返回值会为0,如果表达式为假,返回值为1。

test命令可以被单独使用,然后你能够看到返回值,但它用的最多的还是在if和while结构中,用来提供条件流程控制。

test命令的也可以用[expression]来代替。这对提高可读性有帮助,特别是在处理数字或者字符串的时候。

注意:在\和\符号的周围必须要有空格。 语法:

test expression 或者 [expression] 表达式的值 返回值 true0

false 非零(通常为1) test命令能够测试的对象有:

? ? ?

整数 字符串 文件

test测试数字 语法:

[ number relation number ] 通过关系运算符来对数字进行比较

关系运算符: -lt 小于 -le 小于或者等于 -gt 大于 -ge 大于或者等于 -eq 等于 -ne 不等于 例子(假设X=3):

$ [ \注:7后不能有空格 $ echo $?  0

$ [ \$ echo $? 1

test测试字符串 语法:

[ string1 = string2] 判断字符串是否相等 [ string1 !=string2] 判断字符串是否不等 [ -z string ] 判断字符串的长度是否为零 [ -n string ]判断字符串的长度是否为非零 [ string ] 判断字符串的长度是否为非零

例子: $ X=abc

$ [ \$ echo $? 0

test测试文件 语法:

test -option filename通过选项对文件进行测试 -f file -s file -r file -w file -x file

如果文件存在并且是一个普通文件的时候为真 如果文件存在并且其字节数大于0的时候为真 如果文件存在并且是可读的时候为真 如果文件存在并且是可写的时候为真 如果文件存在并且是可执行的时候为真 目录存在并且是个目录的时候为真

-d directory 例子:

$ test -f funfile $ echo $? 0

$ test -d funfile $ echo $? 1

test其它操作

语法: ! -o -a

NOT OR AND GROUPING

\\( \\) 例子:

$ [ \

$ [ \

$ [ \\( $# = 2 \\) -a \\( \$ test -s file -a -r file 注意:()前面必须要用斜杠。

exit语句

exit命令停止执行当前的shell程序,并且根据提供的参数为这个shell程序设置一个返回值,如果没有提供返回值参数,当前的shell程序的返回值会被设置为在exit命令之前执行的命令的返回值。 语法: exit [arg] 例子:

$ cat exit_test

echo exiting program now exit 99

$ exit_test

exiting_program now $ echo $? 99

if语句

if 结构提供了一种基于命令返回值的的流程控制。如果指定的命令的返回值为0,一个指定的命令列表就会被执行,如果用于判断的命令返回值为非0,指定命令列表会被忽略而不被执行。 语法:

if ( expression ) then

[commands] else

[commands] endif 例子:

if test -s funfile then

echo funfile exists fi

echo hello

另外还可以用else if:

if ( expression ) then [commands]

else if ( expression ) then [commands] else

[commands] endif

还可以用简化格式:

if ( expression ) command 或者

if ( expression ) \\ command

# \后面只能接newline(回车即可), 不能有任何其他字符; # 单个命令command不能包括\以及\也不能使用其它控制语句.

但不能使用下面的格式: if ( expression ) then 或

if ( expression ) then command endif

case语句

if-else结构也能支持多路的分支,但是当有两个或者三个分支的之后,程序会变得十分烦琐。case结构提供了实现多路分支的一种更方便的方法。分支的选择是基于顺序的对一个word和提供的参数之间的比较结果。这些比较是是严格的基于字符串的对比。当一个匹配发现的时候,对应的命令就会被执行。每个命令的列表都以两个分号结束。在完成了相关的比较之后,程序会在esac之后继续执行下去。 语法:

case word in pattern1) list A ;; pattern2)list B ;; patternN) list N  ;;

esac

以下是一些pattern允许的特殊的字符: * 匹配任何字符串和字符包括空字符 ? 匹配任何单个的字符。

[...] 匹配任何一个括号出现中的字符 另外|字符的意义是OR。 例子: case $ANS in yes) echo O.K ;;  no) echo no go ;; esac

while语句

while语句是shell提供的一种循环机制,当条件为真的时候它允许循环体中的命令(继续执行。条件判断是通过条件中的最后一个命令的返回值来进行。通常一个test被用作控制循环的执行,但是任何命令都能被用来产生一个返回值。

语法:

while  list A do

 list B done

例子:

$ cat test_while X=1

while (( X <= 10 )) do

echo hello X is $X let X=X+1 done

$ test_while hello X is 1 hello X is 2 . . .

hello X is 10

until语句

until语句是shell提供的另一种循环机制,它会持续执行命令直到一个条件为真为止。同while循环类似,条件判断由条件中的最后一条命令的返回值来决定的。 语法: until

list A do

list B done 例子:

$ cat test_until X=1

until (( x > 10 ))

do

echo hello X is $X

let X=X+1 done

$ test_until hello X is 1 hello X is 2 hello X is 3 . . .

hello X is 10 for语句

for语句对列表的每一条目都进行一次循环过程,每完成一次循环过程就将var赋予列表中下一个条目,直到完成最后一个条目的循环为止。 语法:

for var in list do

list A done 例子:

$ cat test_for for X in 1 2 3 4 5 do

echo \let X=X*2 echo $X done

$ test_for 2 * 1 is 2 2 * 2 is 4 2 * 3 is 6 2 * 4 is 8 2 * 5 is 10 存取命令行参数

你可以从命令行参数来产生list:

for i in $* do

cp $i $HOME/backupsdone 或者: for i do

cp $i $HOME/backups done 

break、continue语句

break命令会中止循环并且将控制权传递到done关键字后面的第一个命令。结果是完全跳出这个循环体而继续执行下面的命令。

continue命令有一点不同。当在程序执行过程中遇到这个命令,就会忽略本次循环中剩余的命令,而将控制权交给循环的顶部。这样,continue命令能让你仅仅中止循环过程中的一个反复但是继续从循环的顶部开始执行。 在while和until循环中,这种处理(continue)会导致在初始列表的开始部分继续执行,在for循环中,会将变量设置为列表中的下一个条目,然后继续执行循环。

例子: while true do

echo \ read FILE

if test ! -f $FILE then

echo $FILE is not a regular file continue fi

echo removing $FILE rm $FILE break done

第七章 函数

在shell中允许将一组命令集或语句形成一个可用块,这些块称为shell函数。定义函数的格式为: 函数名() { 命令1 . . . } 或者 函数名(){ 命令1 . . . }

两者方式都可行。如果愿意,可在函数名前加上关键字function: function 函数名() { ... }

可以将函数看作是脚本中的一段代码,但是有一个主要区别。执行函数时,它保留当前shell和内存信息。此外如果执行或调用一个脚本文件中的另一段代码,将创建一个单独的shell,因而去除所有原脚本中定义的存在变量。

函数可以放在同一个文件中作为一段代码,也可以放在只包含函数的单独文件中。函数不必包含很多语句或命令,甚至可以只包含一个echo语句。以下是一个简单函数: hello() {

echo \}

所有函数在使用前必须定义。这意味着必须将函数放在脚本开始部分,直至shell解释器首次发现它时,才可以使用。调用函数仅使用其函数名即可。上面的例子中,函数名为hello,函数体包含一个echo语句,反馈当天日期。

在脚本中使用函数

现在创建函数,观察其在脚本中的用法。 #!/bin/sh hello() {

echo \}

echo \hello

echo \

运行脚本func1,结果为: $func1

now going to the function hello

Hello there today 's date is Fri Jul 22 09:05:37 BEIJING 2005 Back from the function

上面例子中,函数定义于脚本顶部。可以在脚本中使用函数名hello调用它。函数执行后,控制返回函数调用的下一条语句,即反馈语句back from the function。

从调用函数中返回

当函数完成处理或希望函数基于某一测试语句返回时,可做两种处理: 1) 让函数正常执行到函数末尾,然后返回脚本中调用函数的控制部分。

2) 使用return返回脚本中函数调用的下一条语句,可以带返回值。0为无错误,1为有错误。

函数返回值测试

可以直接在脚本调用函数语句的后面使用最后状态命令来测试函数调用的返回值。例如:

check_it_is_a_directory $FILENAME if [$? = 0] then

echo “All is OK” else

echo “Something went wrong!” fi

本文来源:https://www.bwwdw.com/article/bnip.html

Top