bash 教程-5 shell 流程控制 条件判断 重定向 read [MD]
我的GitHub | 我的博客 | 我的微信 | 我的邮箱 |
---|---|---|---|
baiqiantao | baiqiantao | bqt20094 | baiqiantao@sina.com |
目录
目录- 目录
- Bash 教程
- 流程控制
- if 条件判断
- case 条件判断
- while 循环
- until 循环
- for...in 循环
- for 循环
- select 循环
- 用于条件判断的表达式
- test 命令 [ ] [[ ]]
- 文件判断 -e -d -f
- 字符串判断 -n -z >
- 整数判断 -eq -le -gt
- 整数的算术表达式 (( ))
- 逻辑运算符 && ! -a
- read 命令
- 读取键盘输入内容
- 逐行读取文件内容
- 常用参数
- 字段分隔符:IFS
- printf 命令
- 输入输出重定向
- 文件描述符
- 输出重定向 fd>file
- 输入重定向 fd
- 流程控制
Bash 教程
- bash-tutorial
- Bash 教程
本文改编自 网道的 Bash 教程,主要为了精简大量本人不感兴趣的内容。
流程控制
if 条件判断
if commands; then
commands
[elif commands; then
commands...]
[else
commands]
fi
elif
和else
部分是可选的,elif
部分也可以有多个if
、then
、elif
、else
、fi
命令可以写在同一行,此时各个命令之间需要加分号
分隔符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 )
:匹配单个字符a
或b
[[: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
圆括号之中使用变量不必加上美元符号 `
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
输入重定向就是改变输入的方向,即不再使用键盘作为命令输入的来源,而是使用文件作为命令的输入。
command
:将 file 文件中的内容作为 command 的输入 - 和输出重定向类似,输入重定向的完整写法是
fd
- 当文件描述符 fd 为 0 时(即标准输入),可省略不写
- 和输出重定向类似,输入重定向的完整写法是
command
:将 file1 作为 command 的输入,并将 command 的处理结果输出到 file2file2 command <
:从标准输入中读取数据,直到遇见分界符 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