美文网首页
Linux Shell 脚本编写指南——第二章

Linux Shell 脚本编写指南——第二章

作者: 面面的徐爷 | 来源:发表于2019-07-16 18:49 被阅读0次

    本文为Linux Shell Scripting Tutorial (LSST) v2.0学习记录


    第二章:开始shell脚本编程

    本章节学习目标:

    • 编写你第一个shell 程序

    • 理解创建一个shell脚本的步骤

    2.1 Bash shell(全称Bourne again shell)

    有关bash的创建历史(来自维基百科):

    Bourne shell是一个交互式的shell,由AT&T实验室的史蒂夫在1977年发布,位于大多数Unix系统上的/bin/sh,随着时间的发展,GNU计划的诞生伴随着shell的开发,这个时候1987年布莱恩编写了Bash,也就是Bourne again shell,总的来说,Bash虽然是一个满足POSIX规范的shell,但有很多拓展。

    Bash就是shell,或者可以说是Linux系统的命令语言解释器:

    • Bash式GNU计划的产物
    • Linux的默认shell
    • 反向兼容UNIX系统的sh
    • 与Korn shell(ksh)以及C shell(csh)兼容
    • 在多平台类似UNIX/dos/Windows都是可运行多个

    BASH的提升特性

    • 命令行编辑
    • 命令行补全
    • 无限大小的命令历史
    • 提示控制
    • 不限大小的array
    • 以2-64为基数的整数运算
    • ……

    作者

    • Brian J. Fox authored the GNU Bash shell, in 1987.
    • Fox maintained Bash as the primary maintainer until 1993, at which point Chet Ramey took over.
    • Chet Ramey is the current maintainer of the GNU Bourne Again Shell and GNU Readline.

    下载

    2.2 shell命令

    bash shell有两种类型的命令:

    1. 内置命令
    2. 外部命令(在bin/目录里面的命令)

    bash和命令类型

    bash接受以下几种类型的命令:

    • 别名(例如ll
    • 关键词(例如if
    • 函数(例如genpassword
    • 内置命令(例如pwd
    • 文件(例如/bin/date)

    type命令

    找出某个命令(ls)是内置命令还是外部命令:

    new@Chevy-PC:~$ type ls
    ls is aliased to `ls --color=auto'
    # 显示为外部命令
    

    找出某个命令(command)是内置命令还是外部命令:

    new@Chevy-PC:~$ type -a history
    history is a shell builtin
    # 显示为内置命令
    

    bash命令关键词以及内置命令

    2.3 Hello, World! 第一个shell脚本

    创建一个shell脚本你需要经过以下几个步骤:

    1. 利用一个文本编辑器(例如vi),将你的指令写入一个文本
    2. 保存该文本并退出
    3. 改变该文本的可执行权限
    4. 测试该脚本并放入你的生产环境
    5. 最简单的shell脚本就是一行代码告诉计算机执行一个命令

    让我们来熟悉vi的操作并创建第一个shell script

    # 打开一个文件
    vi first_script.sh
    
    # 进入编辑模式
    # 按Esc键,然后按I键就进入编辑模式
    
    # 进入命令模式
    # 按Esc键就进入命令模式
    
    # 保存文件
    # 按Esc键然后输入:w
    # 或者按Esc键然后输入:w first_script.sh
    
    # 保存并退出文件
    # 按Esc键然后输入:wq
    # 或者按Esc键然后输入:x
    
    # 跳到某一行
    # 按Esc键然后输入:x, x代表第几行
    
    # 搜索一个字符
    # 按Esc键然后输入/str, str代表该字符
    
    # 退出vi(不保存)
    # 按Esc键然后输入:q
    
    
    # 让我们来编辑第一个脚本,输入以下字符并保存退出
    #!/bin/bash
    echo "Hello, World!" 
    echo "Knowledge is power."
    
    # 将该文件改为可以执行文件并执行
    new@Chevy-PC:~$ chmod 777 first_script.sh
    new@Chevy-PC:~$ ./first_script.sh
    Hello, World!
    Knowledge is power.
    

    Shebang

    在脚本的第一行,我们需要告诉系统用哪种程序来运行这个脚本,写法为#!/path_to_binaries,我们一般称其为Shebang或者bang行[1]

    在bash脚本里面第一行我们一般写成#!/bin/bash,有些程序使用perl来运行的话,就写成#!/bin/perl

    一个#!/bin.sh的脚本示例:

    etc/init.d/policykit
    #! /bin/sh
    ### BEGIN INIT INFO
    # Provides:          policykit
    # Required-Start:    $local_fs
    # Required-Stop:     $local_fs
    # Default-Start:     2 3 4 5
    # Default-Stop:
    # Short-Description: Create PolicyKit runtime directories
    # Description:       Create directories which PolicyKit needs at runtime,
    #                    such as /var/run/PolicyKit
    ### END INIT INFO
    
    # Author: Martin Pitt <martin.pitt@ubuntu.com>
    
    case "$1" in
      start)
            mkdir -p /var/run/PolicyKit
            chown root:polkituser /var/run/PolicyKit
            chmod 770 /var/run/PolicyKit
        ;;
      stop|restart|force-reload)
        ;;
      *)
        echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2
        exit 3
        ;;
    esac
    
    :
    

    Shell注释

    在脚本里面#号后面的代码会被忽略,这行代码我们成为注释,注释可以帮助我们理解代码并且便于修改:

    #!/bin/bash
    # A Simple Shell Script To Get Linux Network Information
    # Vivek Gite - 30/Aug/2009
    echo "Current date : $(date) @ $(hostname)"
    echo "Network configuration"
    /sbin/ifconfig
    

    多行注释可以使用HERE DOCUMENT 特性来进行注释:

    #!/bin/bash
    echo "Adding new users to LDAP Server..."
    <<COMMENT1
        Master LDAP server : dir1.nixcraft.net.in 
        Add user to master and it will get sync to backup server too
        Profile and active directory hooks are below
    COMMENT1
    echo "Searching for user..."
    

    设置脚本权限

    一个刚编辑完的脚本无法直接执行,你需要使用chmod命令给与其可执行权限或者直接调用对应的命令来执行,下面的操作具有同样的效果:

    chmod +x script.sh && ./script.sh
    chmod 777 script.sh && ./script.sh
    
    sh script.sh
    

    使用ls -l可以查看一个文件的权限:

    new@Chevy-PC:~$ ls -l first.sh
    -rwxrwxrwx 1 new new 61 Jul 15 14:24 first.sh
    

    更多chomd的操作可以使用man chmod查看

    为什么不直接使用 scriptname 来调用脚本?为什么当工作目录$PWD正好是scriptname 所在目录时也不起作用?因为一些安全原因,当前目录./并不会被默认添加到用户的$PATH路径中。因此需要用户显式使用 ./scriptname 在当前目录下调用脚本。

    脚本debug

    在运行脚本的时候需要加上-x参数或者-xv参数,又或者是将shebang行改成#!/bin.bash-x

    使用内置命令

    bash shell提供了debug选项,可以使用set命令打开或者关闭:

    • set -x:当脚本被执行的时候展示命令及参数
    • set -v:当脚本被读入的时候展示输入行
    • set -n:读入命令但不执行(在检查脚本是否有变量名重合的时候)
    #!/bin/bash
    ### Turn on debug mode ###
    set -x
    
    # Run shell commands
    echo "Hello $(LOGNAME)"
    echo "Today is $(date)"
    echo "Users currently on the machine, and their processes:"
    
    ### Turn OFF debug mode ###
    set +x
    
    # Add more commands without debug mode
    
    #!/bin/bash
    set -n # only read command but do not execute them
    set -o noexec
    echo "This is a test"
    # no file is created as bash will only read commands but do not executes them 
    

    本章节复习题

    练习题1

    按照下面代码写一个脚本并运行,观察输出:

    # Script to print currently logged in users information, and current date & time.
    clear
    echo "Hello $USER"
    echo -e "Today is \c ";date
    echo -e "Number of user login : \c" ; who | wc -l
    echo "Calendar"
    cal
    exit 0
    

    ​ 输出结果:

    Hello new
    Today is Tue Jul 16 15:34:58 CST 2019
    Number of user login : 0
    Calendar
         July 2019
    Su Mo Tu We Th Fr Sa
        1  2  3  4  5  6
     7  8  9 10 11 12 13
    14 15 16 17 18 19 20
    21 22 23 24 25 26 27
    28 29 30 31
    
    
    练习题2

    写一个程序,打印出你最喜欢的电影名称,同时在下一行打印出导演的名称(以下是我自己的答案):

    #!/bin/bash
    # print moive and director
    
    set -e
    
    my_favorite_moive="gone_with_the_wind"
    
    moive_director="not_known"
    
    echo -e "my_favorite_moive is \c"; 
    echo $my_favorite_moive
    echo -e "the moive's director is \c"; 
    echo $moive_director
    
    exit 0
    
    练习题3

    写一个shell脚本,打印你的名字,在用户按<ENTER>键之前保持等待状态:

    #!/bin/bash
    echo "Vivek Gite"
    read -p "Press [Enter] key to continue..." fakeEnterKey
    
    练习题4

    列出十个内置命令和外部命令:

    # builtin commands
    history
    break
    cd
    continue
    eval
    exit
    grep
    kill
    
    # external commands
    ls
    gzip
    
    练习题5

    使用cd命令进入/etc/init.d目录下,查看各种系统启动脚本:

    new@Chevy-PC:/bin$ cd /etc/init.d/
    new@Chevy-PC:/etc/init.d$ ll
    total 156
    -rwxr-xr-x 1 root root 2269 Apr 22  2017 acpid*
    -rwxr-xr-x 1 root root 4335 Mar 23  2018 apparmor*
    -rwxr-xr-x 1 root root 2802 Nov 21  2017 apport*
    -rwxr-xr-x 1 root root 1071 Aug 22  2015 atd*
    -rwxr-xr-x 1 root root 1232 Apr 19  2018 console-setup.sh*
    -rwxr-xr-x 1 root root 3049 Nov 16  2017 cron*
    -rwxr-xr-x 1 root root  937 Mar 18  2018 cryptdisks*
    -rwxr-xr-x 1 root root  978 Mar 18  2018 cryptdisks-early*
    -rwxr-xr-x 1 root root 2813 Nov 16  2017 dbus*
    -rwxr-xr-x 1 root root 4489 Jun 29  2018 ebtables*
    -rwxr-xr-x 1 root root 3809 Feb 15  2018 hwclock.sh*
    -rwxr-xr-x 1 root root 2444 Oct 25  2017 irqbalance*
    -rwxr-xr-x 1 root root 1503 Feb 22  2018 iscsid*
    -rwxr-xr-x 1 root root 1479 Feb 16  2018 keyboard-setup.sh*
    -rwxr-xr-x 1 root root 2044 Aug 16  2017 kmod*
    -rwxr-xr-x 1 root root  695 Dec  3  2017 lvm2*
    -rwxr-xr-x 1 root root  571 Dec  3  2017 lvm2-lvmetad*
    -rwxr-xr-x 1 root root  586 Dec  3  2017 lvm2-lvmpolld*
    -rwxr-xr-x 1 root root 2378 Jun 17  2018 lxcfs*
    -rwxr-xr-x 1 root root 2240 Jun  6  2018 lxd*
    -rwxr-xr-x 1 root root 2653 Jun 26  2018 mdadm*
    -rwxr-xr-x 1 root root 1249 Jun 26  2018 mdadm-waitidle*
    -rwxr-xr-x 1 root root 2503 Feb 22  2018 open-iscsi*
    -rwxr-xr-x 1 root root 1846 Mar 22  2018 open-vm-tools*
    -rwxr-xr-x 1 root root 1366 Jan 17  2018 plymouth*
    -rwxr-xr-x 1 root root  752 Jan 17  2018 plymouth-log*
    -rwxr-xr-x 1 root root 1191 Jan 18  2018 procps*
    -rwxr-xr-x 1 root root 4355 Dec 13  2017 rsync*
    -rwxr-xr-x 1 root root 2864 Jan 15  2018 rsyslog*
    -rwxr-xr-x 1 root root 1222 May 22  2017 screen-cleanup*
    -rwxr-xr-x 1 root root 3837 Jan 26  2018 ssh*
    -rwxr-xr-x 1 root root 5974 Apr 21  2018 udev*
    -rwxr-xr-x 1 root root 2083 Aug 16  2017 ufw*
    -rwxr-xr-x 1 root root 1391 Jul 18  2018 unattended-upgrades*
    -rwxr-xr-x 1 root root 1306 May 16  2018 uuidd*
    

    1. SBCL - Shebang Scripts

    相关文章

      网友评论

          本文标题:Linux Shell 脚本编写指南——第二章

          本文链接:https://www.haomeiwen.com/subject/htfxlctx.html