文件读写
shell里最重要对一个概念就是流,所谓流就是 byte stream
面向流只有 输入 和 输出 默认的 输入是 stdin,输出是 stdout、stderr
输入和输出可以被重定向来管理字节流,从而达到文件读写的目的
文件操作 | 重定向逻辑 |
---|---|
文件写 | 重定向输出stdout至文件 |
文件读 | 重定向文件至输入stdin |
根据网络教程文件的重定向已经对基本知识介绍的很清楚,本文仅仅针对读写进行举例
文件写
1 | echo "line1" > file.txt |
文件读
文件读取到运行时的变量并不牵扯到重定向的逻辑, 直接使用 cat 获取文件内容并且赋值给变量即可
1 | var1=$(cat file.txt) |
如果非要使用 stdin 重定向,则可以使用以下代码,代表将 file.txt 作为输入并且dollar符号执行,结果赋值给var2
1 | var2=$(<file.txt) |
输入重定向是什么
对网络教程的补充
输出重定向很好理解,所有terminal的输出都会作为 byte stream保存到某个文件
而如何理解输入重定向,以下是对网络教程的补充
1 | echo "line1" > file.txt |
其中 2 代表 2行, 为何第一个带有文件名,第二个不带文件名,我们通过 man wc 来分析,文档显示以下原文
1 | //用于统计 词、行、字符、和比特数 |
其中 EOF(代表End of File),文件自然自带EOF,如果是 Here Document 通常是 Ctrl+D 用于输入一个EOF
可见仅仅输出 2 的shell命令执行了以下操作
- wc -l 不带文件名,触发从stdin读取
- < file.txt 将 file重定向到 stdin 作为输入
- file.txt 自带 EOF 输出行数且不带文件名
我们可以使用 Here Document 来模拟这个过程
1 | wc -l |
为什么echo不能响应输入重定向
对于输入重定向,一般刚刚学会都会想使用echo 来输出文件重定向来的内容,但是执行完毕却没有输出类似的问题
1 | echo < file.txt |
原因在于 file.txt 的内容被重定向到了 stdin,但是echo指令并不会从 stdin 读取任何内容,所以无法输出文件的内容
所以说一个指令是否能否使用输入重定向,决定于它是否从stdin读取内容
一些教程中需要高亮的基础知识
文件描述符
一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件:
- 标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。
- 标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。
- 标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。
所以说如果使用了数字代替字符串,代表三个标准文件,例如将错误追加输出到file
1 | command 2 >> file.txt |
Here Document
Here Document 是 Shell 中的一种特殊的重定向方式,用来将输入重定向到一个交互式 Shell 脚本或程序
个人的理解,是用stdin 模拟一个基于运行时的文件,所以叫 Here Document
1 | command << delimiter |
一般来讲 delimiter 使用 EOF
1 | cat << EOF |
值得注意的两点
- 结尾的delimiter 一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和 tab 缩进
- 开始的delimiter前后的空格会被忽略掉
>& 和 &>
这里的&没有固定的意思
放在>后面的&,表示重定向的目标不是一个文件,而是一个文件描述符,
换言之 2>1 代表将stderr重定向到当前路径下文件名为1的regular file中
而2>&1代表将stderr重定向到文件描述符为1的文件
1 | $ command > file 2>&1 |
顺序问题
1 | find /etc -name .bashrc > list 2>&1 |
- 先将要输出到stdout的内容重定向到文件,此时文件list就是这个程序的stdout,再将stderr重定向到stdout,也就是文件list
- 先将要输出到stderr的内容重定向到stdout,此时会产生一个stdout的拷贝,作为程序的stderr,而程序原本要输出到stdout的内容,依然是对接在stdout原身上的,因此第二步重定向stdout,对stdout的拷贝不产生任何影响