美文网首页
右脚前掌踏入shell领域!

右脚前掌踏入shell领域!

作者: Rotonnn | 来源:发表于2019-06-03 21:11 被阅读0次

    shell 的版本

    一个 shell 脚本第一行第一件事是 “确定本个脚本用什么 shell 执行”。

    ##! bin/bash
    

    这是比较普遍的,用 bash 执行脚本。

    还有一些其他的 shell ,他们在 /bin/ 目录下,比较常见的有 tcsh / zsh / csh / sh 。他们在擅长领域有所不同。在用户登录时,系统通过 /etc/password 下面登录用户条目的第七个字段选择默认的 shell。

    结构化命令!

    test 命令

    if 是最基础做判断用的结构语句。关于它的判断有两种形式

    • test condition
    • [ condition ]

    讲讲 condition! :

    类型 判断符号 备注
    整数 -eq , -ne , -ge , -le , -gt , -lt 只能比较整数
    字符串 > , < , = , != ①在 [ ] 中要转义大小写,以免变成重定向符号;②condition中是根据ASCII码进行比较,Sort是根据本地字符
    文件 -r , -w , -x , -d , -f , -e , -O ,-G , -nt , -ot

    高级 test condition:

    • (( condition ))

      • 不用转义大于小于号
      • 是做数字运算的,拥有很多很好的高级功能
        • val++ val--
        • 幂次方:**
        • 或与:|| &&
        • 位的与或非、取反、左移右移: & | ! ^ << >>
    • [[ condition ]]

      • 是处理字符串的,在基础功能上添加了模式匹配功能
      • e.g: [\[ $user == r* ]] ##查找user中所有r开头的项

    处理命令行输入!

    参数

    其他的语言,比如讲 C,将参数传入函数前,需要在函数名后声明参数的数量和名字,比如:

    int main(int a,char b){...}
    

    shell 不需要这种声明。直接在函数后面跟要传入的参数就好

    $./main.sh a b
    

    传入的参数最多可以有 9 个,在代码中,用 $x 的方式来指代第 x 个参数。
    有这些关于参数的取用方法:

    • $x ##第x个参数
    • $* ##所有参数(一次性抓取)
    • $@ ##所有参数(按分隔符分次抓取)
    • $## ##参数的数量

    $0 取到脚本名,用 basename( $0 ) 可以过滤掉执行脚本命令前面的路径,取到纯粹的脚本名。

    选项

    为了方便操作,最好是在命令下提供一些精细化选项,(比如 ls -al-al

    • case 实现是最基础的方法:
    while [ -n $1]
    do
        case "$1" in 
        a) <cmd> ;;
        b | c) <cmd> ;;
        *) <cmd>;;
        esac
        shift           ##参数左移一位
    done
    

    通过这样一个代码块就可以实现最基础的命令选项功能了。

    不过一个贴心靓仔还需要更加以人为本一些。为了处理 -xyz 这样的用户输入,还需要使用一些工具的帮助。

    • 使用 getopt 的帮助:
      getopt可以识别命令行参数,方便在脚本中的解析。格式如下:
     getopts <optstring> <parameters>
    
    • optstring:定义了命令行的有效选项字母,还定义了选项需要参数值(用 ':' 分隔)
    • paramteres:是参数值

    脚本用法:

    set -- $( getopt ab:cd "$@" )
    //脚本内容...//
    

    假如传入的选项是 -xyz ,传入后会被 getopt 格式化成 -x -y -z 再通过set替换原来的选项。最后再为脚本所用。

    但是getopt也有局限性!它不能处理带分隔符的参数,如果参数是"test3 test4" ,它会把这个参数分别看成两个带引号的参数。这个时候就需要更高一级的getopts了。

    • supreme getopts:

      getopts <optstring> <variable>
      

      和getopt选项和参数处理后只产生一个输出不同,getopts一次只处理一个检测到的参数,处理完所有的参数之后,结束,返回状态码0。
      这个特性让它很适合用在 while 之类的循环中。

      while getopts ab:c opt      ##opt储存getopts参数内容
      do
          case "$opt" in
          /.../
          esac
      done
      

      getopts 有俩环境变量

      • OPTARG:如果选项有参数,保存这个参数值
      • OPTINT:现在在处理的参数位置,每处理一个选项 +1。处理完选项之后可以用 shift [OPTINT-1 ]移动到参数位置

      getopts 允许在输入的参数值中使用空格;允许选项和参数中间不隔空格;没有定义在 optstring 中的选项会输出成 '?'。非常友善,非常好用。

    输入输出重定向

    标准文件描述符

    Linux 将每个对象都当做文件处理,这也包括了输入和输出进程。通过文件描述符,Lunix可以对每个文件对象进行标识。

    每个进程一次最多可以有 9 个文件标识符,不过 bash 只保留了前三个:

    文件描述符 缩写 描述 最初定位 符号
    0 STDIN 输入 键盘 <
    1 STDOUT 输出 屏幕 >
    2 STDERR 错误 屏幕 >

    可以单独重定位:

        ls -al test badtest test1 2> test2
        -rw-r--r-- 1 陈辛辛 197121 53 5月  14 17:39 test2
    --------------------------------------------------------------------
        $ cat test2
        ls: cannot access 'test1': No such file or directory
        ls: cannot access 'badfile': No such file or directory
    
    

    也可以全部重定向:

        $ ls -al test1 badtest test2 &> test3
    --------------------------------------------------------------------
        $ cat test3
        ls: cannot access 'test1': No such file or directory
        ls: cannot access 'badtest': No such file or directory
        -rw-r--r-- 1 陈辛辛 197121 108 5月  14 17:39 test2
    

    临时重定向和永久重定向

    • 临时重定向
      当需要使用临时重定向功能时,在文件描述符前加 '&' :

      1 > &2  #将1的输出重定向为2.它和 &> 是不同的东西。 &> 意味将 STDOUT 和 STDIN 输出重定向为同一个文件。
      
      
    • 永久重定向
      当有大量数据需要重定向的时候,需要每行数据都要重新定位的临时方法就显得不太得体。此时需要用 exec 命令在脚本的执行期间重定向某个特定的文件描述符。
      由上文所述 bash 只启用了 0~2 的文件描述符,但实际上3~8 也是可以用的。

      一个 exec 的例子:

         exec 3 > &1      ##3 的输出状态重定向为 1(STDOUT)
         exec 1 > testfile        ##1 的输出重定向为testfile
         echo "have try"
         exec 1 > &3      ##1 的输出重定向为3(STDOUT)
      

      上文中的 "have try" 最终是在 testfile 中显示

    • 如果想要关闭某个文件描述符,将其重定向为 &-

       exec 3 > &-
       echo "test" > &3
       ---------------------------
       报错:Bad file discriptor
      

      关闭后就不能使用该文件描述符写入数据啦

    控制脚本

    linux信号

    信号 描述
    1 SIGUP 挂起进程
    2 SIGINT 终止进程
    3 SIGQUIT 停止进程
    9 SIGKILL 无条件终止进程
    15 SIGTERM 尽可能终止进程
    17 SIGSTOP 无条件停止,但不是终止进程
    18 SIGTSTP 停止或暂停,但不终止进程
    19 SIGCONT 继续运行停止的进程

    信号的操作!

    • ctrl+c => SIGINT
      终止进程
    • ctrl+z => SIGTSTP
      停止进程。停止的进程用 ps还是能够查看到的,state 状态为T的就是停止的状态。如果想要终止停止的进程,可以 exit 退出shell,还可以通过 PID kill掉进程。
    • trap
      可以抓进程。格式是trap <command> <signame>,当捕捉到 signame ,运行cmd的内容。

    作业控制

    • jobs
      可以查看现在正在处理的作业,不论作业是停止还是运行,前台还是后台。

    把作业放在后台运行可以使用& 命令。 nohup命令起到辅助作用,它可以阻断所有发送给该进程的SIGHUP信号,就算终端退出了也不停止,不仅如此它还会自动把输出 >> 到一个叫做 nohup.out 的文件,使输出不会哐哐往屏幕上蹦。

    虽然jobs本人对作业的状态没什么影响,但是很多命令需要它的帮忙。
    bg把暂停命令在后台重启;fg把暂停命令前台重启;kill杀死进程;
    都需要jobs查看他们的PID

    • 定时运行
      • at
        非常方便的定时执行命令,可惜是一次性的。支持HH:MM,AM/PM,MMDDYY,文本日期和指定时间增量。
      • cron
        <min,hour,dayofmonth,month,dayofweek> cmd
        可以周期性地执行命令。
        crontab命令可以列出 cron 时间表,另外cron自己也有目录。在 /etc/ 目录下,有cron.daily / cron.weekly / cron.hourly / cron.monthly 四个目录,不要求精确运行的前提下,把脚本复制进这几个文件是最方便的定时周期执行的方法。

    相关文章

      网友评论

          本文标题:右脚前掌踏入shell领域!

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