• bash 教程5 shell 流程控制 条件判断 重定向 read [MD]


    博文地址

    我的GitHub 我的博客 我的微信 我的邮箱
    baiqiantao baiqiantao bqt20094 baiqiantao@sina.com

    目录

    Bash 教程

    本文改编自 网道的 Bash 教程,主要为了精简大量本人不感兴趣的内容。

    流程控制

    if 条件判断

    if commands; then
      commands
    [elif commands; then
      commands...]
    [else
      commands]
    fi
    
    • elifelse 部分是可选的,elif 部分也可以有多个
    • ifthenelifelsefi 命令可以写在同一行,此时各个命令之间需要加分号分隔符
    • if 后面跟一个命令时,如果命令执行成功(即命令的返回值为 0),则代表判断条件成立
    • if 后面跟多个命令时,所有命令都会执行,只要最后一个命令返回 0,就代表判断条件成立
    if true; then echo '执行成功'; fi     # true 代表成功
    if pwd; then echo '执行成功'; fi      # 如果命令执行成功,则代表判断条件成立
    if false; true; then echo '成功'; fi  # 只要最后一个命令执行成功,就代表判断条件成立
    

    case 条件判断

    case 结构与其他语言中的 switch ... case 语句类似,用于多值判断时语义更好,可以为每个值指定对应的命令。

    case expression in  # expression 是一个表达式
      pattern )         # pattern 是表达式的一个值或一个模式,以右括号结束,中间的空格可省略
        commands ;;     # 每个匹配模式以 ;; 结尾,匹配到一个条件后就会退出 case 结构
      pattern )
        commands ;;     # 高版本中可以用 ;;& 结尾,此时匹配到一个条件后不会退出 case 结构
      *) commands ;;    # 如果无匹配的模式,可在最后使用星号 * 捕获该值
      ...
    esac
    

    case 的匹配模式可以使用通配符:

    • a ):匹配单个字符 a
    • a|b ):匹配单个字符 ab
    • [[:alpha:]] ):匹配单个字母
    • ??? ):匹配包含 3 个字符的字符串
    • *.txt ):匹配以 .txt 结尾的字符串
    • * ):匹配任意输入,通常作为 case 结构的最后一个模式,用于匹配其他字符和没有输入字符的情况
    case $1 in
      [10-19] )     echo "数字" ;;        # 在匹配一个条件之后,立即退出了 case 结构
      [[:upper:]])  echo "大写" ;;&       # 在匹配一个条件之后,会继续判断下一个条件
      [[:lower:]])  echo "小写" ;;&
      [[:alpha:]])  echo "字母" ;;&
      [[:digit:]])  echo "数字" ;;&
      [[:graph:]])  echo "可见字符" ;;&
      [[:punct:]])  echo "标点符号" ;;&
      [[:space:]])  echo "空格" ;;&
      [[:xdigit:]]) echo "十六进制" ;;&
      * )           echo "其他"
    esac
    

    while 循环

    • break:立即终止循环,程序继续执行循环块之后的语句,而不再执行剩下的循环
    • continue:立即终止本轮循环,继续执行下一轮循环
    while condition; do  # 只要符合条件,就不断循环执行指定的语句
      commands
    done
    

    循环条件 condition 可以是执行一个命令,也可以是一个 test 命令。

    while true; do echo '循环'; done             # 按 Ctrl + C 结束
    while true; false; do echo '不会执行'; done  # 只看最后一个命令的执行结果
    while echo '满足条件'; do echo '循环'; done
    
    number=0
    while [ "$number" -lt 10 ]; do
      echo "Number = $number"
      number=$((number + 1))
    done
    

    until 循环

    until condition; do   # 只要不符合条件,就不断循环执行指定的语句
      commands
    done
    

    一般来说,until 用得比较少,只要把条件 condition 设为否定,until 循环都可以转为 while 循环。注意,until 语句极其危险,后面的 condition 语法一旦有误,就会陷入死循环之中。

    until false; do echo '循环'; done
    
    number=0
    until [ "$number" -ge 10 ]; do
      echo "Number = $number"
      number=$((number + 1))
    done
    
    until cp $1 $2; do                 # 在命令执行成功之前,不断重复尝试
      echo '执行失败,5 秒钟后继续尝试'
      sleep 5
    done
    

    for...in 循环

    for...in 循环用于遍历列表的每一项。

    for var in list; do  # 依次从 list 列表中取出一项,作为变量 var
      commands           # 然后在循环体中进行处理
    done
    
    for i in a b c; do echo --$i--; done
    for i in *.mk; do ls -l $i; done       # 遍历当前目录中所有 .md 文件
    for i in $(cat $1); do echo $i; done   # 遍历文件中的每个单词
    
    for i in $@; do echo $i; done   # 遍历脚本的所有参数
    for i; do echo $i; done         # 省略 in list 时,list 默认等于脚本的所有参数
    
    • 在脚本中,省略 for...in 循环的 in list 时,list 默认等于脚本的所有参数
    • 在函数中,省略 for...in 循环的 in list 时,list 默认等于函数的所有参数

    for 循环

    for (( exp1; exp2; exp3 )); do   # 初始化,循环结束条件,每次迭代后执行
      commands
    done
    
    # 等同于下面的 while 循环
    (( exp1 ))
    while (( exp2 )); do
      commands
      (( exp3 ))
    done
    

    圆括号之中使用变量不必加上美元符号 `<pre style="color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke- 0px; text-decoration-style: initial; text-decoration-color: initial; overflow-wrap: break-word; white-space: pre-wrap;"

    for (( i=0; i<5; i=i+1 )); do echo $i; done
    
    for ((;;)); do
      read -p "请输入工号,输入 over 结束 " var
      echo "您输入了 $var"
      if [ "$var" = "over" ]; then break; fi
    done
    

    select 循环

    select 结构主要用来生成简单的菜单。它的语法与 for...in 循环基本一致。

    • 生成一个菜单,内容是列表 list 的每一项,并且每一项前面还有一个数字编号,格式为 1)
    • 提示用户输入数字编号,按回车完成输入
    • 将用户输入的内容存入环境变量 REPLY,将 REPLY 对应的 list 的内容存入变量 name
    • 如果用户输入了错误的内容,或者没有输入内容直接按回车键,则 name 为空,然后回到第一步
    • 执行命令 commands,执行后回到第一步
    select name [in list]; do   # 用户输入以后,将用户输入的内容存入环境变量 REPLY
      commands                  # 将 REPLY 对应的 list 的内容存入变量 name,如果内容不在 list 中,则 name 为空
    done
    

    select 结构默认不会结束,直到用户按下 Ctrl + C,或者在程序中出现 break 才会退出执行。

    select key in a b c d; do echo "选择了 $REPLY - $key"; date; done    # 默认执行完后不会结束
    select key in a b c d; do echo "选择了 $key"; continue; date; done   # continue 仅会结束当次循环
    select key in a b c d; do echo "选择了 $key"; break; date; done      # break 可以结束 select 循环
    select key in a b c d; do echo "选择了 $key"; exit 0; date; done     # exit 会结束整个脚本的执行
    

    select 可以与 case 结合,针对不同项,执行不同的命令。

    echo "选择你喜欢的操作系统"
    select os in Ubuntu LinuxMint Windows8 Windows10; do
      case $os in
        "Ubuntu"|"LinuxMint") echo "你喜欢 Linux" ;;
        "Windows8" | "Windows10") echo "你喜欢 Windows" ;;
        *) echo "无效输入"; break ;;                          # 执行完会结束 select 结构
      esac
      echo "选择你喜欢的操作系统"
    done
    

    用于条件判断的表达式

    以下基本都是 test 命令的语法,test 命令用于检查某个条件是否成立,它可以进行数值、字符和文件三个方面的判断。

    • $[ ] 作为 算术表达式 时,中括号与内部的表达式之间【不需要有空格】
    • [ ] 作为 条件表达式 时(即 test 命令语法),中括号与内部的表达式之间【必须有空格】

    test 命令 [ ] [[ ]]

    test 命令有三种形式。

    test expression     # 写法一,如果表达式 expression 为真,则表示执行成功,返回值 $? 为 0
    [ expression ]      # 写法二,中括号与内部的表达式之间【必须有空格】
    [[ expression ]]    # 写法三,中括号与内部的表达式之间【必须有空格】,支持正则判断
    [[ str =~ regex ]]  # 如果字符串 str 满足正则表示式 regex,则判断为真
    echo $[2+2]         # 【4】做整数运算时,中括号与内部的表达式之间不需要有空格
    
    INT=$1
    if [[ "$INT" =~ ^-?[0-9]+$ ]]; then echo "是整数"; exit 0
    else echo "不是整数" >&2; exit 1
    fi
    

    注意,test 命令内部的 ()<> 等符合需要用引号引起来(或者是用反斜杠转义),否则会被解释

    文件判断 -e -d -f

    if 关键字后面也可以是下面这些文件判断表达式

    建议将文件放在双引号之中,否则文件为空或有空格时,判断会出错

    • [ -a file ]:如果 file 存在,则为true
    • [ -b file ]:如果 file 存在并且是一个块(设备)文件,则为true
    • [ -c file ]:如果 file 存在并且是一个字符(设备)文件,则为true
    • [ -d file ]:如果 file 存在并且是一个目录,则为true
    • [ -e file ]:如果 file 存在,则为true
    • [ -f file ]:如果 file 存在并且是一个普通文件,则为true
    • [ -g file ]:如果 file 存在并且设置了组 ID,则为true
    • [ -G file ]:如果 file 存在并且属于有效的组 ID,则为true
    • [ -h file ]:如果 file 存在并且是符号链接,则为true
    • [ -k file ]:如果 file 存在并且设置了它的 sticky bit,则为true
    • [ -L file ]:如果 file 存在并且是一个符号链接,则为true
    • [ -N file ]:如果 file 存在并且自上次读取后已被修改,则为true
    • [ -O file ]:如果 file 存在并且属于有效的用户 ID,则为true
    • [ -p file ]:如果 file 存在并且是一个命名管道,则为true
    • [ -r file ]:如果 file 存在并且可读(当前用户有可读权限),则为true
    • [ -s file ]:如果 file 存在且其长度大于零,则为true
    • [ -S file ]:如果 file 存在且是一个网络 socket,则为true
    • [ -t fd ]:如果 fd 是一个文件描述符,并且重定向到终端,则为true。可以用来判断是否重定向了标准输入/输出/错误
    • [ -u file ]:如果 file 存在并且设置了 setuid 位,则为true
    • [ -w file ]:如果 file 存在并且可写(当前用户拥有可写权限),则为true
    • [ -x file ]:如果 file 存在并且可执行(有效用户有执行/搜索权限),则为true
    • [ file1 -nt file2 ]:如果 FILE1 比 FILE2 的更新时间最近,或者 FILE1 存在而 FILE2 不存在,则为true
    • [ file1 -ot file2 ]:如果 FILE1 比 FILE2 的更新时间更旧,或者 FILE2 存在而 FILE1 不存在,则为true
    • [ FILE1 -ef FILE2 ]:如果 FILE1 和 FILE2 引用相同的设备和 inode 编号,则为true
    FILE=  # 注意:如果 FILE 为空,这时 $FILE 不加双引号时会被判断为真(错误逻辑),放在双引号之中会被判断为假
    if [ -e "$FILE" ] || [ -f "$FILE" ] || [ -d "$FILE" ]; then echo "$FILE:条件成立"; fi # 条件成立
    if [ -e $FILE ] && [ -f $FILE ] && [ -d $FILE ]; then echo "$FILE:条件不成立"; fi     # 条件不成立
    
    FILE=$1
    if [ -e "$FILE" ]; then
      if [ -f "$FILE" ]; then echo "$FILE:存在且是普通文件"; fi
      if [ -d "$FILE" ]; then echo "$FILE:存在且是目录"; fi
      if [ -r "$FILE" ]; then echo "$FILE:存在且可读."; fi
      if [ -w "$FILE" ]; then echo "$FILE:存在且可写."; fi
      if [ -x "$FILE" ]; then echo "$FILE:存在且可执行"; fi
    else echo "$FILE:不存在"
    fi
    

    字符串判断 -n -z >

    if 关键字后面也可以是下面这些字符串判断表达式

    建议将字符串放在双引号之中,否则字符串为空或者有空格时,判断会出错

    • [ string ]:如果 string 不为空(长度大于0),则判断为真
    • [ -n string ]:如果字符串 string 的长度大于零,则判断为真
    • [ -z string ]:如果字符串 string 的长度为零,则判断为真
    • [ string1 = string2 ]:如果 string1 和 string2 相同,则判断为真
    • [ string1 == string2 ] 等同于 [ string1 = string2 ]
    • [ string1 != string2 ]:如果 string1 和 string2 不相同,则判断为真
    • [ string1 '>' string2 ]:如果按照字典顺序 string1 排列在 string2 之后,则判断为真
    • [ string1 '<' string2 ]:如果按照字典顺序 string1 排列在 string2 之前,则判断为真
    ANSWER=$1
    if [ -z "$ANSWER" ]; then echo "字符串为空" >&2; exit 1; fi   # 重定向到标准错误
    if [ "$ANSWER" = "yes" ]; then echo "字符串是 YES"
    elif [ "$ANSWER" = "no" ]; then echo "字符串是 NO"
    else echo "UNKNOWN"
    fi
    

    整数判断 -eq -le -gt

    if 关键字后面也可以是下面这些整数判断表达式

    建议先判断字符串是否为空,否则字符串为空时,判断会出错

    • [ integer1 -eq integer2 ]:如果 integer1 等于 integer2 ,则为 true
    • [ integer1 -ne integer2 ]:如果 integer1 不等于 integer2 ,则为 true
    • [ integer1 -le integer2 ]:如果 integer1 小于或等于 integer2 ,则为 true
    • [ integer1 -lt integer2 ]:如果 integer1 小于 integer2 ,则为 true
    • [ integer1 -ge integer2 ]:如果 integer1 大于或等于 integer2 ,则为 true
    • [ integer1 -gt integer2 ]:如果 integer1 大于 integer2 ,则为 true
    INT=$1
    if [ -z "$INT" ]; then echo "字符串为空" >&2; exit 1; fi   # 重定向到标准错误
    
    if [ $INT -eq 0 ]; then echo "等于零"
    else
      if [ $INT -lt 0 ]; then echo "小于零"; else echo "大于零"; fi
      if [ $((INT % 2)) -eq 0 ]; then echo "偶数 even"; else echo "奇数 odd"; fi
    fi
    

    整数的算术表达式 (( ))

    if 关键字后面也可以是下面这些整数的算术表达式

    • Bash 提供的算术表达式 ((...)) 可以进行算术运算的判断
    • 如果算术计算的结果是非零值,则表示判断成立。这一点跟命令的返回值正好相反,需要小心
    • 算术条件也可以用于变量赋值,赋值语句返回等号右边的值,如果返回的是非零值,则表示判断成立
    if ((3 > 2)); then echo "true"; fi                 # 判断条件为真
    if ((1)); then echo "true"; fi                     # 算术计算的结果是非零值,判断条件为真
    if ((0)); then echo "true"; else echo "false"; fi  # 算术计算的结果是 0,判断条件为假
    if (( foo = 5 )); then echo "foo is $foo"; fi      # 首先把 5 赋值给变量,然后返回 5,判断条件为真
    if (( foo = 0 )); then pwd; else echo "false"; fi  # 首先把 0 赋值给变量,然后返回 0,判断条件为假
    

    下面是用算术条件改写的数值判断脚本。

    INT=$1
    if [[ "$INT" =~ ^-?[0-9]+$ ]]; then
      if ((INT == 0)); then echo "等于零"
      else
        if ((INT < 0)); then echo "小于零"; else echo "大于零"; fi
        if (( ((INT % 2)) == 0)); then echo "偶数 even"; else echo "奇数 odd"; fi
    fi
    

    逻辑运算符 && ! -a

    通过逻辑运算,可以把多个判断表达式结合起来。

    • &&:等价于使用参数 -a
    • ||:等价于使用参数 -o
    • !:使用否定操作符时,最好用圆括号确定转义的范围
    mkdir temp && cd temp
    [ ! -d temp ] && exit 1      # 如果不是一个目录,则结束
    [ -d temp ] || mkdir temp    # 如果不是一个目录,则创建目录
    if [ condition1 ] && [ condition2 ] && cd temp; then command; fi
    if [ ! \( condition1 -a condition2 \) ]; then echo "满足条件"; fi  # 使用 ! 时,最好用圆括号确定转义的范围
    

    read 命令

    读取键盘输入内容

    可以使用 read 命令要求用户提供一些数据,并将用户的输入存入变量中。

    • 如果输入项少于 read 命令给出的变量数目,那么多余的变量值为空
    • 如果输入项多于 read 命令给出的变量数目,那么多余的输入项会包含到最后一个变量中
    • 如果 read 命令之后没有定义变量名,那么环境变量 REPLY 会包含输入的一整行数据
    echo "请输入姓名和年龄,以空格分隔,按下回车键表示输入结束"
    read name age    # 变量名 name age 用来保存输入的数值
    echo "姓名:$name 年龄:$age"
    

    逐行读取文件内容

    read 命令除了读取键盘输入,还可以用来读取文件。

    #!/bin/bash
    
    filename='/etc/hosts'
    declare -i line=0  # 声明为整数变量,用于记录行数
    
    while read text    # 使用 read 命令读取文件内容,每次读取一行,并将内容存入变量
    do
      echo "$((++line)) $text"  # 打印每行内容
    done < $filename            # 定向符 < 用于将文件内容导向 read 命令
    

    上面的命令可以逐行读取文件,每一行存入变量 text,打印出来以后再读取下一行。

    常用参数

    • -t:设置超时的秒数。如果超时仍没有输入,脚本将放弃等待,继续向下执行
    • -p:指定用户输入的提示信息,等价于在 read 命令前先执行一个 echo 命令
    • -a:把用户的输入赋值给一个数组
    • -n:限制输入的字符数量(指定只读取若干个字符作为变量值)
    • -e:允许用户输入的时候,使用 readline 库提供的快捷键,比如自动补全
    • -d delimiter:定义使用 delimiter 的第一个字符作为用户输入的结束,而不是换行符
    • -r:raw 模式,表示不把用户输入的反斜杠字符解释为转义字符
    • -s:使得用户的输入不显示在屏幕上,这常常用于输入密码或保密信息
    • -u fd:使用文件描述符 fd 作为输入
    read -t 3 text && echo "用户输入了 $text"
    read -t 3 text || echo "用户在 3 秒内没有输入内容"
    
    TMOUT=3   # 环境变量 TMOUT 也可以指定 read 命令默认等待超时秒数
    read text || echo "用户在 3 秒内没有输入内容"
    
    read -a array && echo ${array[1]}  # 将用户输入被赋值给一个数组,从位置 0 开始
    read -n 3 nnn && echo $nnn         # 限制最多输入 3 个字符
    read -e file  && echo $file        # 加 -e 参数可以允许用户使用自动补全等快捷键
    

    注意,环境变量 TMOUT 默认是没有设置值的,如果设置的话,也会影响启动的 bash 终端(猜测因为它也是通过 read 命令获取用户输入的),如果在指定的 TMOUT 内没有任何输入,bash 终端也会立即退出。

    字段分隔符:IFS

    • read 命令读取的值,默认是以空格分隔
    • 可以通过自定义环境变量 IFS(内部字段分隔符,Internal Field Separator),修改分隔标志
    • IFS 的默认值是空格、Tab 符号、换行符号,通常取第一个(即空格)
    • 如果 IFS 设为空字符串,就等同于将整行读入一个变量
    FILE=/etc/passwd
    info="$(grep "^$USER:" $FILE)"  # 【bqt:x:1000:1000:,,,:/home/bqt:/bin/bash】
    
    IFS=":" read user pw uid gid name home shell <<< $info
    echo $user -  $pw - $uid - $gid - $name - $home - $shell
    
    • 上面的代码中,将 IFS 设为冒号 :,然后用来分解 /etc/passwd 文件的一行
    • 上面 IFS 的赋值命令和 read 命令写在了一行,则 IFS 的改变仅对此行后面的命令生效,该命令执行后,IFS 会自动恢复原来的值
    • <<< 是 Here 字符串,用于将变量值转为标准输入,因为 read 命令只能解析标准输入

    printf 命令

    printf 由 POSIX 标准所定义,因此使用 printf 的脚本比使用 echo 移植性好。printf 使用引用文本或空格分隔的参数,外面可以在 printf 中使用格式化字符串,还可以制定字符串的宽度、左右对齐方式等。

    • 格式替代符 %s%c%d%f 分别代表替换字符串、字符、整数、浮点数
    • %-7s:以左对齐的方式,显示至少 7 个字符宽度的字符串
      • 一个中文算 3 个字符、一个英文算 1 个字符
      • 如果宽度不足则自动用空格填充,如果宽度超过也会将内容全部显示出来
      • - 表示左对齐,没有则表示右对齐
    • %-5.2f:以至少 5 个字符宽度、保留 2 位小数的方式,显示数字
      • 小数点算 1 个字符
      • 小数点后的位数需要强制保留,会四舍五入

    格式控制字符串

    printf "%-7s %-4s" 姓名 性别   # 【姓名  性别】以左对齐的方式,显示至少 7 个字符宽度的字符串
    printf "%7s %4s\n" 姓名 性别   # 【 姓名 性别】以右对齐的方式,显示至少 7 个字符宽度的字符串
    
    # 如果格式只指定了一个参数,那么多出的参数仍然会按照该格式输出
    printf "%-5.2f-" 1.2 1234.555 # 【1.20 -1234.56-】至少显示 5 个字符宽度,强制保留 2 位小数
    printf "%s %s\n" a b c d e    # 【a b(换行)c d(换行)e(换行)】
    
    printf "%s-%d-%c-%f"          # 【-0--0.000000】没有参数列表时的默认值
    

    换行

    printf "白乾涛\n"       # 【白乾涛(换行)】----------第一种换行方式:省略参数列表
    printf '白乾涛\n'       # 【白乾涛(换行)】格式控制字符串使用单引号、双引号效果一般是一样的
    printf 白乾涛\n         # 【白乾涛n】参数列表中有换行时,需要用引号引住
    
    printf "%s\n" "白乾涛"  # 【白乾涛(换行)】---------第二种换行方式:在格式控制字符串中换行
    printf "%s\n" "白\n乾"  # 【白\n乾(换行)】有格式控制字符串时,参数列表中的换行符无效
    printf %s "白乾涛\n"    # 【白乾涛\n】有格式控制字符串时,参数列表中的换行符无效
    printf %s\n "白乾涛"    # 【白乾涛n】格式控制字符串中有换行时,需要用引号引住
    
    printf "%b" "白白\n"    # 【白白(换行)】------------第三种换行方式:使用 %b 在哪都可以换行
    printf "%b\n" "白\n白"  # 【白(换行)白(换行)】使用 %b 在哪都可以换行
    

    输入输出重定向

    参考

    文件描述符

    Linux 中 一切皆文件,所有计算机硬件也都是文件。Linux 会给每个文件分配一个整数的 ID,这个 ID 被称为文件描述符(File Descriptor)。Linux 程序在执行任何形式的 I/O 操作时,都是在读写一个文件描述符。一个文件描述符只是一个和打开的文件相关联的整数,它的背后可能是一个硬盘上的普通文件、FIFO、管道、终端、键盘、显示器,甚至是一个网络连接。

    一般情况下,每个 Linux 命令运行时都会打开以下三个文件:

    • 文件描述符为 0 的标准输入文件 STDIN,对应的硬件设备为键盘
    • 文件描述符为 1 的标准输出文件 STDOUT,对应的硬件设备为显示器
    • 文件描述符为 2 的标准错误输出文件 STDERR,对应的硬件设备为显示器

    Unix 程序默认会从 STDIN 中读取输入信息,并将输出信息写入到 STDOUT,将错误信息写入到 STDERR

    输出重定向 fd>file

    输出重定向就是改变输出的方向,即不再将命令的结果输出到显示器上,而是输出到其它地方,比如文件中。这样就可以把命令的结果保存起来。

    输出重定向语法:command fd>file 或者 command fd>>file

    • fd 表示文件描述符,当 fd 为 1 时(即标准输出),可省略不写
    • > 代表覆盖,>> 代表追加
    • 注意:> 和 fd 中间 不可以 有空格,> 和 file 中间的空格可有可无

    标准输出、标准错误输出重定向

    • command >file:以覆盖的方式,把 command 的正确输出结果输出到 file 文件中
    • command >>file:以追加的方式,把 command 的正确输出结果输出到 file 文件中
    • command 2>file:以覆盖的方式,把 command 的错误信息输出到 file 文件中
    • command 2>>file:以追加的方式,把 command 的错误信息输出到 file 文件中
    file=outFile.txt
    echo "aaa" >$file && cat $file   # 将命令执行结果写入到文件中,会覆盖文件内容
    echo "bbb" >>$file && cat $file  # 将命令执行结果追加到文件后面,不会覆盖文件内容
    
    # 注意:命令正确执行时是没有错误信息的,另外执行出错后必须使用 || 才会执行同一行的其他命令
    xxx 2>$file || cat $file         # 将命令 xxx 不存在的错误信息,以覆盖方式写入文件中
    ls xxx . 2>>$file || cat $file   # 将执行 ls 时找不到文件的错误信息,追加写入到文件中
    

    标准输出、标准错误输出同时重定向

    • command >file 2>&1:以覆盖的方式,把正确输出和错误信息同时保存到文件 file 中
    • command >>file 2>&1:以追加的方式...
    • command >file1 2>file2:把正确的输出结果输出到 file1 中,把错误信息输出到 file2 中
    • command >>file1 2>>file2:以追加的方式...
    • command >file 2>file:【不推荐】stdout 和 stderr 会互相覆盖
    • command >>file 2>>file:【不推荐】stdout 和 stderr 会互相覆盖
    file1=out.txt
    file2=error.txt
    ls xxx . 2>$file1          # 把正确结果和错误信息都保存到文件 file1 中
    ls xxx . >$file1 2>$file2  # 把正确的输出结果输出到 file1 中,把错误信息输出到 file2 中
    

    重定向 /dev/null 文件

    如果你既不想把命令的输出结果保存到文件,也不想把命令的输出结果显示到屏幕上,那么可以把命令的所有结果重定向到文件 /dev/null 中。这是一个特殊的文件,写入到它的内容都会被丢弃,并且不能恢复。如果尝试从该文件读取内容,那么什么也读不到

    ls xxx . >/dev/null
    ls xxx . &>/dev/null
    ls xxx . >/dev/null 2>&1
    

    输入重定向 fd<file

    输入重定向就是改变输入的方向,即不再使用键盘作为命令输入的来源,而是使用文件作为命令的输入。

    • command <file:将 file 文件中的内容作为 command 的输入
      • 和输出重定向类似,输入重定向的完整写法是 fd<file
      • 当文件描述符 fd 为 0 时(即标准输入),可省略不写
    • command <file1 >file2:将 file1 作为 command 的输入,并将 command 的处理结果输出到 file2
    • command <<END:从标准输入中读取数据,直到遇见分界符 END 才停止,其实就是之前提到的 Here Document
    in=inFile.txt
    out=outFile.txt
    while read str; do echo "-- $str"; done <$in  # 逐行读取文件内容
    
    # wc 命令可以用来对文本进行统计,包括单词个数(-w)、行数(-l)、字节数(-c)
    wc -l $in       # 【2 inFile.txt】统计指定文件的行数,这里会打印文件名
    wc -l <$in      # 【2】统计标准输入文件 STDIN 的行数,这里不会打印文件名
    
    cat <$in >$out  # 从 in 中读取内容,然后将输出写入到 out 中
    cat << EOF
        也可以将 Here Document 用在脚本中
    这里的格式会被保留的,例如前面的空格或 Tab 符
    EOF
    

    2022-1-22

  • 相关阅读:
    [转]MNIST机器学习入门
    nvidia tesla k40
    [转]LeNet-5结构分析及caffe实现————卷积部分
    caffe
    [转]CNN的学习
    Mysql常用命令记录
    jaxb xml to bean
    吸血鬼数字算法参考 -- javascript版本
    jQuery input -> file change事件bug
    Jetty
  • 原文地址:https://www.cnblogs.com/baiqiantao/p/15835128.html
Copyright © 2020-2023  润新知