Shell 入门指令

运行脚本的方式:
  sh hello.sh
  bash hello.sh
  . ./hello.sh
  source hello.sh
  ./hello.sh(需要给用户增加执行权限)
  
符号    作用
#   注释
;   命令分隔符
;;  终止case选项
.   等价于source
""  可以读取""中的部分变量
''  阻止String中所有字符的解释
/   路径分隔
\   转义
`   反引号中的命令优先执行
:   空命令,变量扩展,子串替换
?   测试操作符
$   变量替换,命令替换

#!    用于指定当前脚本的解释器
脚本示例:
  #!/bin/bash
  echo hello; echo there
  filename=ttt.sh
  if [ -e "$filename" ]; then    # 注意: "if"和"then"需要分隔,-e用于判断文件是否存在
     echo "File $filename exists."; cp $filename $filename.bak
  else
     echo "File $filename not found."; touch $filename
  fi; echo "File test complete."
脚本解释:
  上面脚本使用了一个if分支判断一个文件是否存在,如果文件存在打印相关信息并将该文件备份;如果不存在打印相关信息并创建一个新的文件。最后将输出"测试完成"。

  -e filename 如果 filename存在,则为真
  -d filename 如果 filename为目录,则为真
  -f filename 如果 filename为常规文件,则为真
  -L filename 如果 filename为符号链接,则为真
  -r filename 如果 filename可读,则为真
  -w filename 如果 filename可写,则为真
  -x filename 如果 filename可执行,则为真
  -s filename 如果文件长度不为0,则为真
  -h filename 如果文件是软链接,则为真
  -n 当串的长度大于0时为真(非空串)
  -z 当串的长度为0时为真(空串)


脚本示例: 
  #!/bin/bash
  varname=b
  case "$varname" in
      [a-z]) echo "abc";;
      [0-9]) echo "123";;
  esac
脚本解释: 
  上面脚本使用case语句,首先创建了一个变量初始化为b,然后使用case语句判断该变量的范围,并打印相关信息。如果你有其它编程语言的经验,这将很容易理解。

反斜线\:
  \n 表示新
  \r 表示回车
  \t 表示水平制表符
  \v 表示垂直制表符
  \b 表示后退符
  \a 表示"alert"(蜂鸣或者闪烁)
  \0xx 转换为八进制的ASCII码, 等价于0xx
  " 表示引号字面的意思

脚本示例:
  $ cp `mkdir back` test.sh back
  $ ls
脚本解释:
  先创建了 back 目录,然后复制 test.sh 到 back 目录

#!/bin/bash
condition=5
if [ $condition -gt 0 ] #gt表示greater than,也就是大于,同样有-lt(小于),-eq(等于) 
then :   # 什么都不做,退出分支
else
    echo "$condition"
fi

: > test.sh #把test.sh 文件清空,如果没有这个文件就创建这个文件,功能和 cat /dev/null > test.sh 相同,但是并不会产生一个新的进程

在一个双括号中, ? 就是一个三元表达式

符号    作用
()      局部变量,初始化数组
{}      文件名扩展
[]      条件测试,数组元素
|       分析前面命令的输出,并将输出作为后面命令的输入
-       选项,重定向stdin或stdout
~       home目录

命令组: ()
  在括号中的变量,由于是在子shell中,所以对于脚本剩下的部分是不可用的。父进程,也就是脚本本身,将不能够读取在子进程中创建的变量,也就是在子shell 中创建的变量

脚本示例:
  #!/bin/bash

  a=123
  ( a=321; )

  echo "$a" #a的值为123而不是321,因为括号将判断为局部变量

初始化数组:
  arr=(1 2 3 4)
  echo ${arr[2]}


命令组: {}
  文件名扩展
    #!/bin/bash
    if [ ! -w 't.txt' ];
    then
      touch t.txt
    fi
    echo 'test test' >> t.txt
    cp t.{txt,back}

  代码块
    #!/bin/bash
    a=123
    { a=321; }
    echo "a = $a"

    bash xxx.sh
    a=321  #a的值被修改

命令组: []
  条件测试
    #!/bin/bash
    a=5
    if [ $a -lt 10 ]
    then
        echo "a: $a"
    else
        echo 'a>10'
    fi
  数组元素
    #!/bin/bash
    arr=(12 22 32)
    arr[0]=10
    echo ${arr[0]}

命令组: <>
  重定向
  test.sh > filename:重定向test.sh的输出到文件 filename 中。如果 filename 存在的话,那么将会被覆盖。
  test.sh &> filename:重定向 test.sh 的 stdout(标准输出)和 stderr(标准错误)到 filename 中。
  test.sh >&2:重定向 test.sh 的 stdout 到 stderr 中。
  test.sh >> filename:把 test.sh 的输出追加到文件 filename 中。如果filename 不存在的话,将会被创建

命令组: |
  分析前面的输出,并将输出作为后面命令的输入
  #!/bin/bash
  tr 'a-z' 'A-Z'
  exit 0
  chmod 755 test26.sh
  ls -l | ./test26.sh
  输出的内容均变为了大写字母

命令组: -
  选项,前缀
  #!/bin/bash
  a=5
  b=5
  if [ "$a" -eq "$b" ]
  then 
    echo "a is equal to b."
  fi
  bash test27.sh
  a is equal to b.
  重定向stdin或stdout

变量定义
  注意
  变量名和等号之间不能有空格。同时,变量名的命名须遵循如下规则:
  首个字符必须为字母(a-z,A-Z)。
  中间不能有空格,可以使用下划线(_)。
  不能使用标点符号。
  不能使用bash里的关键字(可用help命令查看保留关键字)。
  除了直接赋值,还可以用语句给变量赋值,如:for file in `ls /etc`

只读变量
  #!/bin/bash
  myUrl="http://www.shiyanlou.com"
  readonly myUrl
  myUrl="http://www.shiyanlou.com"

  运行脚本报错

特殊变量
  局部变量
  环境变量
  位置参数
    从命令行传递到脚本的参数:$0,$1,$2,$3...
    $0就是脚本文件自身的名字,$1 是第一个参数,$2 是第二个参数,$3 是第三个参数,然后是第四个。$9 之后的位置参数就必须用大括号括起来了,比如,${10},${11},${12}。
    $# : 传递到脚本的参数个数
    $* : 以一个单字符串显示所有向脚本传递的参数。与位置变量不同,此选项参数可超过 9个
    $$ : 脚本运行的当前进程 ID号
    $! : 后台运行的最后一个进程的进程 ID号
    $@ : 与$*相同,但是使用时加引号,并在引号中返回每个参数
    $: 显示shell使用的当前选项,与 set命令功能相同
    $? : 显示最后命令的退出状态。 0表示没有错误,其他任何值表明有错误。
  脚本:
    #!/bin/bash
    # 作为用例, 调用这个脚本至少需要10个参数, 比如:
    # bash test.sh 1 2 3 4 5 6 7 8 9 10
    MINPARAMS=10
    echo
    echo "The name of this script is \"$0\"."
    echo "The name of this script is \"`basename $0`\"."
    echo
    if [ -n "$1" ]              # 测试变量被引用.
    then
    echo "Parameter #1 is $1"  # 需要引用才能够转义"#"
    fi 
    if [ -n "$2" ]
    then
    echo "Parameter #2 is $2"
    fi 
    if [ -n "${10}" ]  # 大于$9的参数必须用{}括起来.
    then
    echo "Parameter #10 is ${10}"
    fi 
    echo "-----------------------------------"
    echo "All the command-line parameters are: "$*""
    if [ $# -lt "$MINPARAMS" ]
    then
     echo
     echo "This script needs at least $MINPARAMS command-line arguments!"
    fi  
    echo
    exit 0

  运行结果: 
    $ bash test30.sh 1 2 10
    The name of this script is "test.sh".
    The name of this script is "test.sh".
    Parameter #1 is 1
    Parameter #2 is 2
    -----------------------------------
    All the command-line parameters are: 1 2 10
    This script needs at least 10 command-line arguments!


算数运算符
  原生bash不支持简单的数学运算,但是可以利用其他命令实现,如:awk/expr
  注意使用反引号`
  表达式与运算符之间要有空格: $a + $b可以, $a+$b不行
  条件表达式放在中括号中也要有空格: [ $a == $b ]可以, [$a==$b]不行
  乘号* 前面必须要有反斜线\,才能实现乘法运算
 
  脚本: 
    #!/bin/bash
    a=10
    b=20
    val=`expr $a + $b`
    echo "a + b : $val"
    val=`expr $a - $b`
    echo "a - b : $val"
    val=`expr $a \* $b`
    echo "a * b : $val"
    val=`expr $b / $a`
    echo "b / a : $val"
    val=`expr $b % $a`
    echo "b % a : $val"
    if [ $a == $b ]
    then
       echo "a == b"
    fi
    if [ $a != $b ]
    then
       echo "a != b"
    fi

  关系运算符只支持数字,不支持字符串,除非字符串的值是数字
  -eq   检测两个数是否相等,相等返回true
  -ne   检测两个数是否相等,不相等返回true
  -gt   检测左边的数是否大于右边的,是,返回true
  -lt   检测左边的数是否小于右边的,是,返回true  
  -ge   检测左边的数是否大于等于右边的,是,返回true
  -le   检测左边的数是否小于等于右边的,是,返回true

  脚本: 
    #!/bin/bash
    a=10
    b=20
    if [ $a -eq $b ]
    then
       echo "$a -eq $b : a == b"
    else
       echo "$a -eq $b: a != b"
    fi


逻辑运算符
  && 逻辑的AND
  || 逻辑的OR

  脚本:
    #!/bin/bash
    a=10
    b=20
    if [[ $a -lt 100 && $b -gt 100 ]]
    then
       echo "return true"
    else
       echo "return false"
    fi

    if [[ $a -lt 100 || $b -gt 100 ]]
    then
       echo "return true"
    else
       echo "return false"
    fi

字符串运算符
  =     检测两个字符串是否相等,相等返回true
  !=    检测两个字符串是否相等,不相等返回true
  -z    检测字符串长度是否为0,为0 返回true
  -n    检测字符串长度是否为0,不为0返回true
  str   检测字符串是否为空,不为空返回true

  脚本: 
    #!/bin/bash
    a="abc"
    b="efg"
    if [ $a = $b ]
    then
       echo "$a = $b : a == b"
    else
       echo "$a = $b: a != b"
    fi
    if [ -n $a ]
    then
       echo "-n $a : The string length is not 0"
    else
       echo "-n $a : The string length is  0"
    fi
    if [ $a ]
    then
       echo "$a : The string is not empty"
    else
       echo "$a : The string is empty"
    fi

文件测试运算符
  -e 文件存在
  -a 文件存在(已弃用)
  -f 表示这个文件是一个一般文件,不是目录或设备文件
  -s 文件大小不为零
  -d 表示这是一个目录
  -b 表示这是一个块设备(软盘,光驱,等)
  -c 表示这是一个字符设备(键盘,modem,声卡,等)
  -p 表示这是一个管道
  -h 这是一个符号链接
  -L 这是一个符号链接
  -S 这是一个socket
  -t 文件被关联到一个终端设备上,一般被用来检测脚本中的stdin([-t 0])或者stdout([-t 1])是否来自一个终端
  -r 文件是否具有可读权限(指的是正在运行这个测试命令的用户是否具有可读权限)
  -w 文件是否具有可写权限(指的是正在运行这个测试命令的用户是否具有可写权限)
  -x 文件是否具有可执行权限(指的是正在运行这个测试命令的用户是否具有可执行权限)
  -g set-group-id(sgid)标记被设置的文件或目录上
  -k 设置粘贴位
  -O 判断是否是文件的拥有者
  -G 文件的group-id 是否与你的相同
  -N 从文件上一次被读取到现在为止,文件是否被修改过
  f1 -nt f2  文件f1比文件f2新
  f1 -ot f2  文件f1比文件f2旧
  f1 -ef f2  文件f1和文件f2是相同文件的硬链接
  !  非,反转上面的所有测试结果

  脚本: 
    #!/bin/bash
    file="/home/shiyanlou/test.sh"
    if [ -r $file ]
    then
       echo "The file is readable"
    else
       echo "The file is not readable"
    fi
    if [ -e $file ]
    then
       echo "File exists"
    else
       echo "File not exists"
    fi


流程控制:
  if-else 语句
    if 语法格式:
      if condition
      then
        command1
        command2
        ...
        commandN
      fi

    if else 语法格式
      if condition
      then

        command1
        command2
        ...
        commandN
      else
        command
      fi

    if-elif-else 语法格式
      if condition1
      then
        command1
      elif condition2
      then
        command2
      else
        command3
      fi

    脚本: 判断两个变量是否相等
      a=10
      b=20
      if [ $a == $b ]
      then
        echo "a == b"
      elif [ $a -gt $b ]
      then
        echo "a > b"
      elif [ $a -lt $b ] 
      then
        echo "a < b"
      else
        echo "Ineligible"
      fi

    输出: a<b

    if else 语句经常与test 结合使用

    脚本:
      num1=$[2*3]
      num2=$[1+5]
      if test $[num1] -eq $[num2]
      then 
        echo "Two numbers are equal!"
      else
        echo "The two numbers are not equal!"
      fi

    输出:  Two numbers are equal! 

  for循环:
    for var in item1 item2 .. itemN
    do
      command1
      command2
      ...
      commandN
    done

    脚本: 
      for loop in 1 2 3 4 5
      do
        echo "The value is: $loop"
      done

    输出:      
      The value is: 1
      The value is: 2
      The value is: 3
      The value is: 4
      The value is: 5
    
    脚本: 
      for str in This is a string
      do
        echo $str
      done

    输出: 
      This
      is
      a
      string

  while 语句:不断执行一系列命令,也用于输入文件中读取数据;命令通产为测试条件
    while condition
    do
      command
    done 

    脚本: 
      #!/bin/bash
      int=1
      while(( $int<=5 ))
      do
        echo $int
        let "int++"
      done
      使用了 Bash let 命令,它用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量

    输出: 
      1
      2
      3
      4
      5

    while循环可用于读取键盘信息。下面的例子中,输入信息被设置为变量MAN,按结束循环。
      
      echo 'press <CTRL-D> exit'
      echo -n 'Who do you think is the most handsome: '
      while read MAN
      do
          echo "Yes!$MAN is really handsome"
      done

  无限循环:
    while :
    do
      command
    done
    或
    while true
    do
      command
    done
    或
    for(( ; ; ))

  until循环
    循环执行一系列命令直至条件为真时停止,一般while优于until循环,测试发生在循环末尾,至少执行一次
    语法: 
      until condition
      do
        command
      done

  case语句:
    case 值 in
    模式1)
      command1
      command2
      ...
      commandN
      ;;  (用于结束case语句)
    模式2)
      command1
      command2
      ...
      commandN
      ;;
    *)
      command1
      command2
      ...
      commandN
      ;;
    esac

    取值后面必须为单词in,每一模式必须以右括号结束,取值可以为变量或常数。匹配发现取值符合某一模式后,其间所有命令开始执行直至 ;;。
    取值将检测匹配的每一个模式。一旦模式匹配,则执行完匹配模式相应命令后不再继续其他模式。如果无一匹配模式,使用星号 * 捕获该值,再执行后面的命令。

    echo 'Enter a number between 1 and 4:'
    echo 'The number you entered is:'
    read aNum
    case $aNum in
        1)  echo 'You have chosen 1'
        ;;
        2)  echo 'You have chosen 2'
        ;;
        3)  echo 'You have chosen 3'
        ;;
        4)  echo 'You have chosen 4'
        ;;
        *)  echo 'You did not enter a number between 1 and 4'
        ;;
    esac

    跳出循环
      break或continue

      break跳出所有循环

      #!/bin/bash
      while : 
      do
        echo -n "Enter a number between 1 and 5:"
        read aNum
        case $aNum in
          1|2|3|4|5) echo "The number you entered is $aNum!"
          ;;
          *) echo "The number you entered is not between 1 and 5! game over"
            break
          ;;
        esac
      done

      continue跳出循环

      #!/bin/bash
      while :
      do 
        echo -n "Enter a number between 1 and 5"
        read aNum 
        case $aNum in
          1|2|3|4|5)
            echo "The number you entered is $aNum"
          ;;
          *)
            echo "The number you entered is not between 1 and 5!"
            continue
            echo "game over"
          ;;
        esac
      done

      当输入大于5的数字时,该例中的循环不会结束,语句 echo "Game is over!" 永远不会被执行。


      求 100 以内所有偶数之和
        #!/bin/bash
        n=100
        awk -v N=$n 'BEGIN {
                      sum = 0;
                      for (i = 1; i <= N; ++i){
                        if (!(i % 2)) sum += i 
                      } 
                      print sum 
                    }'

        #!/bin/bah
        sum=0
        for i in `seq 2 2 100`
        do
          let "sum+=i"
        done
        echo "sum=$sum"

函数:
  [ function ] funcname [()]

  {
    action
    [return int;]
  }

  可以带function fun()定义,也可以直接fun()定义,不带任何参数
  参数返回,可以显示:return返回, 如果不加,将以最后一条命令运行结果,作为返回值,return后跟数值n(0-255)

  例子:
    #!/bin/bash
    demoFun(){
      echo "This is my first shell function!"
    }
    echo "---Execution---"
    demoFun
    echo "---Finished---"

    #!/bin/bash
    funWithReture(){
      echo "This function will add the two numbers of the input..."
      echo "Enter the  first number: "
      read aNum
      echo "Enter the second number: "
      read anotherNum
      echo "The two numbers are $aNum and $anotherNum !"
      return $(($aNum+$anotherNum))
    }
    funWithReturn
    echo "The sum of the two numbers entered is $? !"

    函数返回值在调用该函数后通过$? 来获得
    所有函数在使用前必须定义


    函数参数:
      在函数体内部通过$n的形式来获取参数的值,如$1表示第一个参数,$2 表示第二个参数,${10}表示第10个参数

      #!/bin/bash
      funWithParam(){
        echo "The 1 parameter is $1 !"
        echo "The 2 parameter is $2 !"
        echo "The 3 parameter is $3 !"
        echo "The 10 parameter is ${10} !"
        echo "The total number of parameters is $# !"
        echo "Outputs all parameters as a string $* !"        
      }
      funWithParam 1 2 3 4 5 6 7 8 9 10 11 

      注: $10 不能获取第十个参数,获取第十个参数需要${10}。当n>=10时,需要使用${n}来获取参数。

      猜数字游戏:
      首先让系统随机生成一个数字,给这个数字一个范围,让用户猜数字,对输入作出判断,并且给出提示。
      请用while语句实现。

      #!/bin/bash
      rand=$(($RANDOM%100+1))
      while :
      do
        read aNum
        echo "$rand"
        if test $aNum -eq $rand
        then 
          echo "right"
        else 
          if [ $aNum -gt $rand]
          then 
            echo "your entered is to big to $rand"
          else
            echo "your entered is to small to $rand"
          fi
        fi
      done

这是本人学习笔记,供大家参考学习,如内容有误欢迎大家批评指正,共同进步!

该内容来自实验楼免费课程,不做任何商业用途, 如有侵权请及时联系本人删除!!!

posted @ 2019-06-10 23:48  W-it-H-ou-T  阅读(966)  评论(0编辑  收藏  举报