zoukankan      html  css  js  c++  java
  • shell脚本基础和编写规范

    1.什么是shell,以及shell命令的两种执行方式:

     

    Shell本身是一个用C语言编写的程序,它是用户使用Unix/Linux的桥梁,用户的大部分工作都是通过Shell完成的。Shell既是一种命令语言,又是一种程序设计语言。作为命令语言,它交互式地解释和执行用户输入的命令;作为程序设计语言,它定义了各种变量和参数,并提供了许多在高级语言中才具有的控制结构,包括循环和分支。
        它虽然不是Unix/Linux系统内核的一部分,但它调用了系统核心的大部分功能来执行程序、建立文件并以并行的方式协调各个程序的运行。因此,对于用户来说,shell是最重要的实用程序,深入了解和熟练掌握shell的特性极其使用方法,是用好Unix/Linux系统的关键。
        可以说,shell使用的熟练程度反映了用户对Unix/Linux使用的熟练程度。
    注意:单独地学习 Shell 是没有意义的,请先参考Unix/Linux入门教程,了解 Unix/Linux 基础。
    Shell有两种执行命令的方式:

    • 交互式(Interactive):解释执行用户的命令,用户输入一条命令,Shell就解释执行一条。
    • 批处理(Batch):用户事先写一个Shell脚本(Script),其中有很多条命令,让Shell一次把这些命令执行完,而不必一条一条地敲命令。


        Shell脚本和编程语言很相似,也有变量和流程控制语句,但Shell脚本是解释执行的,不需要编译,Shell程序从脚本中一行一行读取并执行这些命令,相当于一个用户把脚本中的命令一行一行敲到Shell提示符下执行。

        Shell初学者请注意,在平常应用中,建议不要用 root 帐号运行 Shell 。作为普通用户,不管您有意还是无意,都无法破坏系统;但如果是 root,那就不同了,只要敲几个字母,就可能导致灾难性后果。

    2.常见的几种shell

    上面提到过,Shell是一种脚本语言,那么,就必须有解释器来执行这些脚本。

    Unix/Linux上常见的Shell脚本解释器有bash、sh、csh、ksh等,习惯上把它们称作一种Shell。我们常说有多少种Shell,其实说的是Shell脚本解释器。

    bash

    bash是Linux标准默认的shell。bash由Brian Fox和Chet Ramey共同完成,是BourneAgain Shell的缩写,内部命令一共有40个。

    Linux使用它作为默认的shell是因为它有诸如以下的特色:

    • 可以使用类似DOS下面的doskey的功能,用方向键查阅和快速输入并修改命令。
    • 自动通过查找匹配的方式给出以某字符串开头的命令。
    • 包含了自身的帮助功能,你只要在提示符下面键入help就可以得到相关的帮助。

    sh

    sh 由Steve Bourne开发,是Bourne Shell的缩写,sh 是Unix 标准默认的shell。

    ash

    ash shell 是由Kenneth Almquist编写的,Linux中占用系统资源最少的一个小shell,它只包含24个内部命令,因而使用起来很不方便。

    csh

    csh 是Linux比较大的内核,它由以William Joy为代表的共计47位作者编成,共有52个内部命令。该shell其实是指向/bin/tcsh这样的一个shell,也就是说,csh其实就是tcsh。

    ksh

    ksh 是Korn shell的缩写,由Eric Gisin编写,共有42条内部命令。该shell最大的优点是几乎和商业发行版的ksh完全兼容,这样就可以在不用花钱购买商业版本的情况下尝试商业版本的性能了。

    注意:bash是 Bourne Again Shell 的缩写,是linux标准的默认shell ,它基于Bourne shell,吸收了C shell和Korn shell的一些特性。bash完全兼容sh,也就是说,用sh写的脚本可以不加修改的在bash中执行。

    3.Shell脚本语言与编译型语言的差异:

    大体上,可以将程序设计语言可以分为两类:编译型语言和解释型语言。

    编译型语言

    很多传统的程序设计语言,例如Fortran、Ada、Pascal、C、C++和Java,都是编译型语言。这类语言需要预先将我们写好的源代码(source code)转换成目标代码(object code),这个过程被称作“编译”。

    运行程序时,直接读取目标代码(object code)。由于编译后的目标代码(object code)非常接近计算机底层,因此执行效率很高,这是编译型语言的优点。

    但是,由于编译型语言多半运作于底层,所处理的是字节、整数、浮点数或是其他机器层级的对象,往往实现一个简单的功能需要大量复杂的代码。例如,在C++里,就很难进行“将一个目录里所有的文件复制到另一个目录中”之类的简单操作。

    解释型语言

    解释型语言也被称作“脚本语言”。执行这类程序时,解释器(interpreter)需要读取我们编写的源代码(source code),并将其转换成目标代码(object code),再由计算机运行。因为每次执行程序都多了编译的过程,因此效率有所下降。

    使用脚本编程语言的好处是,它们多半运行在比编译型语言还高的层级,能够轻易处理文件与目录之类的对象;缺点是它们的效率通常不如编译型语言。不过权衡之下,通常使用脚本编程还是值得的:花一个小时写成的简单脚本,同样的功能用C或C++来编写实现,可能需要两天,而且一般来说,脚本执行的速度已经够快了,快到足以让人忽略它性能上的问题。脚本编程语言的例子有awk、Perl、Python、Ruby与Shell。

    4.什么时候使用shell

    因为Shell似乎是各UNIX系统之间通用的功能,并且经过了POSIX的标准化。因此,Shell脚本只要“用心写”一次,即可应用到很多系统上。因此,之所以要使用Shell脚本是基于:

    • 简单性:Shell是一个高级语言;通过它,你可以简洁地表达复杂的操作。
    • 可移植性:使用POSIX所定义的功能,可以做到脚本无须修改就可在不同的系统上执行。
    • 开发容易:可以在短时间内完成一个功能强大又妤用的脚本。


    但是,考虑到Shell脚本的命令限制和效率问题,下列情况一般不使用Shell:

      1. 资源密集型的任务,尤其在需要考虑效率时(比如,排序,hash等等)。
      2. 需要处理大任务的数学操作,尤其是浮点运算,精确运算,或者复杂的算术运算(这种情况一般使用C++或FORTRAN 来处理)。
      3. 有跨平台(操作系统)移植需求(一般使用C 或Java)。
      4. 复杂的应用,在必须使用结构化编程的时候(需要变量的类型检查,函数原型,等等)。
      5. 对于影响系统全局性的关键任务应用。
      6. 对于安全有很高要求的任务,比如你需要一个健壮的系统来防止入侵、破解、恶意破坏等等。
      7. 项目由连串的依赖的各个部分组成。
      8. 需要大规模的文件操作。
      9. 需要多维数组的支持。
      10. 需要数据结构的支持,比如链表或数等数据结构。
      11. 需要产生或操作图形化界面 GUI。
      12. 需要直接操作系统硬件。
      13. 需要 I/O 或socket 接口。
      14. 需要使用库或者遗留下来的老代码的接口。
      15. 私人的、闭源的应用(shell 脚本把代码就放在文本文件中,全世界都能看到)。

    总结来说:其实只要能够操作应用程序的接口都能称为shell,狭义的shell指的是命令行方面的软件,包括本章要介绍的bash等。广义的shell则包括图形界面软件,因为图形界面其实也能够操作各种应用程序来调用内核工作。

    6.bash的主要优点有下面几个

    1. 命令记忆功能:~/.bash_history记录着前一次登录前所执行过的命令,而至于这一次登录所执行的命令都被暂存在临时内存中,当你成功注销系统后,该命令记忆才会记录到.bash_history中。最大的好处就是我们可以查询我们的历史操作,但是记录命令的数量值不能设者的太多,以防止黑客破坏。
    2. 命令与文件补全功能([tab]键的好处)

    不解释

    1. 命令别名设置功能(alias

    例如用ff 来代替ls -al 这个命令

    [root@circle ~]# alias ff='ls -al'

    [root@circle ~]# ff

    total 56

    dr-xr-x---.  2 root root 4096 Apr 24 22:25 .

    dr-xr-xr-x. 22 root root 4096 Apr 24 12:35 ..

    -rw-------.  1 root root 1156 Dec  7 17:22 anaconda-ks.cfg

    -rw-------.  1 root root  721 Apr 25 02:38 .bash_history

    -rw-r--r--.  1 root root   18 May 20  2009 .bash_logout

    -rw-r--r--.  1 root root  176 May 20  2009 .bash_profile

    -rw-r--r--.  1 root root  176 Sep 23  2004 .bashrc

    -rw-r--r--.  1 root root  100 Sep 23  2004 .cshrc

    -rw-r--r--.  1 root root 8835 Dec  7 17:22 install.log

    -rw-r--r--.  1 root root 3384 Dec  7 17:21 install.log.syslog

    -rw-r--r--.  1 root root  129 Dec  4  2004 .tcshrc

    -rw-r--r--.  1 root root  226 Apr 24 22:25 test.sh

    [root@circle ~]#

    1. 作业控制、前台、后台控制(jod control, foreground, background
    2. 程序脚本(shell script)本章主要就是向集中讲解这一部分

    其实关于shell是否是一种语言的疑问,但发现有的人认为它算是一种脚本语言,有的人不认为它是一种语言,但无论是或不是,shell所发挥的作用是不变的:粘两个网上的答案吧:

    1.说它不是一种语言

    shell 不是一种语言,而是一种编程的方法。 定义  shell 是操作系统的最外层。shell 合并编程语言以控制进程和文件,以及启动和控制其它程序。shell 通过提示您输入,向操作系统解释该输入,然后处理来自操作系统的任何结果输出来管理您与操作系统之间的交互。   shell 向提供了与操作系统通信的方式。此通信以交互的方式(来自键盘的输入立即操作)或作为一个 shell 脚本执行。shell 脚本是 shell 和操作系统命令的序列,它存储在文件中。   当登录到系统中时,系统定位要执行的 shell 的名称。在它执行之后,shell 显示一个命令提示符。此提示符通常是一个 $(美元符)。当提示符下输入命令并按下 Enter 键时,shell 对命令进行求值,并尝试执行它。取决于命令说明,shell 将命令输出写到屏幕或重定向到输出。然后它返回命令提示符,并等待您输入另一个命令。

    2.说它是一种语言

    计算机科学中,Shell俗称壳(用来区别于核),是指“提供使用者使用界面”的软件(命令解析器)。它类似于DOS下的command.com。它接收用户命令,然后调用相应的应用程序。同时它又是一种程序设计语言。作为命令语言,它交互式解释和执行用户输入的命令或者自动地解释和执行预先设定好的一连串的命令;作为程序设计语言,它定义了各种变量和参数,并提供了许多在高阶语言中才具有的控制结构,包括循环和分支。在C++中,Shell是希尔排序的名称。   

    基本上shell分两大类:   

    一:图形界面shell(Graphical User Interface shell 即 GUI shell)   例如:应用最为广泛的 Windows Explorer (微软的windows系列制作系统),还有也包括广为人知的 Linux shell,其中linux shell 包括 X windows manger (BlackBox和FluxBox),以及功能更强大的CDE、GNOME、KDE、 XFCE。   

    二:命令行式shell(Command Line Interface shell ,即CLI shell)   例如:   bash / sh / ksh / csh(Unix/linux 系统)   COMMAND.COM(MS-DOS 系统)   cmd.exe / 命令提示字符(Windows NT 系统)   Windows PowerShell(支援 .NET Framework 技术的 Windows NT 系统)   传统意义上的shell指的是命令行式的shell,以后如果不特别注明,shell是指命令行式的shell。   文字操作系统与外部最主要的接口就叫做shell。shell是操作系统最外面的一层。shell管理你与操作系统之间的交互:等待你输入,向操作系统解释你的输入,并且处理各种各样的操作系统的输出结果。   shell提供了你与操作系统之间通讯的方式。这种通讯可以以交互方式(从键盘输入,并且可以立即得到响应),或者以shell script(非交互)方式执行。shell script是放在文件中的一串shell和操作系统命令,它们可以被重复使用。本质上,shell script是命令行命令简单的组合到一个文件里面。   Shell基本上是一个命令解释器,类似于DOS下的command.com。它接收用户命令(如ls等),然后调用相应的应用程序。较为通用的shell有标准的Bourne shell (sh)和C shell (csh)。   交互式shell和非交互式shell   交互式模式就是shell等待你的输入,并且执行你提交的命令。这种模式被称作交互式是因为shell与用户进行交互。这种模式也是大多数用户非常熟悉的:登录、执行一些命令、签退。当你签退后,shell也终止了。   shell也可以运行在另外一种模式:非交互式模式。在这种模式下,shell不与你进行交互,而是读取存放在文件中的命令,并且执行它们。当它读到文件的结尾,shell也就终止了。

    所以关于sehll到底是什么东西,在这里做一点自己的理解

    当我们用户要想使用内核操控计算机的各种硬件或实现一些功能的时候,是不能直接与内核交互的,我们只能通过shell这个应用程序伴我们来把我们认知的命令解释成内核所知道的语言,然后这种shell的解释其有好多种,我们最常用的是/bin/bash这个命令接口的shell,他有好多的优点都在上文中罗列出来了,shell帮助你联络内核的方式有两种,

    一种为交互式:就是我们Linux登录后一条一条命令输入的这种命令行的方式,从键盘输入,并且可以立即得到响应。

    另一种叫做非交互式:我们将一堆命令以特定的格式写到文件(就是脚本)中,shell不需每次执行都与我们交互,直接去执行该文件(就是脚本),便可以执行其中的命令。

    这其实就是shell!(仅个人见解)

    7.Shell脚本编程——规范编程与变量

    一、shell script的概念

    其实,shell script是利用shell的功能所写的一个程序,这个程序是使用纯文本文件,将一些shell的语法与命令(含外部命令)写在里面,搭配正则表达式、管道命令与数据流重定向等功能,以达到我们所想要的处理目的。

    总的来说概念有三点:

    1.将要执行的命令按照顺序保存到一个文本文件

    2.给该文件可执行权限,便可运行

    3.可结合各种shell控制语句以完成更复杂的操作。

    二、shell脚本的应用场景

    1.重复性操作

    2.批量事务处理

    3.自动化运维

    4.服务运行状态监控

    5.定时任务执行

    三、shell脚本的构成

    1、脚本声明

    因为我们一般都使用bash,所以脚本文件的第一行内容一般是:

    #/bin/bash(用来声明这个脚本所使用的shell名称)

    因为我们使用的是bash,所以必须要用上面这样的内容来声明

    2、注释信息

    注释信息可以帮助我们了解有关于这个脚本的相关内容,所以我们在编写脚本的时候一定要写注释信息,而注释信息中放于开头的那部分注释一般要包括:

    1)脚本功能

    2)脚本的版本信息

    3)作者和联系方式

    4)版权声明

    5)脚本的history(历史记录)

    6)脚本内较特殊的命令,使用“绝对路径”的方式来执行

    7)脚本执行时需要的环境变量预先声明和设置

    例:

    [root@circle ~]# cat /etc/sysconfig/network-scripts/ifup

    #!/bin/bash(声明)

    # Network Interface Configuration System(注释)

    # Copyright (c) 1996-2009 Red Hat, Inc. all rights reserved.(注释)

    #

    # This program is free software; you can redistribute it and/or modify(注释)

    # it under the terms of the GNU General Public License, version 2,(注释)

    # as published by the Free Software Foundation.(注释)

    #

    # This program is distributed in the hope that it will be useful,(注释)

    # but WITHOUT ANY WARRANTY; without even the implied warranty of(注释)

    # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the(注释)

    # GNU General Public License for more details.(注释)

    #

    # You should have received a copy of the GNU General Public License(注释)

    # along with this program; if not, write to the Free Software(注释)

    # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA(注释)

    unset WINDOW # defined by screen, conflicts with our usage(由此开始时可执行语句)

    . /etc/init.d/functions

    四、shell脚本的编写与执行

    1.编写自己的第一个脚本

     

    #!/bin/bash

    #Filename:first.sh

    #Author:circle

    #Date:2017-04-26

    #查看系统内核文件信息

    cd /boot

    echo "当前所在路径"

    pwd

    echo "内核文件"

    ls -lh vml*

    编写完成后,保存退出

    2.执行脚本

    执行脚本的方式有四种

    (1)绝对路径

    (2)相对路径

    (3)sh 脚本路径(与“bash 脚本路径”相同)

    (4)source 脚本路径 (与“. 脚本路径”相同)

      其中,绝对路径与相对路径执行shell script 时,需要脚本文件具有相对应的可执行权限。方法(4)也只在当前环境生效,其他三种方法是另外打开一个shell来执行该脚本

     

    其实总结来说也就是可以归类为两种:

    (1)作为可执行程序,编写完脚本后,为脚本添加可执行权限,然后用绝对路径或者相对路径来运行。

    [root@circle ~]# ll first.sh

    -rw-r--r--. 1 root root 172 Apr 26 11:59 first.sh

    [root@circle ~]# chmod +x first.sh

    [root@circle ~]# ll first.sh

    -rwxr-xr-x. 1 root root 172 Apr 26 11:59 first.sh

    [root@circle ~]# /root/first.sh

    当前所在路径:

    /boot

    内核文件:

    -rwxr-xr-x. 1 root root 4.1M Jul 24  2015 vmlinuz-2.6.32-573.el6.x86_64

    [root@circle ~]# ./first.sh (作为可执行程序,系统环境变量中没有他的路径存在所以我们才要加上“绝对路径或者./”来告诉系统去哪执行这个程序)

    当前所在路径:

    /boot

    内核文件:

    -rwxr-xr-x. 1 root root 4.1M Jul 24  2015 vmlinuz-2.6.32-573.el6.x86_64

    [root@circle ~]#

    (2)作为解释器参数:

    作为解释器参数的话就不需要可执行权限也能运行该脚本,而且也不需要在第一行声明该脚本所使用的shell,应为我们输入这个命令的时候相当于已经告诉了系统,使用哪种shell运行

    [root@circle ~]# chmod -x first.sh

    [root@circle ~]# ll first.sh

    -rw-r--r--. 1 root root 172 Apr 26 11:59 first.sh

    [root@circle ~]# sh first.sh

    当前所在路径:

    /boot

    内核文件:

    -rwxr-xr-x. 1 root root 4.1M Jul 24  2015 vmlinuz-2.6.32-573.el6.x86_64

    [root@circle ~]# source first.sh

    当前所在路径:

    /boot

    内核文件:

    -rwxr-xr-x. 1 root root 4.1M Jul 24  2015 vmlinuz-2.6.32-573.el6.x86_64

    [root@circle boot]# (这里为何source执行完之后所在路径变成了/boot我也不太清楚,留作疑问以后解答)

    五、管道操作

    1.管道操作符号|

    2.管道符号的作用:将左侧的命令输出结果,作为右侧命令的处理对象。

    3.格式 cmd1|cmd2|cmd3|.....[cmdn]

    4.实例:

    [root@circle ~]# rpm -qa |grep vim

    vim-minimal-7.4.629-5.el6.x86_64

    vim-common-7.4.629-5.el6_8.1.x86_64

    vim-filesystem-7.4.629-5.el6_8.1.x86_64

    vim-enhanced-7.4.629-5.el6_8.1.x86_64

    [root@circle ~]# cat /etc/passwd|grep "root"

    root:x:0:0:root:/root:/bin/bash

    operator:x:11:0:operator:/root:/sbin/nologin

    [root@circle ~]# cat /etc/passwd|grep nologin|wc -l

    15

    [root@circle ~]#

    六、重定向操作

    1. Linux操作系统下有一句话:一切皆文件

    当我们向计算机里面输入内容的时候用的设备一般就是键盘,那么既然一切皆文件,键盘这个输入设备在Linux中也需要一个对应的设备文件来表示,这个文件就是/dev/stdin,而我们把内容进行输入了,但当计算机要输出内容的时候,对应的输出设备(一般指显示器)的文件是什么呢,输出文件有两个:(1)标准输出/dev/stdout2)标准错误输出/dev/stderr

    所以:Linux命令默认从标准输入设备(stdin)获取输入,将结果输出到输出设备(stdout)显示、一般情况下,标准输入设备就是键盘,标准输出设备就是终端,即显示器。

    1.标准输入、标准输出与标准错误输出

    (1)标准输入:从该设备接收用户输入的数据

    (2)标准输出:通过该设备向用户输出数据

    (3)标准错误输出:通过该设备报告执行出错的信息

    类型

    设备文件

    文件描述编号

    默认设备

    标准输入

    /dev/stdin

    0

    键盘

    标准输出

    /dev/stdout

    1

    显示器

    标准错误输出

    /dev/stder

    2

    显示器

    2.何为重定向?

    有时我们不想从键盘输入内容而是从一些文件中读取,或者有时我们不需要将内容或者错误内容输出到显示器上让我们看见,我们只是需要将输出内容放置到我们规定的文件里面,而完成这些动作所使用的方法便是重定向,输入就叫输入重定向,输出就叫输出重定向

     

    重定向的操作分类

    类型

    操作符

    用途

    重定向输入

    <

    从指定文件读取数据

    重定向输出

    >

    将输出结果保存(覆盖)到指定文件

    >>

    将输出结果追加到指定文件

    标准错误输出

    2>

    将错误信息保存(覆盖)到指定文件

    2>>

    将错误信息追加到指定文件

    混合输出

    &>

    将输出和错误输出保存到同一文件

     

    实例:

    输入重定向

    1)修改密码

    [root@circle ~]# vim mima

    1234

    1234

    保存退出

    [root@circle ~]# passwd big < mima

    Changing password for user big.

    New password: Password change aborted.

    New password: Password change aborted.

    New password: Password change aborted.

    passwd: Have exhausted maximum number of retries for service(失败了,发现防火墙没关)

    [root@circle ~]# /etc/init.d/iptables stop

    iptables: Setting chains to policy ACCEPT: filter          [  OK  ]

    iptables: Flushing firewall rules:                         [  OK  ]

    iptables: Unloading modules:                               [  OK  ]

    [root@circle ~]# setenforce 0

    [root@circle ~]# passwd big < mima

    Changing password for user big.

    New password: BAD PASSWORD: it is too short

    BAD PASSWORD: is too simple

    Retype new password: passwd: all authentication tokens updated successfully.

    (2)添加周期性计划任务

    [root@circle ~]# crontab -l

    no crontab for root

    [root@circle ~]# echo "0 22 * * * /sbin/init 0" > 1.txt

    [root@circle ~]# crontab < 1.txt

    [root@circle ~]# crontab -l

    0 22 * * * /sbin/init 0

    [root@circle ~]#

    [root@circle ~]# crontab -r

    [root@circle ~]# crontab -l

    no crontab for root

    输出重定向

    >是覆盖文件原来的内容输出到文件里面

    >>是追加到文件的末尾

    1.覆盖输出重定向

    [root@circle ~]# ls > 1.txt

    [root@circle ~]# cat 1.txt

    1.txt

    anaconda-ks.cfg

    Desktop

    Documents

    Downloads

    install.log

    install.log.syslog

    ks.cfg

    mima

    Music

    Pictures

    Public

    Templates

    Videos

    [root@circle ~]#

    追加输出重定向

    [root@circle ~]# ls /boot/ >> 1.txt

    [root@circle ~]# cat 1.txt

    1.txt

    anaconda-ks.cfg

    Desktop

    Documents

    Downloads

    install.log

    install.log.syslog

    ks.cfg

    mima

    Music

    Pictures

    Public

    Templates

    Videos

    config-2.6.32-431.el6.x86_64

    efi

    grub

    initramfs-2.6.32-431.el6.x86_64.img

    lost+found

    symvers-2.6.32-431.el6.x86_64.gz

    System.map-2.6.32-431.el6.x86_64

    vmlinuz-2.6.32-431.el6.x86_64

    [root@circle ~]#

    标准错误输出重定向:(覆盖及追加)

    [root@circle ~]# LS

    -bash: LS: command not found

    [root@circle ~]# LL

    -bash: LL: command not found

    [root@circle ~]# LS 2> 1.txt

    [root@circle ~]# LL 2>> 1.txt

    [root@circle ~]# cat 1.txt

    -bash: LS: command not found

    -bash: LL: command not found

     

    混合输出

    [root@circle ~]# vim test.sh

    #Filename:test.sh

    #Author:circle

    #Date:2017-04-26

    #重定向输出,混合输出,同时测试不添加第一行声明然后用sh运行脚本是否可行

    LS

    Ls

    保存退出

    [root@circle ~]# sh test.sh

    test.sh: line 5: LS: command not found

    1.txt  Desktop    Downloads  install.log.syslog  mima   Pictures  Templates  Videos

    anaconda-ks.cfg  Documents  install.log  ks.cfg      Music  Public    test.sh

    [root@circle ~]# sh test.sh &> 3.txt

    [root@circle ~]# cat 3.txt

    test.sh: line 5: LS: command not found

    1.txt

    3.txt

    anaconda-ks.cfg

    Desktop

    Documents

    Downloads

    install.log

    install.log.syslog

    ks.cfg

    mima

    Music

    Pictures

    Public

    Templates

    test.sh

    Videos

    7.shell的变量功能与概念

    以我个人的见解,所谓的变量也就是用一个简单或者说方便我们识别的“词组或者字符”来表示一大堆我们实际要使用的内容,这样我们在脚本编写或者输入命令的时候就会方便许多,例如我定义了myname这个变量来记录我自己的名字,当我的名字改变时我不需要亲自再去查找我改变后的名字,只需要查看myname这个变量的内容就可以了,也就是说实际在变得是变量的内容,而不是变量这个“词组或者字符”本身,他们是不能变得。

    [root@circle ~]# myname=circle

    [root@circle ~]# echo $myname

    circle

    [root@circle ~]# myname=big

    [root@circle ~]# echo $myname

    big

    1.变量的概念

    变量是用来存放系统或者用户需要使用的特定参数或者值,变量的值可以根据用户设定或者系统环境变化而相应变化,在shell脚本中使用变量,可使脚本更加灵活,适应性强。

    2.变量分类

    (1)自定义变量(也称用户变量):由用户自己定义、修改和使用

    定义变量时,变量名不加美元符号$

    注意,变量名和等号之间不能有空格,同时变量名遵循以下规则:

    ·首个字符不能为数字(其实变量名也只能由数字、字母和下划线构成)

    ·中间不能有空格,可以使用下划线

    ·不能使用标点符号

    ·不能使用bash里面的关键字(可用help命令查看保留关键字)

    例:[root@circle ~]# myname="circle"

    (2)环境变量:由系统维护,用于设置工作环境

    使用命令env来查看系统的环境变量,显示内容太多,这里只列举一部分

    [root@circle ~]# env

    HOSTNAME=circle

    SELINUX_ROLE_REQUESTED=

    TERM=xterm

    SHELL=/bin/bash

    HISTSIZE=1000

    SSH_CLIENT=192.168.52.2 50728 22

    SELINUX_USE_CURRENT_RANGE=

    QTDIR=/usr/lib64/qt-3.3

    QTINC=/usr/lib64/qt-3.3/include

    SSH_TTY=/dev/pts/0

    PATH=/usr/lib64/qt-3.3/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin

    PATH变量用于设置可执行程序的默认搜索路径,所以我们使用的命令的可执行程序都是放在PATH变量所包含的路径下的,否侧我们要执行的时候就要使用上文提到的,四种方法了:绝对和相对路径,还有shsource执行。

    当然,我们也可以把我们想要添加的路径添加到PATH中,使她成为默认搜索路径。

    [root@circle ~]# env |grep PATH

    PATH=/usr/lib64/qt-3.3/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin

    [root@circle ~]# PATH=$PATH:/root

    [root@circle ~]# env |grep PATH

    PATH=/usr/lib64/qt-3.3/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin:/root

    [root@circle ~]# chmod +x 1.txt

    [root@circle ~]# 1.txt

    /root/1.txt: line 1: -bash:: command not found

    /root/1.txt: line 2: -bash:: command not found

    [root@circle ~]#

    此时,PATH变量被临时修改了

    想要永久修改的话,可以改变全局变量文件/etc/profile或者单独修改某用户家目录下的~/.bash_profile文件

    (3)预定义变量(特殊变量)

    前面讲到,变量名只能包含数字、字母和下划线,因为某些包含其它字符的变量有特殊含义,是bash程序预先定义好的一类特殊变量,用户只能使用预定义变量,而不能创建新的预定义变量,也不能直接为预定义变量赋值。

    特殊变量表

    变量

    含义

    $0

    当前脚本名称

    $n

    传递给脚本或函数的参数。n是一个数字(1-9)。$1代表第一个参数,以此类推

    $#

    传递给脚本或函数的参数个数

    $*

    传递给脚本或函数的所有参数(将所有参数视为一个整体)

    $@

    传递给脚本或函数的所有参数。被双引号(“ ”)包含时,与$*稍有不同,$@是单个参数的组合

    $?

    上个命令的退出状态,或函数的返回值,保存着命令或脚本的执行状态码

    $$

    当前shell进程ID。对于shell脚本,就是这些脚本所在的进程ID

    关于$?返回所谓的执行状态码的解释

    Linux下一条命令或一个进程执行完成会返回一个一个状态码。

    0   ===   成功执行

    0 ===  执行过程中出现异常或非正常退出

    Shell脚本中 最后执行的一条命令将决定整个shell脚本的状态. 此外 shell的内部命令exit也可以随时终止shell脚本的执行,返回Shell脚本的状态码

    shell脚本执行结束前 的最后一个命令是不带参数的exit ,那么 shell脚本的最终返回值 就是 exit 语句前一条语句的返回值,根据这个值可以判断脚本成功执行与否。

     $? 可以查看 最后一条命令的返回值 该变量可以在shell 脚本中的任何地方使用

    [root@circle ~]# ls; echo $?

    1.txt            Documents           ks.cfg                       mybak_20170426170828.tar.gz  Templates

    3.txt            Downloads           mima                         mybak.sh                     test2.sh

    anaconda-ks.cfg  install.log         Music                        Pictures                     test.sh

    Desktop          install.log.syslog  mybak_20170426170642.tar.gz  Public                       Videos

    0成功执行

    [root@circle ~]# LS;echo $?

    -bash: LS: command not found

    127错误代码

    $*$@的区别

    $*$@都代表传递给函数或脚本的所有参数,不被双引号(“”)包含时,都以“$1”“$2”“$3...$n”的形式输出所有参数。

    但是当他们被双引号(“”)包含时,“$*”会将所有参数作为一个整体,以“$1 $2 $3 ... $n”的形式输出所有参数;“$@”会将各个参数分开,以“$1”“$2”“$3...$n”的形式输出所有参数。

    例:

    #!/bin/bash

    echo "$*=" $*

    echo ""$*"=" "$*"

     

    echo "$@=" $@

    echo ""$@"=" "$@"

     

    echo "print each param from $*"

    for var in $*

    do

        echo "$var"

    done

     

    echo "print each param from $@"

    for var in $@

    do

        echo "$var"

    done

     

    echo "print each param from "$*""

    for var in "$*"

    do

        echo "$var"

    done

     

    echo "print each param from "$@""

    for var in "$@"

    do

        echo "$var"

    done

     

    执行./test.sh "a" " b" " c" " d"

     

    $*=  a b c d

    "$*"= a b c d

    $@=  a b c d

    "$@"= a b c d

    print each param from $*

    a

    b

    c

    d

    print each param from $@

    a

    b

    c

    d

    print each param from "$*"

    a b c d

    print each param from "$@"

    a

    b

    c

    d

    这个例题是我从网上粘过来的,还没有学控制语句所以等回头再看吧。

    下面关于上面的所有的特殊变量写一个例题,来直观的看一下结果:、

    [root@circle ~]# vim test2.sh

    #!/bin/bash

    #Filename:test3.sh

    #Author:circle

    #特殊变量的测试

    echo "所有参数的是:$*"

    echo "脚本的名称是:$0"

    echo "脚本的执行的状态码是:$?"

    echo "所有参数的个数是:$#"

    ~       

    [root@circle ~]# sh test2.sh a b c d

    所有参数的是:a b c d

    脚本的名称是:test2.sh

    脚本的执行的状态码是:0

    所有参数的个数是:4           

    例题2

    [root@circle ~]# vim mybak.sh

    #!/bin/bash

    #备份

    tar zcf ./mybak_$(date +%Y%m%d%H%M%S).tar.gz $* &>/dev/null

    echo "已执行脚本 $0"

    echo "共完成 $# 个对象的备份"

    echo "具体包括 $@"

    保存退出

    [root@circle ~]# sh mybak.sh /etc/passwd /etc/shadow

    已执行脚本 mybak.sh

    共完成 2 个对象的备份

    具体包括 /etc/passwd /etc/shadow

    [root@circle ~]# ll mybak_20170426170828.tar.gz

    -rw-r--r--. 1 root root 1194 Apr 26 17:08 mybak_20170426170828.tar.gz

    [root@circle ~]# tar tvf mybak_20170426170828.tar.gz

    -rw-r--r-- root/root      1657 2017-04-26 13:08 etc/passwd

    ---------- root/root      1051 2017-04-26 13:46 etc/shadow

    [root@circle ~]#

    3.变量定义与输出

    1)定义一个新变量

    格式:变量名=变量值(或者说是变量内容)

    注意:变量名必须是以字母或下划线开头,严格区分大小写

    (2)赋值可使用引号

    ·双引号:允许通过$符号引用其他的变量值

    ·单引号:禁止引用其他变量值,$视为普通字符

    ·Shell中可以用反斜杠 "" 对字符做转义,比如

    echo "hello" >> ./file1

    可以将 hello 字符串写入文件./file1,但是hello前后是不带双引号的。如果想写入前后带双引号的,即"hello",可以这样做:

    echo ""hello"" >> ./file1

    ·反撇号“ `` ”:或$( ):命令替换,提取命令的执行结果

    例:

    [root@circle ~]# Z=aaa

    [root@circle ~]# echo "$Z 123"

    aaa 123

    [root@circle ~]# echo '$Z 123'

    $Z 123

    [root@circle ~]# Z=111

    [root@circle ~]# X=121

    [root@circle ~]# Y=`expr $Z + $X`

    [root@circle ~]# echo $Y

    232

    [root@circle ~]# Y=$(expr $Z + $X)

    [root@circle ~]# echo $Y

    232

    (3)输入输出格式

    ·输入格式:read [-p 提示信息] 变量名

    ·输出格式:echo $变量名           

    [root@circle ~]# vim read.sh

    #!/bin/bash

    #输入输出测试

    read -p "请输入你的名字 " name

    read -p "请输入你的密码 " passwd

    if  [ $passwd = "123123" ]; then

            echo "hello $name ! "

    else

            echo "sorry,wrongnumber. "

    fi

    保存退出

    [root@circle ~]# sh read.sh

    请输入你的名字 asdfasdfs

    请输入你的密码 123123

    hello asdfasdfs !

    [root@circle ~]# sh read.sh

    请输入你的名字 123

    请输入你的密码 222

    sorry,wrongnumber.

     

    4.变量的作用范围

    默认情况下,新定义的变量只在当前的shell环境中有效,因此称为局部变量,当进入子程序或者新的shell时,局部变量将无法再使用。为了使用户定义的变量在所有子shell环境中能够继续使用,减少重复设置工作,可以通过内部命令export将指定的变量导出为“全局变量”

    格式1export 变量名

    格式2export 变量名=变量值

    两种格式可以混合使用

    [root@circle ~]# hostname DJ

    [root@circle ~]# bash

    [root@DJ ~]# X=666

    [root@DJ ~]# echo $X

    666

    [root@DJ ~]# bash

    [root@DJ ~]# echo $X

     

    [root@DJ ~]#

    [root@DJ ~]# X=777

    [root@DJ ~]# export X Y=12345

    [root@DJ ~]# bash

    [root@DJ ~]# echo $X $Y

    777 12345

    [root@DJ ~]#

     

    5.变量的算术运算

    变量的算术运算多用于脚本的过程控制,只能进行简单的整数运算,不支持小数运算,整数值的运算主要通过内部命令expr进行

    格式:expr 变量1 运算符 变量2 [运算符 变量3]......

    [root@DJ ~]# expr $X + $Y;expr $X - $Y;expr $X * $Y;expr $X / $Y;expr $Y % $X

    13122

    -11568

    9592065

    0

    690

    %”百分号代表取余数,也就是结果只会显示余数,而作乘法运算的时候,需要在*前面加上转义符号“

    求精度计算:使用bc(计算器)命令

    [root@DJ ~]#

    [root@DJ ~]# rpm -q bc

    bc-1.06.95-1.el6.x86_64

    [root@DJ ~]# echo "scale=100; $X / $Y" |bc

    .0629404617253948967193195625759416767922235722964763061968408262454

    434993924665856622114216281895504

    [root@DJ ~]# 

  • 相关阅读:
    18网三袁昳 实验三
    18网三袁昳 网络对抗技术实验二
    18网三袁昳 网络对抗技术实验一
    实验六
    实验五(18网三43号)
    实验四 18网三43号
    实验三(18网三43号)
    实验二(18网三43号袁昳)
    实验一(18网三43号)
    实验四(恶意代码技术)
  • 原文地址:https://www.cnblogs.com/dengjun/p/6771312.html
Copyright © 2011-2022 走看看