首页 > 代码库 > linux资料整理之shell编程

linux资料整理之shell编程

博客:http://lijinhuan.blog.51cto.com/

微博:http://weibo.com/lijinhuanexperience

微信:xiaoleetongxue






一、shell脚本执行方式

1sh命令执行脚本文件

    vi hello.sh

    i进入插入模式

    输入echo hello world!

    :输入wq保存退出

    sh hello.sh


2给脚本文件添加执行权限,用./命令执行

chmod 755 hello.sh

./hello.sh


二、vi编辑器

1命令模式下用i(sert),a(ppend)o,s等均可进入编辑模式。按esc返回命令模式

2、退出相关命令

   :q! 不存档强制退出。

   :w 保存但不退出,w(rite)后可加所要存档的文档名。

   :wq 存档后退出。

   命令模式下按zz,功能与 :wq 相同。

   :x :wq相同

    命令模式:

ZZZQ保存/不保存退出

3、编辑

:从光标所在位置后面开始新增资料

        :在光标所在行下新增一列并进入输入模式。

4、在命令模式下执行

1dd :删除光标所在的行

2#dd 删除多个行,如3dd 表示删除光标行及光标的下两行

3d$ 删除光标到行尾的内容

4u:恢复刚才被修改的文本  U:恢复光标所在行的所有修改

5yy: 复制整行

6nyy:复制包括当前行在内的n

7P粘贴

8nG:移动到底n行行首

9:/string搜索指定的字符串。按键n:继续进行搜索

10set nu ‘显示行号

11syntax on(syn on) ‘语法高亮


    

三、shell变量与语法

 1shell的基本元素

        (1#/bin/bash 必须的,指出shell类型

        (2注释

       (3)变量

       (4)控制


[jinhuan.li@virt_host_194_dev shell]$ vim test1.sh

#! /bin/bash

#this is clear

ls -alh

echo "gogogogogo"



 2、执行shell脚本

  1一般以.sh为文件后缀。没有也能执行。

  (2常见的两种执行方式

     . /文件名在当前目录下写明路径执行,要求文件必须有执行权限,如

     chmod 755 run.sh

     . /run.sh

     sh 文件名

 sh run.sh

   (3文件开头指定一个或多个解释脚本程序的shell,如#!/bin/bash

如果指定,注意/bin不要漏了“/”,否则用./方式执行会找不到路径。

不指定的话一般默认以/bin/sh执行shell脚本



 3shell程序一般结构

        #! /bin/bash

#example

function sayhello(){

        echo "Enter your name:"

        read name

        echo "Hello ${name}"

}

echo "programme starts here"

sayhello

echo "programme ends"



 4shell中的特殊符号

   (1、注释符#

       除了#!/bin/bash里的#特殊

   (2、美元符 $

变量符。与反斜杠转义符相反,使其后的普通字符作为变量名,如$a表示变量a的值。变量字符长度超过1个时,用{}括起来

   (3、单引号

被引起的字符全部做普通字符,即全部原样

echo my $SHELL

4、双引号

引号内的内容,除$、转义符\、倒引号`这三个保留特殊功能,其他字符均做普通字符。

5、倒引号(数字1键旁边的那个键)

引号内的字符串当做shell命令行解释执行,得到的结果取代整个倒引号括起来的部分。


  [jinhuan.li@virt_host_194_dev shell]$ echo ‘my home $HOME‘

my home $HOME

  [jinhuan.li@virt_host_194_dev shell]$ echo "my home $HOME"

my home /home/jinhuan.li

  [jinhuan.li@virt_host_194_dev shell]$ echo "my home `pwd`"

my home /home/jinhuan.li/shell

  [jinhuan.li@virt_host_194_dev shell]$ echo ‘my home `pwd`‘

my home `pwd`



6反斜线

     反斜线是转义字符,它能把特殊字符变成普通字符。在某个字符前面利用反斜杠(\)能够阻止shell把后面的字符解释为特殊字符。

4

[yuqun@yuqun ~]$echo  Filename  is  N0\$\*

Filename  is  N0$*


     注意:在单引号括起来的字符串中,反斜线也成为普通字符,而失去转义字符功能。

[jinhuan.li@virt_host_194_dev shell]$ echo "NO$*"

NO

[jinhuan.li@virt_host_194_dev shell]$ echo "NO\$\*"

NO$\*




 5、变量

1shell 变量 可以保存如路径名、文件名或者一个数字

本地变量  局部变量只在创建它们的Shell中使用,可以在shell程序内任意使用和修改它们。


环境变量  可以在创建它们的Shell及其派生出来的任意子程序中使用。有些变量是用户创建的,其他的则是专用的(比如PATHHOME)。是系统环境的一部分,不必去定义它们,可以在shell程序中使用它们 。还能在shell中加以修改。

内部变量  由系统提供的。与环境变量不同,但用户不能修改它们。


[jinhuan.li@virt_host_194_dev shell]$ name=lijinhuan

[jinhuan.li@virt_host_194_dev shell]$ echo $name

lijinhuan

[jinhuan.li@virt_host_194_dev shell]$ exit

exit

[root@virt_host_194_dev ~]# echo $name


[root@virt_host_194_dev ~]# name=lijinhuan

[root@virt_host_194_dev ~]# echo $name

lijinhuan

[root@virt_host_194_dev ~]# echo $name

lijinhuan

[root@virt_host_194_dev ~]# bash

[root@virt_host_194_dev ~]# echo $name


[root@virt_host_194_dev ~]# echo $PATH

/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin

[root@virt_host_194_dev ~]# echo $HOME

/root

[root@virt_host_194_dev ~]# 


(2)本地变量(用户变量,局部变量)

 本地变量 在用户现在的shell生命期的脚本中使用

 变量名=

 注意:

    -1-等号两边不可以有空格

    -2-取值包含空格,必须用双引号括起来

    -3-Shell变量可以用大小写字母,区分大小写

    

3)变量声明和使用

     -1-变量是弱类型的(不用声明类型)

     -2-变量声明及赋值格式

        变量=值(等号两边不能有空格)

     -3-变量的引用

        $变量名   

         ${变量名}

     变量名为1个字符时建议使用方式一,多余一个字符时建议使用方式二

     举例: $a

        ${abc}


 

4显示变量

      -1-echo命令可以显示单个变量取值,变量名前加$

      

(5)清除变量

         unset 变量名

         举例:echo ${name}

         unset name (注意:name前没有$)

        显示本地所有变量 set


    (6设置只读变量

     设置变量时,不想再改变其值,可以将之设为只读变量

     变量名=

     readonly  变量名


(7)环境变量

环境变量用于所有用户进程(通常称为子进程)。登陆进程称为父进程,通过pstree可以查看

环境变量可以用于所有子程序,着包括编辑器、脚本和应用

    举例:vi a.sh

                #!/bin/bash

                # 检测环境变量

                echo "家目录是 $HOME"

   环境变量可以在命令行中设置,但用户注销时这些值将丢失

   环境变量均为大写

   必须用export命令导出


8设置环境变量 

   variable-name=value

   export variable-name(环境变量名大写)


9显示环境变量

    env 可以看到所有的环境变量

    echo $环境变量名 (显示一个变量)


     (10清除环境变量

     unset 环境变量名



HOME : 代表使用者的家目录。cd ~ 去到使用者的家目录 或者利用 cd 就可以直接回到使用者家目录了。

PS1shell的主提示符

 SHELL : 目前这个环境使用的 SHELL 是哪个程序? 如果是 bash 的话,预设是 /bin/bash

PWD:用户当前工作目录的路径。它指出用户目前在Linux文件系统中处在什么位置。它是由Linux自动设置的

 HISTSIZE : 这个与“历史命令”有关,曾经下达过的指令可以被系统记录下来,而记录的“数目”则是由这个值来设定的。 


 ENV : 这个使用者所使用的个性化环境设置文件的读取文件。 

MAIL : 当我们使用 mail 这个指令在收信时,系统会去读取的邮件信箱文件 (mailbox)。 

 PATH : 就是执行文件搜寻的路径,目录与目录中间以冒号(:)分隔, 由于文件的搜寻是依序由 PATH 的变量内的目录来查询,所以,目录的顺序也是重要的喔。 

LANG : 语系文件,很多数据都会用到他,当出现编码错误的时候往往需要设置它,中文编码是zh_CN.UTF8


(11)环境变量设置与应用举例

举例:配置java环境变量可使任何目录都能执行javac命令

  -1-需要配置Java环境变量

     JAVA_HOME(JDK存放的路径)

     CLASSPATH(字节码的位置,让JVM知道要运行的类的字节码放在哪)

     PATH (OS找到javac等命令的存放的位置)

  -2-Linux下配置它们

   打开终端

   vi .bash_profile

   在配置文件中追加内容 

      JAVA_HOME=JDK存放位置

      CLASSPATH=.(当前目录)

      PATH=$JAVA_HOME/BIN:$PATH(不覆盖原来的内容,追加)

      export JAVA_HOME CLASSPATH PATH

  保存,让配置起作用(source .bash_profile或者注销)


让环境变量的修改在退出shell再次登录时仍有效,需要在相关配置文件中修改

Bash的初始化文件有:/etc/profile~/.bash_profile~/.bash_login~/.profile~/.bashrc/etc/bashrc



/etc/profile 存放一些全局(共有)变量,不管哪个用户,登录时都会读取该文件。通常设置一些Shell变量PATH,USER,HOSTNAMEHISTSIZE

~/.bash_profile:每个用户都可使用该文件输入专用于自己使用的shell信息,当用户登录时,该文件仅仅执行一次!默认情况下,他设置一些环境变量,执行用户的.bashrc文件.


~/.bashrc:该文件包含专用于你的bash shellbash信息,当登录时以及每次打开新的shell,该该文件被读取.


/etc/bashrc:为每一个运行bash shell的用户执行此文件.bash shell被打开时,该文件被读取.



上述配置文件的作用

1)登录Linux先启动系统配置文件/etc/profile,并从/etc/profile.d目录的配置文件中搜集shell的设置,为系统的每个用户设置环境信息。

2)用户配置文件~/.bash_profile,每个用户专用于自己使用的shell信息,仅用户登录时执行一次!

默认情况下,此文件通过脚本执行同目录下用户的.bashrc文件。

3~/.bashrc文件包含专用于用户bash shellbash信息,登录及每次打开新的shell时都会执行。里面又会调用/etc/bashrc



      (12)设置自己的环境变量

        /home/user/.bash_profile中定义下句,会怎样?

alias la=ls a|grep \.*”’

答:user下次再登陆,其shell会自动建立一个别名命令la,功能为查看当前目录下名字以.开头的文件。

写在~/.bash_profile中,需重新登录才能有效。除非运行source .bash_profile使其立即有效。

写在~/.bashrc中,则打开新的终端中就有效

区别:bash_profile只在会话开始的时候读取一次,而bashrc则每次打开终端时都会读取

按照传统,定义的变量如PATH放到.bash_profile中,而像别名函数等放在.bashrc中,但是.bash_profile先于.bashrc读取内容,也可全放入.bashrc


     (13)内部变量

     3、内部变量

内部变量是Linux所提供的一种特殊类型的变量,这类变量在程序中用来作出判断。在shell程序内这类变量的值是不能修改的。

部分内部变量是:

$# ——传送给shell程序的参数的数量

$?——最后命令的完成码或者在shell程序内部执行的shell程序(返回值)

$0——shell程序的名称

$*——调用shell程序时所传送的全部参数的单字符串, “参数1”“参数2”…形式保存的参数


$@“参数1”“参数2”…形式保存的参数

$nn个参数


$$本程序的PID

$!上一个命令的PID



[jinhuan.li@virt_host_194_dev shell]$ vim test3.sh

#!/bin/bash

echo "\$0 : $0 "

echo "\$# : $#"

echo "\$* : $*"

echo "\$@ : $@"

echo "\$1 : $1"



echo "\$$ : $$"

echo "\$! : $!"

echo "\$? : $?"





四、变量表达式

1条件判断命令test

test n1 -参数 n2(或 –参数 表达式)

真返回0,假返回1

1)整数,比较运算符见右表

test 1 lt 4  #判断1<4

echo $?  #结果为0

·test语句的等价形式[ 1 lt 4 ]

可用中括号代替test,把表达式括起来实现判断

注意表达式与中括号间有空格。


注:

-lt小于

-le小于等于

-gt大于

-ge大于等于

-eq等于

-ne不等于



[jinhuan.li@virt_host_194_dev shell]$ test 1 -lt 4;echo $?;

0

[jinhuan.li@virt_host_194_dev shell]$ test 5 -lt 4;echo $?;

1


[jinhuan.li@virt_host_194_dev shell]$ vim test4.sh

#!/bin/bash

if test $1 -gt 0

then

        echo "$1 is positive!"

else

        echo "$1 is error!"

fi






2、文件测试


判断

-f存在且是普通文件

-d存在且是目录

-s存在且字节数大于0

-r存在且可读

-w存在且可写

-x存在且可执行

如:test -d mydoc

判断mydoc是否是目录




[jinhuan.li@virt_host_194_dev shell]$ vim test5.sh 

#! /bin/bash

if [ $# -ne 1 ]

then    

        echo "usage -$0 file-name"

        exit 1

fi


if [ -f $1 ]

then

        echo "$1 file exist"

else

        echo "sorry $1 file does not exists"

fi


[jinhuan.li@virt_host_194_dev shell]$ sh test5.sh 

usage -test5.sh file-name

[jinhuan.li@virt_host_194_dev shell]$ sh test5.sh test

sorry test file does not exists

[jinhuan.li@virt_host_194_dev shell]$ sh test5.sh test1.sh 

test1.sh file exist


3、字符串测试

test s  字符串s非空

test s1=s2字符串s1等于s2

test s1!=s2字符串s1不等于s2 

test  -z  s字符串长=0,即为空串

test  -n字符串长>0



4、其他参数

-a逻辑与

-o逻辑或

逻辑非



5、流程控制

(1)表达式求值

$ expr 1 + 3

$ expr 2 – 1

$ expr 1 \* 3 使用*要加转义符

$ echo `expr 1 + 3`

注意:表达式中,数字和运算符指教要有空格,出现在语句中要加反引号


(2)分支结构

[root@virt_host_194_dev shell]# vim myif.sh 

#!/bin/bash

if [ $# -eq 0 ]

then

        echo "0 params"

elif [ $# -gt 1 ]

then

        echo "more than 1 params"

else

        echo "1 params"

fi


[root@virt_host_194_dev shell]# sh myif.sh 

0 params

[root@virt_host_194_dev shell]# sh myif.sh sdfds

1 params

[root@virt_host_194_dev shell]# sh myif.sh sdfdssdfsdf sfsdf

more than 1 params



[root@virt_host_194_dev shell]# vim case.sh 

#!/bin/bash

case "$#" in

        0) echo "0 params" ;;

        1) echo "1 params" ;;

        *) echo "more  params" ;;

esac



[root@virt_host_194_dev shell]# sh case.sh 

0 params

[root@virt_host_194_dev shell]# sh case.sh sdf

1 params

[root@virt_host_194_dev shell]# sh case.sh sdf sfsd

more  params



3)循环结构

[root@virt_host_194_dev shell]# vim for.sh 

#!/bin/bash

for i in `seq 1 9`

do

        echo `expr $i \* 10`

done


[root@virt_host_194_dev shell]# sh ./for.sh 

10

20

30

40

50

60

70

80

90


read 变量1 [变量]

可以从键盘上读取多个变量的值,用户输入数据时,以空格或者Tab键作为分隔。

如果输入的数据个数不够,则从左到右对应赋值,没有输入的变量为空;

如果输入的数据个数超了,则从左到右对应赋值,最后一个变量被赋予剩余的所有数据。


[root@virt_host_194_dev shell]# vim for.sh 

#!/bin/bash

read a b

for i in `seq $a  $b`

do

        echo `expr $i \* 10`

done



[root@virt_host_194_dev shell]# sh ./for.sh 

2 8

20

30

40

50

60

70

80



i=1

sum=0

while [ $i le 100 ]

do

sum=$[$sum+$i]

  i=$[$i+1]

done

echo $sum


[ ]:直接求值命令




五 命令结果重定向

1stdout标准输出

2stderr标准错误

输出重定向到文件file,终端上只能看到标准错误:
#命令 >file

错误重定向到文件file ,终端上只能看到标准输出:
#命令 2>file

标准输出和标准错误都重定向到file,终端上看不到任何信息:
#命令 >file 2>&1 

(等于#命令 1>file 2>&1


屏蔽命令任何输出的:>/dev/null  2>&1
cp /etc/my.conf  >/dev/null  2>&1

/dev/null空设备

此句命令的结果是:

cp命令没有目标文件,应该输出错误。 

2>&1表示错误重定向指向标准输出。

>/dev/null又使标准输出重定向到空,就是不要输出信息

即:一个错误的命令执行,什么功能都不实现,且没有任何信息或错误提示输出。





1command >file 2>file

2command >file 2>&1 

有什么区别? 

      1)的写法,stdoutstderr都直接送到file会出现两个同抢占file的管道,file会被打开两次,stdoutstderr输出的信息会互相覆盖。

      2)的写法将stdout直接送向file, stderr继承1的管道后,再被送往file,此时,file 只被打开了一次,也只使用了一个管道FD1,它包括了stdoutstderr的内容。
      IO效率上,前一条命令的效率要比后面一条的命令效率要低,所以在编写shell脚本的时候,常用command > file 2>&1 这样的写法。



linux资料整理之shell编程