重定向

重定向是 Shell 的核心特性之一,它可以改变数据流的走向。把输出保存到文件、从文件读取输入、把错误信息单独处理,都离不开重定向。

输出重定向

覆盖写入

> 把命令输出写入文件,会覆盖原有内容:

echo "Hello World" > output.txt
ls -l > filelist.txt

如果文件不存在,会自动创建。

追加写入

>> 在文件末尾追加内容,不覆盖原有内容:

echo "第一行" > log.txt
echo "第二行" >> log.txt
echo "第三行" >> log.txt

log.txt 的内容:

第一行
第二行
第三行

日志文件通常用追加方式写入。

输入重定向

< 从文件读取输入:

while read line; do
    echo "读取到:$line"
done < data.txt

统计文件的行数:

wc -l < data.txt

错误重定向

标准错误(文件描述符 2)可以单独重定向:

ls 不存在的文件 2> error.log

把错误信息写入 error.log,正常输出仍显示在屏幕。

同时重定向输出和错误

ls / /notexist > output.txt 2> error.txt

正常输出到 output.txt,错误信息到 error.txt。

输出和错误写入同一文件

ls / /notexist > all.txt 2>&1

2>&1 表示把标准错误重定向到标准输出。注意顺序很重要:

# 正确:先重定向输出,再把错误指向输出
command > file.txt 2>&1

# 错误:错误还是输出到屏幕
command 2>&1 > file.txt

更简洁的写法:

command &> file.txt

丢弃输出

把输出重定向到 /dev/null,相当于丢弃:

# 丢弃正常输出
command > /dev/null

# 丢弃错误输出
command 2> /dev/null

# 丢弃所有输出
command &> /dev/null

这在判断命令是否执行成功时很有用:

if grep -q "pattern" file.txt 2> /dev/null; then
    echo "找到了"
fi

Here Document

Here Document 用于在脚本中嵌入多行文本:

cat << EOF
这是第一行
这是第二行
变量值:$HOME
EOF

运行结果:

这是第一行
这是第二行
变量值:/home/user

<< 后面是结束标记,可以任意命名,常用 EOF 或 END。

不解析变量

用单引号包住结束标记,变量不会被解析:

cat << 'EOF'
变量不会被解析:$HOME
命令替换也不会执行:$(date)
EOF

运行结果:

变量不会被解析:$HOME
命令替换也不会执行:$(date)

去除行首制表符

<<- 会忽略行首的制表符,方便脚本缩进:

if true; then
    cat <<- EOF
		第一行
		第二行
	EOF
fi

注意只有制表符会被忽略,空格不会。

Here String

Here String 是 Here Document 的简化形式,用于传递单行字符串:

grep "pattern" <<< "这是一行测试文本"
read a b c <<< "1 2 3"
echo "a=$a, b=$b, c=$c"

运行结果:

a=1, b=2, c=3

文件描述符

Shell 默认打开三个文件描述符:

编号名称默认设备
0标准输入键盘
1标准输出屏幕
2标准错误屏幕

可以自定义文件描述符:

# 打开文件描述符 3 用于读取
exec 3< input.txt

# 从文件描述符 3 读取
read -u 3 line
echo "读取到:$line"

# 关闭文件描述符
exec 3<&-

小结

  • > 覆盖写入,>> 追加写入
  • < 从文件读取输入
  • 2> 重定向错误,&> 重定向所有输出
  • /dev/null 丢弃输出
  • << EOF Here Document 多行文本
  • <<< Here String 单行字符串