Linux.Shell编程笔记-基本元素


第三章 编程的基本元素

再识变量

实例对 各种情况的测试计算

[hcr@slave2 temp]$ vim variable.sh
#!/bin/bash
a=2334
let "a += 1"
echo "a = $a"
echo
 
#替换成字母
b=${a/23/BB}
 
echo "b = $b"
 
declare -i b
echo "b = $b"
let  "b += 1"
echo "b =$b"
echo
 
#替换成数字
c=BB34
echo "c = $c"
d=${c/BB/23}
echo "d = $d"
let "d += 1"
echo "d = $d"
echo
# 为空值
 
e=""
 
echo "e = $e"
let e+=1
echo "e = $e"
 
# 为null
echo
 
echo "f = $f"
let "f += 1"
 
echo "f = $f"
echo 

shell中有3种变量:用户变量、位置变量{pracessing parameter)和环境变量。其中用户变

量在编程过程中使用最多,位置变量在对参数判断和命令返回值判断时会使用,环境变量主要是在程序运行的时候需要设置。

用户变量

声明变量

VarName=varValue

声明本地变量 local

但是必须得在脚本中去写。

Shell中的特殊符号

特殊字符

含义

用法

~

主目录,相当于 $HOME

cd ~

#

shell脚木中的注释

# 注释

··

命令替换.例如·pwd·返回pwd命令执行的结果字符串

abc=·which hadoop·

$

变量表达式符号

"a = $a"

&

后台作业,将此符号置于命令末端,则让命令于后台运行

sh start.sh &

*

字符串通配符

ls a* >>f.txt

()

在括号中执行子shell命令

(let "e = $b + $c";echo $e)

\

转义下一个字符

\\

|

管道

ps -ef |grep tomcat

[]

开始字符集通配符号和 if表达式

ls [a-z]*.sh
if [ "$1" != 0 ];then if

{}

命令块

a=${aa/12/34}

;

shell命令分隔符

(let "e = $b + $c";echo $e)

‘’

强引用

a='abc';

“”

弱引用

a="$a"

<

输入重定向

cat < a.txt > b.txt

>

输出重定向

cat a.txt > b.txt

/

路径名目录分隔符

cd /

单个任意字符

ll ??.sh

逻辑NOT

ll [!a-b].txt

替换运算符

 

:-
${varname:-word}

在符号前的变量如果存在且非空则返回符号前的变量,否则返回符号后的字符

echo ${name:-'else'}

:=
${varname:=word}

在符号前的变量如果存在且非空则返回符号前的变量,否则讲把符号后的字符赋值给符号前的变量

echo ${name:='else'}

:?
${varname:?word}

在符号前的变量如果存在且非空则返回符号前的变量,否则打印符号后的字符

echo ${name:?'else'}

:+
${varname:+word}

在符号前的变量如果存在则返回符号后的变量,否则返回null

echo ${name:+'else'}

如果上边的替换运算符去掉冒号(:) ,就是一样用但是条件少了一个且非空

匹配运算符

 

${varname#pattern}

必须以开头匹配pattern模式的最短字符串将被删除,返回剩余的字符串。否则返回全部

echo ${path#/*sr/}

${varname##pattern}

必须以开头匹配pattern模式的最长字符串将被删除,返回剩余的字符串。否则返回全部

echo ${path##/*sr/}

${varname%pattern}

必须以结尾匹配pattern模式的最短字符串将被删除,返回剩余的字符串。否则返回全部

echo ${path%/*}

${varname%%pattern}

必须以结尾匹配pattern模式的最长字符串将被删除,返回剩余的字符串。否则返回全部

echo ${path%%/*}

${varname/pattern/string}

匹配开始pattern模式的第一个字符串将被替换成string,如果string为null那么匹配的东西将被删除,返回处理后的数据。

echo ${path/hadoop/hadoop-0.2}

${varname//pattern/string}

匹配开始pattern模式的所有字符串将被替换成string,如果string为null那么匹配的东西将被删除,返回处理后的数据。

echo ${path//hadoop/hadoop-0.2}

${varname/#pattern/string}

必须以开头匹配开始pattern模式的最短字符串将被替换成string,如果string为null那么匹配的东西将被删除,返回处理后的数据。

echo ${path/#\/usr/\/www}或者
echo ${path/#‘/usr’/‘/www’}

${varname/%pattern/string}

必须以结尾匹配开始pattern模式的最短字符串将被替换成string,如果string为null那么匹配的东西将被删除,返回处理后的数据。

echo ${path/%\/usr/\/www}

位置变量

位置变量也称系统变量、位置参数,是shell脚本运行时传递给脚本的参数,同时也表示在shell函数内部的函数参数。它们的名称是以数字命名(由于历史原因,直接引用的位置参数只能从$0到$9超过这个范围则必须用括号括起来,如${10}。

shell内置了一个shift命令,shift命令可以“截去”参数列表最左端的一个。执行了shift后,$1的值将永远一丢失,而$2的旧值会被赋给$1,以此类推。表达参数总数的$#将会减一。shift是个可带参数的命令,例如,shift 2表示截去两个参数,而单纯的shift命令的含义是shift 1。 

[root@ebsdi-23260-oozie tmpFile]# cat shift.sh
#!/bin/bash
 
while [ -e $1 ];
do
        cat $1
        shift
done
[root@ebsdi-23260-oozie tmpFile]# vim for.sh
#!/bin/bash
 
for file in $*
do
 cat $file
done
~
环境变量

常用的环境变量

名称

描述

PATH

命令搜索路补,以胃号为分隔符。注意与D0S不同的是,
当前目录不在系统路径里

HOME

用户home目录的路径名,是cd命令的默认参数

COLUMNS

定义了命令编辑模式下可使用命令行的长度

EDITOR

默认的行编辑器

VISUAL

默认的可视编辑器

FCEDIT

命令fc使用的编辑器

HISTFILE

命令历史文件

HISTSIZE

命令历史文件中最多可包含的命令条数

HISTFILESIZE

命令历史文件中包含的最大行数

IFS

定义shell使用的分隔符

MAIL

指向一个需要shell监视其修改时问的文件。
当该文件修改后,Shell将发消息"You have a mail"给用户

MAILCHECK

shell检查MAIL文件的周期,单位是秒。

SHELL

shell的路径名

TERM

终端类型

TMOUT

shell自动退出的时间,单位为秒,若设为0,则禁正shell自动退出

PROMPT_COMMAND

指定在卞命令提示符前应执行的命令

PS1

主命令提示符

PS2

二级命令提示符,命令执行过程中要求输入数据时用

PS3

select的命令提示符

PS4

调试命令提示符

MANPATH

寻找手册页的路径,以胃号分隔

LOGNAME

用户登录名

MAILPATH

功能与MAIL类似。但可以用一组文件,
以冒号分隔,每个文件后跟一个问号和一条发向用户的消息

LD_LIBARAY_PATH

寻找库的路径,以冒号分割

启动文件

shell使用一些启动文件来协助创建一个运行环境,其中每个文件都有特定的用途,对登录

和交互环境的影响也各不相同。/etc目录下的文件提供全局设置,如果用户主目录下存在同名文件,它将覆盖全局设置。

使用/bin/login读取/etc/passwd文件成功登陆后,启动了一个交互登录shell。用命令行可以启动一个交互非登录shell(例如[prompt] $/hin/bash )。非交互shel l通常出现在shell脚本运行的时候,之所以称为非交互的,因为它正在运行一个脚本,而且命令与命令之间并不等待用户的输入。

无论运行什么shell,文件/etc/enviranment都先运行。即使用rexedc和rshd开始的shell,也应该设置定义在/etc/enviranment文件中的环境变量。

/etc/enviranment设置诸如最小搜索路径、时区、语言等用户环境。这个文件不是一个

shellscript,并且只接受以下数据格式:

name=<value>

(环境变量名=变量值)

init开始的所有进程都要执行这个文件,它影响所有的登录shell .

函数

作为一种完整的编程语言,Linuxshell必定不能缺少函数( function)支持:一段独立的程序

代码用于执行一个完整的单项工作。函数复用是优质代码的一大特征,故在一些大型的程序里,常常可以见到函数的身影。

当shell执行函数时,并不独立创建子进程。常用的做法是,将函数写入其他文件中,当需要的时候才将它们载入脚本。

执行命令的顺序

交互shell在获得用户输入时,并不是直接就在PATH路径中查找,而是按照固定顺序依次移

找命令位置。搜索顺序为;

别名 即使用aliascommand="..",创建的命令。

关键字 如if, fvro

函数 自定义的一些函数

内置命令 如cd, pwd等命令。

外部命令 即脚木或可执行程序,这才在path路径中查找

由此可见,在同名时,函数的优先级高于脚本。可以使用内置命令 command,buildin 和enable改变优先级顺序,它允许你将函数、别名和脚本文件定义成相同的名字,井选抒执行其中之一。

如果想要知道执行的命令是哪种类型,可以使用type命令。当重命名时,type命令会告诉你真正被执行的命令的来源是别名、函数或外部命令。
 

 [houchangren@ebsdi-23260-oozie shell]$ type user_login
user_login is a function
user_login ()
{
    if who | grep $1 >> /dev/null; then
        echo " user $1 is on";
    else
        echo " user $1 is off";
    fi
}
[houchangren@ebsdi-23260-oozie shell]$ type ll
ll is aliased to `ls -l --color=tty'
[houchangren@ebsdi-23260-oozie shell]$ type ls
ls is aliased to `ls --color=tty'
[houchangren@ebsdi-23260-oozie shell]$ type cat
cat is hashed (/bin/cat)

函数的使用规则

函数使用时,遵循一些重要规则:

》函数必须先定义,后使用。

》函数在当前环境下运行,共享调用它的脚木中的变量,并且,函数允许你以给位置参数赋值的方式向函数传递参数。函数体内部可以使用local限定词创建局部变量。

》如果在函数中使用exit命令,会退出脚本。如果想退回到原本调用函数的地方,则使用 return命令。

》函数的return语句返回函数执行最后一条命令的退出状态。

》使用内置命令export -f 可以将函数等出到子shell中。

》如果函数保存在其他文件巾,可以使用source或dot(就是圆点./start.sh)命令将它们装入当前脚木。

》函数可以递归调用,并且没有调用限制。

》可以使用declare -f 找到登录会话中定义的函数。函数会按照字母顺序打印所有的函数定义。这个定义列表可能会很长,需要使用文本阅读器more或less查看。如果仅仅想看函数名,则使用declare -F语句。

自动加载

如果想在每次启动系统时自动加载函数,则只需要将函数写入启动文件中。例如

$HOME/.profile中即可,则每次启动时,source$HOME/.profile都会自动加载函数.

函数定义

函数定义

[houchangren@ebsdi-23260-oozie shell]$ cat user_login.sh
#!/bin/bash
 
function user_login(){
if who | grep $1 >> /dev/null ; then
echo " user $1 is on"
else
echo " user $1 is off"
fi
 
}
[houchangren@ebsdi-23260-oozie shell]$ source user_login.sh
[houchangren@ebsdi-23260-oozie shell]$ user_login2 23
bash: user_login2: command not found
[houchangren@ebsdi-23260-oozie shell]$ user_login erpmerge
 user erpmerge is on
[houchangren@ebsdi-23260-oozie shell]$ user_login hbase
 user hbase is off
[houchangren@ebsdi-23260-oozie shell]$ unset -f user_login

使用source 读入文件内容

然后使用操作

unset -f 命令可以取消函数

函数的参数和返回值

由于函数是在当前shell中执行,所以变量对于函数和shell都可见。在函数内部对变量做的任何改动也会影响shell的环境。

参数 你可以像使用命令一样,向函数传递位置参数,位置参数是函数私有的,对位置参数的任何操作并不会影响函数外部使用的枉何参数。

局部变量限定词local 当使用local时,定义的变量为函数的内部变量。内部变量在函数退出时消失,不会影响到外部同名的变量。

返回方式return return命令可以在函数体内返回函数被调用的位置。如果没有指定return的参数,则函数返回最后一条命令的退出状态。return命令同样也可以返回传给它的参数。按照规定,return命令只能返回D到255之间的整数。如果在函数体内使用exit命令,则退出整个脚本。

[houchangren@ebsdi-23260-oozie shell]$ cat add.sh
#!/bin/bash
 
_add(){
let "sum=$1+$2"
return $sum
}
[houchangren@ebsdi-23260-oozie shell]$
[houchangren@ebsdi-23260-oozie shell]$ _add 12 23
[houchangren@ebsdi-23260-oozie shell]$ echo $?
35
条件控制和流程控制
条件控制

If/else

if who | grep 'sdfsdfds';
then echo 'right';
elseif who | grep 'sdfsdfsdfsd';
echo 'right';
else 
echo 'wrong';
fi
If [test] ;
 then
do cmd
elseif [test];
then
         docmd;
else
do cmd;
fi

ifelse组合,

if else

if elseif

if elseif if

退出状态

每条命令或函数,在退出时都会返回一个小的整数值给调用它的程序。这就是命令或函数的退出状态(exit status )。与c语言稍有不同的是,在判断语句中,条件(cnndition)实际上是语句列表,而不是般的布尔表达式。

按照惯例,函数以及命令的退出状态用0来表示成功,而非零表示失败。

POSIX中定义了退出状态对应的值

描述

0

成功

>0

在重定向或者单词展开期间(~、变量、命令、算数展开、单词切割等)操作失败

1-125

命令退出失败。特定退出值的定义,参见不同命令的定义

126

命令找到而无法执行命令文件

127

命令无法找到

>128

命令因受到信号而死亡

退出状态和逻辑操作

Not and or

If [ !condition];
then
         statement
if
 
If [ condition && condition2];
then
         statement
if

 
If [ condition || condition2];
then
         statement
if
条件测试

If语句

if test 2 -gt 3; then  echo '大于'; fi
if [ 2 -gt 3 ]; then  echo '大于'; fi

注意点,在使用 [ ]这个的时候一定要记得参数和符号之前有空格

字符串比较

-z string

字符串string 为空串(长度为0)时返回真

-n string

字符串string 为非空串时返回真

str1 = str2

字符串str1 和字符串str2 相等时返回真

str1 == str2

同 =

str1 != str2

字符串str1 和字符串str2 不相等时返回真

str1 < str2

按字典顺序排序,字符串str1 在字符串str2 之前

[houchangren@ebsdi-23260-oozie shell]$ cat if.sh
#!/bin/bash
if [ $1 = "test" ]
then
echo "right"
fi
[houchangren@ebsdi-23260-oozie shell]$ sh if.sh test
right
[houchangren@ebsdi-23260-oozie shell]$ sh if.sh test3
[houchangren@ebsdi-23260-oozie shell]$

字符串的操作符两边都必须有空格哦。

[houchangren@ebsdi-23260-oozie shell]$ cat checkUserIsExist.sh
#!/bin/sh
 
line=|grep $1 /etc/passwd |
if [ -n $line ]
then
        echo "user $1 exist"
fi
[houchangren@ebsdi-23260-oozie shell]$ sh checkUserIsExist.sh houchangren
user houchangren exist

整数数值比较

int1 -eq int2

如果int1 等于int2,则返回真

int1 -ne int2

如果int1 不等于int2,则返回真

int1 -lt int2

如果int1 小于int2,则返回真

int1 -le int2

如果int1 小于等于int2,则返回真

int1 -gt int2

如果int1 大于int2,则返回真

int1 -ge int2

如果int1 大于等于int2,则返回真

<

小于(在双括号里使用)

(("$a" < "$b"))

<=

小于等于 (在双括号里使用)

(("$a" <= "$b"))

>

大于 (在双括号里使用)

(("$a" > "$b"))

>=

大于等于(在双括号里使用)

(("$a" >= "$b"))

 考 :http://blog.csdn.net/ruishenh/article/details/17998921

文件属性检查

 

-b filename

当filename 存在并且是块文件时返回真(返回0)

-c filename

当filename 存在并且是字符文件时返回真

-d pathname

当pathname 存在并且是一个目录时返回真

-e pathname

当由pathname 指定的文件或目录存在时返回真

-f filename

当filename 存在并且是正规文件时返回真

-g pathname

当由pathname 指定的文件或目录存在并且设置了SGID 位时返回真

-h filename

当filename 存在并且是符号链接文件时返回真 (或 -L filename)

-k pathname

当由pathname 指定的文件或目录存在并且设置了"粘滞"位时返回真

-p filename

当filename 存在并且是命名管道时返回真

-r pathname

当由pathname 指定的文件或目录存在并且可读时返回真

-s filename

当filename 存在并且文件大小大于0 时返回真

-S filename

当filename 存在并且是socket 时返回真

-t fd

当fd 是与终端设备相关联的文件描述符时返回真

-u pathname

当由pathname 指定的文件或目录存在并且设置了SUID 位时返回真

-w pathname

当由pathname 指定的文件或目录存在并且可写时返回真

-x pathname

当由pathname 指定的文件或目录存在并且可执行时返回真

-O pathname

当由pathname 存在并且被当前进程的有效用户id 的用户拥有时返回真(字母O 大写)

-G pathname

当由pathname 存在并且属于当前进程的有效用户id 的用户的用户组时返回真

file1 -nt file2

file1 比file2 新时返回真

file1 -ot file2

file1 比file2 旧时返回真

f1 -ef f2

f1和f2硬链接到的是一个文件是为真

测试脚本

[houchangren@ebsdi-23260-oozie shell]$ ll
总计 24
-rw-rw-r-- 1 houchangren houchangren  51 01-08 10:46 add.sh
-rw-rw-r-- 1 houchangren houchangren  85 01-08 13:38 checkUserIsExist.sh
-rwxrwxr-x 1 houchangren houchangren 284 01-08 13:55 testalg.sh
[houchangren@ebsdi-23260-oozie shell]$ cat testalg.sh
#!/bin/bash
 
file=$1
if [ -d $file ]
then
echo "$file is dir"
elif [  -f $file ]
then
echo "$file is file "
        if [ -r $file ] && [ -w $file ] && [ -x $file ]
                then
                echo "You have read,write,execute permission  on $file";
        fi
else
echo "$file is neither a file and a directory"
fi
[houchangren@ebsdi-23260-oozie shell]$ sh testalg.sh /etc
/etc is dir
[houchangren@ebsdi-23260-oozie shell]$ sh testalg.sh ../
../ is dir
[houchangren@ebsdi-23260-oozie shell]$ sh testalg.sh testalg.sh
testalg.sh is file
You have read,write,execute permission  on testalg.sh
[houchangren@ebsdi-23260-oozie shell]$ sh testalg.sh /dev/null
/dev/null is neither a file and a directory
[houchangren@ebsdi-23260-oozie shell]$ 

Case语句

当存在很多个逻辑判断的时候if用起来就显着那么臃肿了。Case可以很简洁的指定

case也是一个流程控制结构。Parscal中的case语句和C语言中的switch语句被用来测试诸

如整数和字符的简单值。shell中的case语句。可以依据可包含通配符的模式测试字符串。

[houchangren@ebsdi-23260-oozie shell]$ cat testcase.sh
#!/bin/bash
case $1 in
    -f) echo "参数1是-f";;
    -d) echo "参数1是-d";;
    -x) echo "参数1是-x";;
    -w) echo "参数1是-w";;
    *)  echo "输入的参数不是预先估的参数!";;
esac
[houchangren@ebsdi-23260-oozie shell]$ sh testcase.sh -w
参数1是-w
[houchangren@ebsdi-23260-oozie shell]$ sh testcase.sh -ll
输入的参数不是预先估的参数!
循环控制

在众多高级语言中,循环总是不可缺少的元素。循环一让我们控制某些代码的重复行为,或允许对多个对象操作。

for循环是最简单的循环,我们在许多编程语言中都可以见到它的身影。在shell脚本里,对象可以是命令行参数、文件名,或者任何、可以以列表格式建立的东西。

[houchangren@ebsdi-23260-oozie shell]$ for file in *.sh
> do
> echo $file
> done
add.sh
a.sh
checkUserIsExist.sh
if.sh
testalg.sh
testcase.sh
user_login.sh
[houchangren@ebsdi-23260-oozie shell]$

在for循环中,如果in list被省略,则默认为in"$@",即命令行参数的引用列表。就好像你已经输入了for name in “$@”。

[houchangren@ebsdi-23260-oozie shell]$ cat testfor.sh
#!/bin/sh

for param
do
echo $param
done
[houchangren@ebsdi-23260-oozie shell]$ sh  testfor.sh 1
1
[houchangren@ebsdi-23260-oozie shell]$ sh  testfor.sh 1 2
1
2
[houchangren@ebsdi-23260-oozie shell]$ sh  testfor.sh 1 2 3 4
1
2
3
4
[houchangren@ebsdi-23260-oozie shell]$

While /until

While 和传统中的操作一样

While [ condition ]

do

docmd

done

until [ condition ]

do

docmd

done

while和until的操作一样,就是条件处理循环的时候是相反的。While是条件=true接着循环

跳出循环

break和continue语句允许对循环的运行精确控制:跳出循环或重新执行循环。

当嵌套层超过一层的时候可以指定break或者continue后加数字跳出(继续)指定的层

[houchangren@ebsdi-23260-oozie shell]$ cat testwhile.sh
#!/bin/bash

num=0
while true
do
echo "while1- $num"
        while true
        do
        echo "while2- $num"
                   while true
                        do
                        echo "while3- $num"
                        num=$(($num+1))
                        case $num in
                        5 ) break 2;;
                        10 ) break 3;;
                        * ) break 1 ;;
                        esac
                        done
                       
                done
        if [ $num -ge $1 ];
                then
                break 1
        fi
done
[houchangren@ebsdi-23260-oozie shell]$ sh testwhile.sh 10
while1- 0
while2- 0
while3- 0
while2- 1
while3- 1
while2- 2
while3- 2
while2- 3
while3- 3
while2- 4
while3- 4
while1- 5
while2- 5
while3- 5
while2- 6
while3- 6
while2- 7
while3- 7
while2- 8
while3- 8
while2- 9
while3- 9
[houchangren@ebsdi-23260-oozie shell]$

实例

[houchangren@ebsdi-23260-oozie shell]$ cat whileexample.sh
#!/bin/bash
author=false
list=false
file=""
 
while  [ $# -ge 0 ]
do
 case $1 in
        -f) file=$2;echo "filename:$file"; shift ;;
        -l) list=true;;
        -a) author=true;;
        --) shift;break ;;
        -*) echo $0:$1:unrecognized option ;;
        * ) break ;;
 esac
 shift
done
[houchangren@ebsdi-23260-oozie shell]$ sh whileexample.sh -f whileexample.sh
filename:whileexample.sh
[houchangren@ebsdi-23260-oozie shell]$ sh whileexample.sh -fx wer
whileexample.sh:-fx:unrecognized option
[houchangren@ebsdi-23260-oozie shell]$
用getopts工具来格式化参数

Getopts参考

http://www.Bkjia.com/os/201309/246174.html

[houchangren@ebsdi-23260-oozie shell]$ cat whileexample2.sh
#!/bin/bash
 
author=false
list=false
file=""
 
while getopts alf: opt
do
case $opt in
        f) file=$OPTARG;echo "file:$file" ;;
        l) list=true ;;
        a) author=ture;;
    esac
done
shift $(($OPTIND -1))
[houchangren@ebsdi-23260-oozie shell]$ sh  whileexample2.sh -f whileexample.sh
file:whileexample.sh
[houchangren@ebsdi-23260-oozie shell]$

相关内容