bash shell 临时笔记

来源:互联网 发布:white trash 知乎 编辑:程序博客网 时间:2024/05/21 06:11

 

1. 1变量替换

1. 2参数替换

 

1.1.1 变量的名字是它的值保存的地方。引用它的值称为变量替换(variable substitution)。.

              如 果variable1是一个变量的名字,那么$variable1就是引用这个变量的值

              变量赋值: var_name="var_value"     等号两边不能有空格 ;给变量赋的值中有空白字符,“ ”引号是必须的

                                read var_name

                                for  var_name in num1 num 2

                                var_name=$(cmd)   命令替换,注意要保持命令行输出的完整性,最好var_name="$(cmd)" ,使用双引号

             变量替换: $var_name 等同于 ${var_name}   在某些场合使用$variable形式会引起错误,这时你可能需要使用${variable}的形式了

                                "$var_name"       在一个双引号(" ")里的变量引用不会禁止变量替换。所以双引号被称为部分引用,有时也称为"弱引用"

                               变量替换不能用‘$var_name’     一个单引号里(' ')的变量替换是被禁止的,变量名只被解释为普通的字面意思

 

1.1.2  一个未初始化的变量有一个”null”值――表示从没有被赋值过(注意null值不等于零)。虽然有时在数学运算会被当成0 ,但是不可靠,但是该行为无法预期 。

1.1.3 变量没有类型。

         本质上来说,Bash变量是字符串,但是根据环境的不同,Bash允许变量有整数计算和比较。其中的决定因素是变量的值是不是只含有数字

1.1.4特殊变量种类

        局部变量     local loc_var=23       # 声明为局部变量

        环境变量

             1.1.4.1

               每次一个Shell启动时,它都会创建新的合适的环境变量。如果它增加或是更新一个环境变量,都会使这个Shell的环境表得到更新(译者注:换句话说,更改或增加

               的变量会立即生效),并且这个Shell所有的子进程(即它执行的命令)能继承它的环境变量。(译者注:准确地说,应该是后继生成的子进程才会继承Shell的新环

               境量,已经运行的子进程并不会得到它的新环境变量)。

             1.1.4.2

              如果一个脚本要设置一个环境变量,则需要将它导出(”export”),也就是说要通知到脚本的环境表。这就是export命令的功能。这样子脚本才会看到这个新修改变量

              一个脚本只能导出(export)变量到子进程,也就是说只能导出到由此脚本生成的命令或进程中。在一个命令行中运行的脚本不能导出一个变量影响到命令行的环境

              子进程不能导出变量到生成它的父进程中

       位置参数

               注意$0

                     shift  ;

                     $* $@ ; $* 和$@ 结合不同的IFS,代表的东西可能不一样

2.1.1设置变量的属性 r x i

           declaretypeset内建命令(它们是完全相同的)可以用来限定变量的属性.

           declare [+/-][rxi][变量名称=设置值]declare-f

          参数说明

                +/-  "-"可用来指定变量的属性,"+"则是取消变量所设的属性

                -f  仅显示函数

                 r  将变量设置为只读。

                 x  指定的变量会成为环境变量,可供shell以外的程序来使用。

                 i  [设置值]可以是数值,字符串或运算式。

                 使用内建的declare可以来限定变量的范围, foo (){    declare FOO="bar"    }   局部变量

2.1.2 变量的间接引用

         变量间接引用的实际用处是什么? 它提供了Bash具有C中一点指针的功能 .

         Bash不支持指针运算,这极大地限制了间接引用的用处。事实上,在脚本语言里间接引用是一个蹩脚地东西

        a=letter_of_alphabet   # 变量"a"保存着另外一个变量的名字.    letter_of_alphabet=z

         # 间接引用.   eval a=\$$a

2.1.3 间接引用用到的命令字 eval

        eval的作用是再次执行命令行处理,也就是说,对一个命令行,执行两次命令行处理

        2.1.3.1与eval一起记忆的一个命令let

             let 命令是 BASH 中用于计算的工具,用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量。如果表达式中包含了空格或其他特殊字符,则必须引起来。

             shell程序中的操作默认都是字符串操作,在要运行数学运算符的时候可能得到意想不到的答案,所以用let

        2.1.3.2 与let一起的算术运算

               let不允许只出现等号右边的计算,用“ ”或者表达式中间没有空格,不需要$let ″j=i*6+2″等价于((j=i*6+2)),

               var=`expr$var+1`   将需要运算的表达式写入在expr 后面,参数与运算符号中间有空格隔开 

             (())、expr 可以只有等号右边的计算,由$((...))、$(expr ...)、`expr ...` 查看返回结果                      expr表达式参数间必须有空格

     let和(())运行是内建命令,使用相同的算法。       let或者表达式用“”,或者表达式中间没有空格
              let 和 expr 的运算是整数运算,不包括浮点预算

2.1.4 变量的检查和初始化赋值

         ${parameter-default}, ${parameter:-default}

                   前者变量没有被声明(变量的值是NULL,也看做被声明),就使用这个default作为默认值;

                   后者变量没有被设置(变量的值是NULL,也是没有被设置),就使用default默认值

         ${parameter=default}, ${parameter:=default}  等同于上面

    ${parameter?err_msg}, ${parameter:?err_msg} 变量没有被声明或者被设置,打印err信息

    ${parameter+alt_value},${parameter:+alt_value}

   如果变量parameter被声明或被设置,使用alt_value作为新值,否则使用空字符串

 

2.1.5 对变量的值就行修改

 注意: Pattern 可以使用正则表达式,但是Replacement不能使用正则表达式

    ${var#Pattern}, ${var##Pattern}

“删除”从$var前端 开始的最短 或 最长匹配$Pattern的字符串.  必须是从头第一个字母开始的匹配,否则替换不了

    ${var%Pattern}, ${var%%Pattern}

”删除“从$var后端 开始的最短 或 最长匹配$Pattern的字符串。 必须是结尾最后一个字母的匹配。       记忆方法:键盘上三个键的位置紧挨着:#$%

    ${var/#Pattern/Replacement}

”替换“如果变量var前缀匹配模式Pattern,则用Replacement代替匹配模式的字符串.

    ${var/%Pattern/Replacement}

”替换“如果变量var后缀匹配模式Pattern,则用Replacement代替匹配模式的字符串.

 

        注意: 这些pos 不能使用正则表达式------------------------------------

    ${var:pos} ${var:(-pos)} 

变量var被展开成从位移pos个字符往后的值.pos为负值,则从字符后面的倒数pos位置提取字符

    ${var:pos:len}

从变量var中展开成从位移pos的字符往后最长为len的字符串。

    ${var/Pattern/Replacement}

在变量var第一个匹配Pattern的字符串用Replacement代替.     变量中间的字符,不一定是开头或者结尾的字符

如果省略了Replacement ,则第一个匹配Pattern的字符串会被删除.

    ${var//Pattern/Replacement}

全局替换Global replacement.所有在变量var中被Pattern匹配到的都由Replacement代替.

 
2.1.6 查看定义的变量   
    ${!varprefix*}, ${!varprefix@}

匹配所有前面声明过的变量,并且变量名以varprefix开头.

    ${!name[@]}  ${!name[*]}
      如果name为一个数组变量,那么结果是该数组的所有下标的列表。如果name不是数组,那么,如果name为空,结果就为空,如果name不为空,结果就为0.2.1.7 变量的长度
    ${#var}

字符串长度(即变量$var的字符个数)。

对于数组来说,${#array}是数组的第一个元素的长度.${#array[*]}${#array[@]}表示数组中元素的个数

${#*}${#@} 表示位置参数的个数

 

2.1.8 对变量操作的总结

      # 表示求长度

      !表示求变量的名字

      # 表示开头匹配 ,扩展 /# /% ## %% //

      % 表示结尾匹配

      / 表示求替换

      没有/ 的都是删除操作

3.1 内部命令和内建命令
3.1.1  内建命令就是bash工具自带的命令,大多和linux系统命令是一个名字。
          设立内建命令的原因就是(1)内建命令不需要fork一个新的进程,可以执行的更快(2)内建命令可能会访问bash的内核。
          常用的内建命令,有:
      3.1.1.1 I/O类
                    echo
                    printf
                    read
     3.1.1.2 文件类
                    cd
                    pwd
                    pushd popd dirs  操作目录栈
      3.1.1.3 变量类
                    let
                    eval
                    set  unset:set -r 受限shell restricted
                    export
                    declare typeset
                    readonly
                    getopts
      3.1.1.4 脚本类
                    .(source 命令)  , source是在主进程的环境下执行,. 是在进程的子进程下执行
                   exit
                   exec
                   caller
                   shopt
      3.1.1.5 命令类
                   true false
                   type
                   hash
                   bind
                   help
       3.1.1.6 作业控制类
                   作业不是进程
                   jobs
                   discown
                   fg bg
                   wait
                   suspend
                   logout
                   times
                   kill
                   command
                   builtin
                   enable
                   autload
         3.1.1.7 比较类
                   test
                   [
          3.1.1.8 函数类
                   return
          3.1.1.9 terminfo操作
                  tput
          3.1.1.10 数据类
                  seq 
 
3.2.1 子shell
        子shell中的变量是局部变量,不能被父进程读取。
        进程在不同的子shell中可以串行地执行.这样就允许把一个复杂的任务分成几个小的子问题来同时地处理
        在子shell中的目录更改不会影响到父shell
        子shell可用于为一组命令设定临时的环境变量
        用"|"管道操作把I/O流重定向到子shell,例如ls -al | (command)
 
    3.2.1.1 外部命令调用会产生一个子shell

    3.2.1.2( 命令1; 命令2; 命令3; ... )

              嵌在圆括号里的一列命令在一个子shell里运行
    3.2.1.3 在一个花括号内的代码块不会运行一个子shell.

              { command1; command2; command3; ... }

    3.2.1.4 命令替换将会调用一个subshell :var=$() ; var=`do_action`

    3.2.1.5 & ,提交后台作业

    3.2.1.6 管道

    3.2.1.7 . (source命令)或者file命令

    3.2.1.8 exec命令

    3.2.1.9 函数调用

3.2.2 受限shell

     #bin/bash -r   或者 set -r   shell运行在受限模式下

     这是一种安全策略, 目的是为了限制脚本用户的权限 , 受限shell模式下如下操作不能执行:

           使用cd 命令更改工作目录.

           更改环境变量$PATH,$SHELL,$BASH_ENV,或$ENV 的值.
           读或更改shell环境选项变量$SHELLOPTS的值.
           输出重定向.
           绝对路径.
           调用exec来把当前的受限shell替换成另外一个不同的进程.
           脚本中许多其他无意中能破坏或捣乱的命令.
           在脚本中企图脱离受限shell模式的操作.

3.2.3 命令替换

          将一个命令的输出赋值给某一个变量 。

          var=`do_action`  允许嵌套的,但要用\转义``

          var=$(do_action)  允许嵌套的

          命令替换甚至允许将整个文件的内容放到变量中, 可以使用重定向或者cat命令。不要将2进制文件的内容保存到变量中

                 variable1=`<file1`      #  将"file1"的内容放到"variable1"中.   

                 variable2=`cat file2`   #  将"file2"的内容放到"variable2"中.    但是这行将会fork一个新进程

3.2.4 进程替换

          进程替换则是把一个进程的输出回馈给另一个进程 (换句话说,它把一个命令的结果发送给另一个命令).

          进程替换的一般形式: 由圆括号括起的命令

>(command)

<(command)  在"<" 或or ">" 与圆括号之间是没有空格的. 如果加了空格将会引起错误信息

进程替换能比较两个不同命令之间的输出:$ comm <(ls -l) <(ls -al) ;   diff <(ls $first_directory) <(ls $second_directory)

4.1 测试

      4.1.1 测试结构

               if  any_thing

               if test any_thing

               if  [ 空格分隔的变量 ]

               [ 空格分割的变量 ]     && ||  不能用在这个内建命令中  , 与 或 -a  -o

               if [[ ]]

               [[ ]]   与 或 && ||

               ((  )) 算术比较, 返回值和 [ ] 相反 

     4.1.2 文件类的比较

                -e     文件存在

                -f      文件是一个普通文件(不是一个目录或是一个设备文件)
                -s     文件大小不为零
                -d     文件是一个目录
                -b     文件是一个块设备(软盘, 光驱, 等等.)
                -c     文件是一个字符设备(键盘, 调制解调器, 声卡, 等等.)
                -p     文件是一个管道
                -h     文件是一个符号链接
                -L     文件是一个符号链接
                -S     文件是一个socket
                -t      文件(描述符)与一个终端设备相关

             这个测试选项可以用于检查脚本中是否标准输入 ([ -t 0 ])或标准输出([ -t 1 ])是一个终端.

                 -r      文件是否可读 (指运行这个测试命令的用户的读权限)
                 -w     文件是否可写 (指运行这个测试命令的用户的读权限)
                 -x      文件是否可执行 (指运行这个测试命令的用户的读权限)
                 -g      文件或目录的设置-组-ID(sgid)标记被设置

             如果一个目录的sgid标志被设置,在这个目录下创建的文件都属于拥有此目录的用户组,而不必是创建文件的用户所属的组。这个特性对在一个工作组里的同

             享目录很有用处。

                 -u     文件的设置-用户-ID(suid)标志被设置

             一个root用户拥有的二进制执行文件如果设置了设置-用户-ID位(suid)标志普通用户可以以root权限运行。[1] 这对需要存取系统硬件的执行程序(比如说pppd

            和cdrecord)很有用。如果没有设置suid位,则这些二进制执行程序不能由非root的普通用户调用。

                 -O           你是文件拥有者
                 -G           你所在组和文件的group-id相同
                -N           文件最后一次读后被修改
                f1 -nt f2   文件f1f2
                f1 -ot f2   文件f1f2
                f1 -ef f2   文件f1f2 是相同文件的硬链接
                !              "非" -- 反转上面所有测试的结果(如果没有给出条件则返回真).

    4.1.3  算术比较

               -eq  等于         if [ "$a" -eq "$b" ]

               -ne  不等于    if [ "$a" -ne "$b" ]

               -gt   大于        if [ "$a" -gt "$b" ]

               -ge  大于等于  if [ "$a" -ge "$b" ]

               -lt     小于       if [ "$a" -lt "$b" ]

               -le    小于等于 if [ "$a" -le "$b" ]

                <      小于(在双括号里使用)      (("$a" < "$b"))

                <=   小于等于 (在双括号里使用)(("$a" <= "$b"))

                >     大于 (在双括号里使用)      (("$a" > "$b"))

                >=   大于等于(在双括号里使用)(("$a" >= "$b"))

  4.1.4 字符串比较

       = ==等于
           if [ "$a" = "$b" ]
       != 不相等 
           if [ "$a" != "$b" ]

  < 小于,依照ASCII字符排列顺序

      if [[ "$a" < "$b" ]]   符号

      if [ "$a" \< "$b" ]    内建命令  所以 要转义

       > 大于,依照ASCII字符排列顺序

      if [[ "$a" > "$b" ]]

      if [ "$a" \> "$b" ]

       -z 字符串为"null",即是指字符串长度为零。     在测试方括号里进行-n测试时一定要把字符串用引号起来,不然可能会出错,可移植性不好
       -n 字符串不为"null",即长度不为零            在测试方括号里进行-n测试时一定要把字符串用引号起来,而且如果var有空格就不好办
 
  4.1.5  与 或
      [ ]   中: -a -o 
      [[ ]] 中: && ||  ,  [[ ]] 比 [ ] 更常用

4.2  流程控制

    4.2.1  for

              2种形式: for var in action or $var-list

                               for(( a=2; a<var;a++ ))    c 风格 ,var没有$

   4.2.2 while

             2种形式: while [ ] or [[ ]] or action

                              while((  a < var ))   c 风格,var没有$

   4.2.3 util

            util [ ] or [[ ]] or action   until [[ condition ]] 是直到conditon 成立,才不执行do done操作

   4.2.4 case

            case "$var_name" in               对变量使用""并不是强制的,因为不会发生单词分离

            “$case1”)

               do_sth

               ;;                                         case没有break,没有do done

           "$case2")

              do_sth

              ;;                                            case  没有break,没有do done

            esac

    4.2.5 select

           select var_name in $var_list

           do

              action

              break;

           done

   4.2.6 if [ ] 或 [[ ]] 或 action 或 test

            then

                do_sth

           else if [ ] [[ ]] test action        或者elif

           then

               do_sth

          else

                do_sth

         fi

         fi    注意, 有几个fi就要有几个fi  ; 上面如果使用elif,那么下面只要一个fi就可以了  。

5.数组

    数组是多个变量的存储,数组的变量时array[num], 等同于一般的变量var;  要访问一个数组元素,可以使用花括号来访问,即${array[xx]},0可以省略为${array}

    数组元素没有类型,不同类型的元素可以放在同一个数组里

   5.1 数组定义

         declare -a array

        array =()          ()表明变量是数组

   5.2 数组初始化

      5.2.1 array[0]=$var  等同于变量赋值

      5.2.2 array=($var0 $var1 $var2 .....)

      5.2.3 array=([2]=$var [24]=$var)

  5.3 增加一个元素到数组                不同于c,数组可以扩展

     array=("$array[@]" "new1")  相当于,重新写了扁数组中的所有元素

     array[${#array[@]}=new1

  5.4 调用数组

    5.4.1 ${array[@]} ${array[*]} 数组中的所有元素

             ${#array[@]} ${#array[*]}数组中元素个数

             ${array[num]} 数组中array[num]的值,

             ${array} 等同于 ${array[0]}

   5.4.2  ${array:pos:len} 数组从下标pos开始len个元素 , 即array[pos] array[pos+1]..array[pos+len-1]

             ${array[@]:0}  ${array[@]}  $array[*] 显示数组的所有元素

   5.4.3  对数据某元素的调用

            ${array[N]:pos:len}  即 array[N]中,位置pos开始len个长度的字符

   5.4.4 删除数组的某个元素

            unset array[N]  删除array[N],等同于array[4]=

            unset array  等同于 unset array[@]  删除整个数组

  5.5  复制数组

       array_2=($array[@])

       array_2=("$array[@]")  这个会保持数组中的分割符

  5.6 判断索引是否在数组里

      if [ "name" in array ]   不能用 if [ -z array[name] ] 

 

6.1 函数

    一个函数是一个子程序,用于实现一串操作的代码块(code block),

     6.1.1 func_name()

              {                               有更好的可移植性 , 符合c语言的格式

              }

             function func_name

             {

             } 

     6.1.2 传给脚本的命令行参数怎么办?在函数内部可以看到它们吗?

                 除非显示的传给函数参数,否则函数看不到传给脚本的参数,例如看不到$1 $2 $3

     6.1.3 函数里变量 和 参数 的作用域

        6.1.3.1 函数定义的变量默认是global的,其作用域从“函数"被调用时"执行变量定义的地方”开始,到shell结束或被显示删除处为止            

                    函数定义的变量也可以被显示定义成local的,其作用域局限于函数内。

                    函数调用之前,所有在函数内声明且没有明确声明为local的变量都可在函数体外可见

         6.1.3.2  函数的参数是local的

         6.1.3.3  脚本中定义的变量是global的,其作用域从"被定义"的地方开始,到shell结束或被显示删除的地方为止

     6.1.4 函数的返回值  $?  return的返回值也是写到$?里

              func xxx

              a=$?   不能写成a=$(func xxx)

         6.1.4.1  return     内建命令 ,返回的最大正整数是255

                      如果没有return ,将返回函数最后一个执行命令的退出状态

          6.1.4.2 为了函数可以返回字符串或是数组,用一个可在函数外可见的变量

          6.1.4.3 rerurn 返回的最大正整数是255 ,如何返回更大的数值

                      一种获取大整数的"返回值"的办法是简单地将要返回的值赋给一个全局变量

                      更优雅的做法是在函数用 echo 打印"返回值到标准输出",然后使用命令替换(command substitution)捕捉此值

     6.1.5 函数的输入重定向

          函数本质上是一个代码块(code block), 这意味着它的标准输入可以被重定向

         Function ()    {     ...    } < file    # 也试一下这个:   Function ()    {     {       ...      } < file  }

7.1 内部变量

      OFS=\r\n

8.1 常用命令

     find

     rev

     md5sum

     printf printf “ string  %d %u %s ”  $var1 $var2 $var3

     head   head filename -n N 打印头N行 ; head filename -n -N 打印头N行之后的所有行

     tail     tail filename -n M 打印结尾M行; tail filename -n +M 打印头M行之后的所有行

     bc     hex=`echo "obase=16;ibase=10; $n" | bc`   十进制转化为16进制  ; echo $1+$2 | bc 浮点数计算

     tput  光标属性

     tput cup row_num col_num  将光标移到 row行 col列位置

     tput cols  查看当前串口tty的列宽col

     date +%a +%A +%b +%B 显示当前的时间,不同的显示格式 。  man date

9.1 全局变量

   $LOGNAME

 

0 0
原创粉丝点击