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

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

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","$2",$3")
$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命令找不到目录,可切换到参数形态指定的目录下。