美文网首页Linux基础
(转)Linux Shell脚本攻略1:小试牛刀(3)

(转)Linux Shell脚本攻略1:小试牛刀(3)

作者: 千幻流光 | 来源:发表于2018-10-22 17:41 被阅读5次

    本文为转载
    作者:数据分析之路
    来源:CSDN
    原文:https://blog.csdn.net/qixizhuang/article/details/77918786


    函数和参数

    1. 定义函数
      • function fname() { statements }
      • fname() { statements }
    2. 调用函数:fname
    3. 参数可以传递给函数,并由脚本进行访问:fname arg1 arg2
    4. 参数也可以传递给脚本并通过script:$0(脚本名)访问。
      • $1是第一个参数。
      • $n是第n个参数。
      • "$@" 被扩展成"$1""$2""$3"
      • "$*" 被扩展成"$1c$2c$3",其中cIFS的第一个字符。
      • "$@" 要比"$*"用得多。由于"$*"将所有的参数当做单个字符串,因此它很少被使用。
    5. 在Bash中,函数同样支持递归:F() { echo $1; F hello; sleep 1; }
    6. Fork炸弹::(){ :|:& };:

    fork炸弹(fork bomb)在计算机领域中是一种利用系统调用fork(或其他等效的方式)进行的拒绝服务攻击。
    与病毒与蠕虫不同的是,fork炸弹没有传染性。
    fork炸弹会使对同时执行进程、程序数设限的系统无法执行新程序,对于不设限的系统则使之停止响应。
    fork炸弹通过进程递归式派生(fork,亦即自我复制),以使系统拒绝服务甚至崩溃。

    由Jaromil所作的在类UNIX系统的shell环境下触发fork炸弹的shell脚本代码,总共只用了13个字符(包括空格)
    :(){ :|:& };:
    注解如下:

    1. :() # 定义函数,函数名为":",即每当输入":"时就会自动调用{}内代码
    2. { # ":"函数的开始标识
    3. : # 用递归方式调用":"函数本身
    4. | # 并用管道(pipe)将其输出引至...
    5. : # 另一次递归调用的":"函数
      综合3-5,:|:表示的即是每次调用函数":"的时候就会生成两份拷贝
    6. & # 调用间脱钩,以使最初的":"函数被杀死后为其所调用的两个":"函数还能继续执行
    7. } # ":"函数的结束标识
    8. ; # ":"函数定义结束后,将要进行的操作...
    9. : # 调用":"函数,"引爆"fork炸弹
      其中函数名“:”只是简化的一例,实际实现时可以随意设定,一个较易理解(将函数名替换为“forkbomb”)的版本如下:
      forkbomb(){ forkbomb|forkbomb &} ; forkbomb
    1. 导出函数
      函数也能像环境变量一样用export导出,如此一来,函数的作用域就可以扩展到子进程中,如:$ export -f fname
    2. 读取命令返回值,如果命令成功退出则返回状态为0,否则为非0:
      $ cmd; echo $?;
    3. 向命令传递参数。假设-p-v是可用选项,-k N是另一个可以接受数字的选项,同时该命令还接受一个文件名作为参数,那么,它有如下几种执行方式:
      • $ command -p -v -k 1 file
      • $ command -pv -k 1 file
      • $ command -vpk 1 file
      • $ command file -pvk 1

    将命令序列的输出读入变量

    1. 输入通常是通过stdin或参数传递给命令。输出要么出现在stderr,要么出现在stdout。当我们组合多个命令时,通常将stdin用于输入,stdout用于输出。此时,这些命令被称为过滤器(filter),我们使用管道(pipe)连接每个过滤器,管道操作符是|。如:$ cmd1 | cmd2 | cmd3
    2. 我们通常使用管道并利用子shell的方式将多个文件的输出组合起来,如:
      $ ls | cat -n > out.txt
    3. 我们可以用下面的方法读取由管道相连的命令序列的输出,这种方法被称为子shell。
      $ cmd_output=$(COMMANDS)
      $ cmd_output=$(ls | cat -n); echo $cmd_output;
    4. 另一种被称为反引用backtick(也有人称反标记)的方法也可以用于存储命令输出:
      $ cmd_output=`COMMANDS`
      `$ cmd_output=`ls | cat -n`; echo $cmd_output;`
      
    5. 利用子shell生成一个独立的进程,可以使用()操作符来定义一个子shell:
      $ pwd; (cd /bin; ls); pwd;
      • 当命令在子shell中执行时,不会对当前shell有任何影响;所有的改变仅限于子shell内。
    6. 通过引用子shell的方式保留空格和换行符。假如我们使用子shell或反引用的方法将命令的输出读入一个变量中,可以将它放入双引号中,以保留空格和换行符\n
      如下图,有无双引号的类似命令,输出了不同结果:
      图1

    不使用回车键来读取n个字符

    1. read是一个重要的Bash命令,它用于从键盘或标准输入中读取文本。我们可以使用read以交互的形式读取来自用户的输入。
    2. 大多数编程语言的输入库是从键盘读取输入,但只有按下回车键的时候,才标志着输入完毕。而read命令提供了一种不需要按回车键就可以读取输入的方法。
    3. 从输入中读取n个字符并存入变量variable_name:
      $ read -n number_of_chars variable_name
    4. 用无回显的方式读取密码:
      $ read -s var
    5. 显示提示信息
      $ read -p "Enter input:" var
    6. 在特定时限内读取输入(s)
      $ read -t timeout var
    7. 用特定的定界符作为输入行的结束
      $ read -d delim_char var

    运行命令直至成功

    有时候命令只有满足某些条件或是某种外部事件(例如文件可以被下载)操作才能够成功执行,这种情况下,我们可能希望重复执行命令,直到成功为止。

    repeat() 
        {
        while true  
        do 
            $@ && return
        done 
        } 
    

    大多数现代系统中,true是作为/bin中的一个二进制文件来实现的,因此每执行一次while循环,shell就会生成一个进程。不想这样的话,可以使用shell内建的:命令

        repeat() 
        {
        while :     # : 命令总是会返回为0的退出码,即成功执行命令的退出码。
        do 
            $@ && return
        done
        } 
    
        repeat() 
        {
        while true
        do
            $@ && return
            sleep 30    #访问网站的时候要控制频率,以防被加入黑名单。
        done 
        }  
    

    字段分隔符

    1. 内部字段分隔符(Internal Field Separator,IFS)是shell脚本编程中的一个重要概念。在处理文本数据时非常重要。
    2. 内部字段分隔符适用于特殊用途的定界符(delimiter),IFS是存储定界符的环境变量,它是当前shell环境使用的默认定界字符串。
    3. 考虑CSV数据的情况:
      data="name,sex,rollno,location"
      oldIFS=$IFS
      for item in $data;
      do
          echo Item: $item
      done
      IFS=$oldIFS
      
      #!/bin/bash
      #用途:演示IFS的用法
      line="root:x:0:0:root:/root:/bin/bash"
      oldIFS=$IFS;
      IFS=":"
      count=0
      for item in $line;
      do
          [ $count -eq 0 ] && user=$item;
          [ $count -eq 0 ] && shell=$item;
          let count++
      done;
      IFS=$oldIFS
      echo $user\'s shell is $shell;
      

    迭代器

    对一系列值进行迭代时,循环非常有用。Bash提供了多种类型的循环。

    1. for循环

    for循环的一般用法

        for var in list;   #list可以是一个字符串,也可以是一个序列。
        do
            commands;
        done
    
    • echo {1..50}能够生成一个从1~50的数字列表。
    • echo {a..z}; echo {a..h};能够生成字母列表。
    • for i in {a..z}; do actions; done;

    for循环也可以采用C语言中for循环的格式,如:

        for((i=0;i<10;i++))
        {
            commands;
        }
    

    2. while循环

        while condition
        do
            commands;
        done
    

    3. until循环

        x=0;
        until [ $x -eq 9 ];
        do
            let x++; echo $x;
        done
    

    比较与测试

    if条件判断的几种实现方式:

    • if...then...else...fi结构
        if condition;
        then
            commands;
        else if condition; then
            commands;
        else
            commands;
        fi
    
    • 简略实现
      [ condition ] && action; #如果condition为真,则执行action;
      [ condition ] || action; #如果condition为假,则执行action。
      # &&是逻辑与运算符,||是逻辑或运算符。

    算数比较

    1. 条件通常被放置在封闭的中括号内,一定要注意在[]与操作数之间有一个空格,如果忘记了这个空格,脚本就会报错,例如:
      [$var -eq 0 ] (左[缺少空格) or [ $var -eq 0] (右]缺少空格)

    2. 对变量或值进行算术条件判断:

      • [ $var -eq 0 ] #当$var等于0时,返回真
      • [ $var -ne 0 ] #当$var为非0时,返回真
      • [ $var -gt 0 ] #当$var大于0时,返回真
      • [ $var -lt 0 ] #当$var小于0时,返回真
      • [ $var -ge 0 ] #当$var大于等于0时,返回真
      • [ $var -le 0 ] #当$var小于等于0时,返回真
    3. 可以结合多个条件进行测试

      • [ $var1 -ne 0 -a $var2 -gt 2 ] #使用逻辑与-a
      • [ $var1 -ne 0 -o $var2 -gt 2 ] #使用逻辑或-o
    4. 文件系统相关测试

      • [ -f $file_var ] # 如果给定的变量包含正常的文件路径或文件名,则返回真。
      • [ -x $var ] # 如果给定的变量名包含的文件可执行,则返回真。
      • [ -d $var ] # 如果给定的变量包含的是目录,则返回真。
      • [ -e $var ] # 如果给定的变量包含的文件存在,则返回真。
      • [ -c $var ] # 如果给定的变量包含的是一个字符设备文件的路径,则返回真。
      • [ -b $var ] # 如果给定的变量包含的是一个块设备文件的路径,则返回真。
      • [ -w $var ] # 如果给定的变量包含的文件可写,则返回真。
      • [ -r $var ] # 如果给定的变量包含的文件可读,则返回真。
      • [ -L $var ] # 如果给定的变量包含的是一个符号链接,则返回真。
      fpath="/etc/passwd"
      if [ -e $fpath ]; then
          echo File exists;
      else
          echo Does not exist;
      fi
      
    5. 字符串比较

      • 使用字符串比较时,最好用双中括号,因为有时候采用单个中括号会产生错误。
      • [[ $str1 = $str2 ]] :当str1等于str2时,返回真,也就是说,str1和str2包含的文本是一模一样的。
      • [[ $str1 == $str2 ]]:这是检车字符串是否相等的另一种写法。
      • [[ $str1 != $str2 ]]:如果str1和str2不相同,则返回真。
      • [[ $str1 > $str2 ]]:如果str1的字母序比str2大,则返回真。
      • [[ $str1 < $str2 ]]:如果str1的字母序比str2小,则返回真。
      • [[ -z $str1 ]]:如果str1包含的是空字符串,则返回真。
      • [[ -n $str1 ]]:如果str1包含的是非空字符串,则返回真。
        if [[ -n $str1 ]] &&[[ -z $str2 ]];
        then
            commands;
        fi
    
        str1="Not empty "
        str2=""
        if [[ -n $str1 ]] && [[ -z $str2 ]];
        then
            echo str2 is nonempty and str2 is empty string.
        fi
    

    test命令可以用来执行条件检测

        if [ $var -eq 0 ]; then echo "True"; fi
        # 也可以写成:
        if test $var -eq 0; then echo "True"; fi
    

    相关文章

      网友评论

        本文标题:(转)Linux Shell脚本攻略1:小试牛刀(3)

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