上一节中 [[16-linux程序后台执行指西]],我们提到了,重定向操作,对于后台执行命令来说,很有用,这一节来详细说说。
部分内容参考:Linux 基础入门(新版) - 实验楼[1]
Linux 默认提供了三个特殊设备,用于终端的显示和输出,分别为stdin(标准输入,对应于你在终端的输入),stdout(标准输出,对应于终端的输出),stderr(标准错误输出,对应于终端的输出)。
文件描述符在形式上是一个非负整数。本质上是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。
当程序打开一个现有文件或者创建一个文件时,内核会向进程返回一个文件描述符。
默认情况下,使用终端的标准输入作为命令的输入和标准输出作为命令的输出。比如,标准输入(standard input)的文件描述符是 0,标准输出(standard output)是 1,标准错误(standard error)是 2。
我们可以将结果从屏幕重定向到某个文件。
我们可以分别处理,或直接用&
:
# 将标准错误重定向到标准输出,再将标准输出重定向到文件,注意要将重定向到文件写到前面
$ cat Documents/test.c hello.c >somefile 2>&1
# 或者只用bash提供的特殊的重定向符号"&"将标准错误和标准输出同时重定向到文件
$ cat Documents/test.c hello.c &>somefilehell
因为shell 中标准输出与标准错误不同,上面的文件描述符,二者对应的也并不相同,因此需要对它们分别处理。
❯ cat unname.txt > /dev/null
❯ cat 123 > /dev/null
cat: 123: No such file or directory
❯ cat 123 2>/dev/null
有时候,我们可能并不想覆盖文件的原有内容。则可以通过>>
进行追加数据:
$ who >> test6
$ cat test6
Thu Jun 11 12:23:05 CST 2020
mugpeng console Jun 2 13:36
mugpeng ttys000 Jun 6 10:21
输入重定向将文件的内容重定向到命令。command < inputfile
记忆方法:输入重定向与输出重定向符号相反。在命令行上,命令在左,文件在右,重定向符号指向数据流动的方向。
此外,还有一种内联输入重定向inline input redirection。该重定向无需对命令指定文件,但需要指定一个文本标记来划分输入数据的开始与结尾,使用内联输入重定向,shell 会使用次提示符来提示输入数据。符号为<<。注意开始和结尾都使用了一致的文本标记test。
$ wc << test
> I
> am
> happy.
> test
3 3 12
有的时候,我们可能希望脚本中的某些内容永久的重定向到某个文件中,比如操作的日志。这时候可以使用 exec 。
# 先开启一个子 Shell
$ zsh
# 使用exec替换当前进程的重定向,将标准输出重定向到一个文件
$ exec 1>somefile
# 后面你执行的命令的输出都将被重定向到文件中,直到你退出当前子shell,或取消exec的重定向
$ ls
$ exit
$ cat somefile
在 Shell 中有 9 个文件描述符。上面我们使用了也是它默认提供的 0,1,2 号文件描述符。另外我们还可以使用 3-8 的文件描述符,只是它们默认没有打开而已。
你可以使用下面命令查看当前 Shell 进程中打开的文件描述符:
$ ls -Al /dev/fd/
total 0
lrwx------ 1 yzpeng yzpeng 64 Apr 30 12:59 0 -> /dev/pts/0
lrwx------ 1 yzpeng yzpeng 64 Apr 30 12:59 1 -> /dev/pts/0
lrwx------ 1 yzpeng yzpeng 64 Apr 30 12:59 2 -> /dev/pts/0
lr-x------ 1 yzpeng yzpeng 64 Apr 30 12:59 3 -> /proc/70349/fd
ps:mac 与linux 下结果可能有所不同。
我们还可以创建自定义的新的文件描述符。
通过exec 还设定:
# 进入新的zsh
$ zsh
$ exec 4>somefile
# 先进入目录,再查看,否则你可能不能得到正确的结果,然后再回到上一次的目录
$ cd /dev/fd/;ls -Al;cd -
# 注意下面的命令>与&之间不应该有空格,如果有空格则会出错
$ echo "this is test" >&4
$ cat somefile
$ exit
如果需要永久设定,也可以添加到rc 文件中。
同样,你也可以通过exec,强制覆盖默认的文件描述符的指向。不过,并不推荐。
当我们设定的文件描述符不想使用时,还可以关闭它们:
$ exec 4>&-
$ cd /dev/fd;ls -Al;cd -
在上一节我们也说过,/dev/null 有时候很有用。
在 Linux 中有一个被称为“黑洞”的设备文件,所有导入它的数据都将被“吞噬”—— /dev/null 。它叫做空设备,是一个特殊的设备文件,它通常被用于丢弃不需要的输出流,或作为用于输入流的空文件,这些操作通常由重定向完成。读取它则会立即得到一个 EOF。
如果将标准输出重定向到这个“黑洞”,则就会完全得不到任何的输出结果了。
$ cat Documents/test.c 1>/dev/null 2>&1
如果我们想要将结果同时输出到屏幕与文件,我们可以使用tee命令:
echo 5 | tee test2.txt
cat test2.txt
5
不过需要注意的是,如果想要实现>>
追加的效果,需要使用参数 -a:
$ for i in {1..5}; do echo $i | tee -a test2.txt; done
1
2
3
4
5
$ cat test2.txt
1
2
3
4
5
另外,我们还可以将输出同时保存到多个文件,类似执行完输出重定向操作,又对生成的重定向输出文件做了一个cp 命令:
$ for i in {1..5}; do echo $i | tee -a test3.txt test33.txt; done
1
2
3
4
5
$ ls test3*
test3.txt test33.txt
[1]
Linux 基础入门(新版) - 实验楼: http://demo.erdangjiade.com/modals/8/856/demo/courses/show.html