• 《Shell十三问》笔记(下)


    继续开始shell十三问中11-13问和后续补充的笔记,加油!


    (14)输入重定向与输出重定向

    • “>”是标准输出重定向,可以把输出结果送入文件
    • “<”是标准输入重定向,可以重新指定文件的内容作为输入
    • “2>”是标准错误重定向,可以把命名执行出现的错误提示送入文件

    如果你想把标准输出和标准错误输出到一个文件中,可以使用如下的方法

    • $ ls my.file no.such.file 1>file.both 2>&1 (错误到输出)
    • $ ls my.file no.such.file 2>file.both >&2(输出到错误)

    使用“<<”追加写入,“<”为最后一次写入的内容
    (15)锁定文件避免覆盖写入

    $ set -o noclobber
    $ echo "4" > file.out
    -bash: file: cannot overwrite existing file
    

    如上所示即可避免覆盖写入,当想再次使用后

    $ set +o noclobber
    $ echo "5" > file.out
    $ cat file.out
    5
    

    如果想临时的覆盖文档内容,而不取消限制,那么可以使用”>|”

    $ set -o noclobber
    $ echo "6" >| file.out
    $ cat file.out
    6
    

    来看一道题,为什么file文件为空

    $ echo "some text here" > file
    $ cat < file
    some text here
    $ cat < file > file.bak
    $ cat < file.bak
    some text here
    $ cat < file > file
    $ cat < file
    

    [toggle title="点击展开"]
    前面提到:$ cat < file > file 之后原本有内容的档案结果却被洗掉了﹗
    要理解这一现像其实不难,这只是 priority 的问题而已:
    * 在 IO Redirection 中,stdout 与 stderr 的管道会先准备好,才会从 stdin 读进资料。
    也就是说,在上例中,> file 会先将 file 清空,然后才读进 < file ,
    但这时候档案已经被清空了,因此就变成读不进任何资料了…
    [/toggle]
    2个问题

    $ cat <> file (如果说前面的用优先级解释,但是这个不理解,暂时放一放吧)
    $ cat < file >> file
    

    (16)管道内保存数据

    在 cm1 | cm2 | cm3 … 这段 pipe line 中,若要将 cm2 的结果存到某一档案呢?
    若你写成 cm1 | cm2 > file | cm3 的话,
    那你肯定会发现 cm3 的 stdin 是空的﹗(当然啦,你都将水管接到别的水池了﹗)
    聪明的你或许会如此解决:

    cm1 | cm2 > file ; cm3 < file
    

    虽然这样可行,但是文件I/O会加倍,严重影响效率,所以解决方法是使用tee命令,如下:

    cm1 | cm2 | tee file | cm3
    

    (17)几个条件判断
    [toggle title="&&与||实现"]

    comd1 && {
     comd2
     comd3
     :
    } || {
     comd4
     comd5
    }
    

    [/toggle]
    [toggle title="if...than...else句式"]

    if comd1
    then
        comd2
        comd3
    else
        comd4
        comd5
    fi
    
    if comd1; then
        comd2
    elif comd3; then
        comd4
    else
        comd5
    fi
    

    [/toggle]
    这个的意思是:意思是说:
    若 comd1 为 true ,然则执行 comd2 ﹔否则再测试 comd3 ,然则执行 comd4 ﹔倘若 comd1 与 comd3 均不成立,那就执行 comd5 。

    提别一提的是,当than后面不需要接命令的话,可以使用“:”符号占位,这里就不多记录了,和C语言一样,多多的书写实践还能写出得心应手的脚本。

    (18)循环

    原文写的很简单易懂,我就直接摘过来了~

    最后要介绍的是 shell script 设计中常见的”循环”(loop)。
    所谓的 loop 就是 script 中的一段在一定条件下反覆执行的代码。
    bash shell 中常用的 loop 有如下三种:
    * for
    * while
    * until

    for loop 是从一个清单列表中读进变量值,并”依次”的循环执行 do 到 done 之间的命令行。
    例:
    [toggle title="in句式"]

    for var in one two three four five
    do
        echo -----------
        echo '$var is '$var
        echo
    done
    

    上例的执行结果将会是:
    1) for 会定义一个叫 var 的变量,其值依次是 one two three four five 。
    2) 因为有 5 个变量值,因此 do 与 done 之间的命令行会被循环执行 5 次。
    3) 每次循环均用 echo 产生三行句子。
    而第二行中不在 hard quote 之内的 $var 会依次被替换为 one two three four five 。
    4) 当最后一个变量值处理完毕,循环结束。

    我们不难看出,在 for loop 中,变量值的多寡,决定循环的次数。
    然而,变量在循环中是否使用则不一定,得视设计需求而定。
    倘若 for loop 没有使用 in 这个 keyword 来指定变量值清单的话,其值将从 $@ (或 $* )中继承:

    for var; do
    ....
    done
    

    [/toggle]
    for loop 用于处理”清单”(list)项目非常方便,
    其清单除了可明确指定或从 positional parameter 取得之外,
    也可从变量替换或命令替换取得… (再一次提醒:别忘了命令行的”重组”特性﹗)
    然而,对于一些”累计变化”的项目(如整数加减),for 亦能处理:

    for ((i=1;i<=10;i++))
    do
       echo "num is $i"
    done
    

    除了 for loop ,上面的例子我們也可改用 while loop 來做到:

    num=1
    while [ "$num" -le 10 ]; do
        echo "num is $num"
        num=$(($num + 1))
    done
    

    while loop 的原理与 for loop 稍有不同:
    它不是逐次处理清单中的变量值,而是取决于 while 后面的命令行之 return value :
    * 若为 ture ,则执行 do 与 done 之间的命令,然后重新判断 while 后的 return value 。
    * 若为 false ,则不再执行 do 与 done 之间的命令而结束循环。

    分析上例:
    1) 在 while 之前,定义变量 num=1 。
    2) 然后测试(test) $num 是否小于或等于 10 。
    3) 结果为 true ,于是执行 echo 并将 num 的值加一。
    4) 再作第二轮测试,此时 num 的值为 1+1=2 ,依然小于或等于 10,因此为 true ,继续循环。
    5) 直到 num 为 10+1=11 时,测试才会失败… 于是结束循环。

    我们不难发现:
    * 若 while 的测试结果永远为 true 的话,那循环将一直永久执行下去:

    while :; do
        echo looping...
    done
    

    一旦你能够理解 while loop 的话,那,就能理解 until loop :
    * 与 while 相反,until 是在 return value 为 false 时进入循环,否则结束。
    因此,前面的例子我们也可以轻鬆的用 until 来写:

    num=1
    until [ ! "$num" -le 10 ]; do
        echo "num is $num"
        num=$(($num + 1))
    done
    

    或是

    num=1
    until [ "$num" -gt 10 ]; do
        echo "num is $num"
        num=$(($num + 1))
    done
    

    (19)break与continue(与C相同)

    这两个命令常用在複合式循环裡,也就是在 do … done 之间又有更进一层的 loop ,
    当然,用在单一循环中也未尝不可啦… ^_^

    break 是用来打断循环,也就是”强迫结束” 循环。
    若 break 后面指定一个数值 n 的话,则”从裡向外”打断第 n 个循环,
    预设值为 break 1 ,也就是打断当前的循环。
    在使用 break 时需要注意的是, 它与 return 及 exit 是不同的:
    * break 是结束 loop
    * return 是结束 function
    * exit 是结束 script/shell

    而 continue 则与 break 相反:强迫进入下一次循环动作。
    若你理解不来的话,那你可简单的看成:在 continue 到 done 之间的句子略过而返回循环顶端…
    与 break 相同的是:continue 后面也可指定一个数值 n ,以决定继续哪一层(从裡向外计算)的循环,
    预设值为 continue 1 ,也就是继续当前的循环。

    在 shell script 设计中,若能善用 loop ,将能大幅度提高 script 在複杂条件下的处理能力。
    请多加练习吧….

    (20)[^ ] 跟 [! ]

    通配符(wildcard)知识,暂不记录
    “^”是正则表达式中符号,”!”是通配符中的符号,都表示”非”

    (21)eval

    eval是完成命令重组后再一次重组

    a=1
    A1=abc
    eval echo $A$a
    

    (22)正则表达式
    正则表达式(Regular Expression)知识,暂不记录
    (23)grep与egrep与fgrep区别
    * grep:
    传统的 grep 程式, 在没有参数的情况下, 只输出符合 RE 字串之句子. 常见参数如下:
    -v: 逆反模示, 只输出”不含” RE 字串之句子.
    -r: 递迴模式, 可同时处理所有层级子目录裡的文件.
    -q: 静默模式, 不输出任何结果(stderr 除外. 常用以获取 return value, 符合为 true, 否则为 false .)
    -i: 忽略大小写.
    -w: 整词比对, 类似 <word> .
    -n: 同时输出行号.
    -c: 只输出符合比对的行数.
    -l: 只输出符合比对的文件名称.
    -o: 只输出符合 RE 的字串. (gnu 新版独有, 不见得所有版本都支持.)
    -E: 切换为 egrep .

    * egrep:
    为 grep 的扩充版本, 改良了许多传统 grep 不能或不便的操作. 比方说:
    - grep 之下不支持 ? 与 + 这两种 modifier, 但 egrep 则可.
    - grep 不支持 a|b 或 (abc|xyz) 这类”或一”比对, 但 egrep 则可.
    - grep 在处理 {n,m} 时, 需用 { 与 } 处理, 但 egrep 则不需.
    诸如此类的… 我个人会建议能用 egrep 就不用 grep 啦… ^_^

    * fgrep:
    不作 RE 处理, 表达式仅作一般字串处理, 所有 meta 均失去功能.

  • 相关阅读:
    druid 基本配置
    计算机组成
    数据结构
    shell编程练习
    java之Nio
    java集合深入学习
    mysql学习
    tomcat学习
    大数据面试题
    计算机网络复习
  • 原文地址:https://www.cnblogs.com/ishell/p/4240139.html
Copyright © 2020-2023  润新知