网站建设的新发展,佛山专业网站制作公司,动漫制作专业的初始岗位,重庆定制型网站建设相关阅读Linuxhttps://blog.csdn.net/weixin_45791458/category_12234591.html?spm1001.2014.3001.5482 本文将讨论Linux中的重定向相关问题#xff0c;在阅读本文前#xff0c;强烈建议先学习文件描述符的相关内容Linux#xff1a;文件描述符详解。 重定向分为两类#x…相关阅读Linuxhttps://blog.csdn.net/weixin_45791458/category_12234591.html?spm1001.2014.3001.5482 本文将讨论Linux中的重定向相关问题在阅读本文前强烈建议先学习文件描述符的相关内容Linux文件描述符详解。 重定向分为两类第一类是全局重定向它对后续在Bash中创建的所有子进程都生效因为文件描述符的继承第二类是命令重定向它只对单个命令生效。
全局重定向
输入重定向
exec [number|varname] filename
# 如果不使用exec则无法影响当前Bash进程
# [number|varname]和之间不能有空格 输入重定向会首先将文件名进行拓展如参数扩展和命令替换如果使用number会在文件描述符number上以读模式打开该文件实际上系统调用open打开一个文件返回的文件描述符是最小可用的整数值这是不能直接控制的但可以用系统调用dup、dup2或fcntl进行复制如果使用varname则会自动分配一个大于等于10的文件描述符并将其赋值给变量varname如果未指定number或varname则默认为标准输入文件描述符0。 例1展示了指定数字分配文件描述符和自动分配文件描述符的过程。
例1
[zhangchenEDA Desktop]$ psPID TTY TIME CMD34005 pts/0 00:00:00 bash34070 pts/0 00:00:00 ps
[zhangchenEDA Desktop]$ ls -al /proc/34005/fd # 查询bash进程的文件描述符
total 0
dr-x------. 2 zhangchen zhangchen 0 Sep 24 14:08 .
dr-xr-xr-x. 9 zhangchen zhangchen 0 Sep 24 14:08 ..
lrwx------. 1 zhangchen zhangchen 64 Sep 24 14:08 0 - /dev/pts/0
lrwx------. 1 zhangchen zhangchen 64 Sep 24 14:08 1 - /dev/pts/0
lrwx------. 1 zhangchen zhangchen 64 Sep 24 14:08 2 - /dev/pts/0
lrwx------. 1 zhangchen zhangchen 64 Sep 24 14:09 255 - /dev/pts/0
[zhangchenEDA Desktop]$ exec 5 test1 # 指定数字分配文件描述符
[zhangchenEDA Desktop]$ ls -al /proc/34005/fd
total 0
dr-x------. 2 zhangchen zhangchen 0 Sep 24 14:08 .
dr-xr-xr-x. 9 zhangchen zhangchen 0 Sep 24 14:08 ..
lrwx------. 1 zhangchen zhangchen 64 Sep 24 14:08 0 - /dev/pts/0
lrwx------. 1 zhangchen zhangchen 64 Sep 24 14:08 1 - /dev/pts/0
lrwx------. 1 zhangchen zhangchen 64 Sep 24 14:08 2 - /dev/pts/0
lrwx------. 1 zhangchen zhangchen 64 Sep 24 14:09 255 - /dev/pts/0
l-wx------. 1 zhangchen zhangchen 64 Sep 24 14:08 5 - /home/zhangchen/Desktop/test1
[zhangchenEDA Desktop]$ exec {fd} test2 # 自动分配文件描述符
[zhangchenEDA Desktop]$ echo $fd
10
[zhangchenEDA Desktop]$ ls -al /proc/34005/fd
total 0
dr-x------. 2 zhangchen zhangchen 0 Sep 24 14:08 .
dr-xr-xr-x. 9 zhangchen zhangchen 0 Sep 24 14:08 ..
lrwx------. 1 zhangchen zhangchen 64 Sep 24 14:08 0 - /dev/pts/0
lrwx------. 1 zhangchen zhangchen 64 Sep 24 14:08 1 - /dev/pts/0
l-wx------. 1 zhangchen zhangchen 64 Sep 24 14:08 10 - /home/zhangchen/Desktop/test2
lrwx------. 1 zhangchen zhangchen 64 Sep 24 14:08 2 - /dev/pts/0
lrwx------. 1 zhangchen zhangchen 64 Sep 24 14:09 255 - /dev/pts/0
l-wx------. 1 zhangchen zhangchen 64 Sep 24 14:08 5 - /home/zhangchen/Desktop/test1 例2展示了输入重定向过程中的系统调用由于strace无法直接在交互式bash中追踪内建命令exec我们选择编写一个测试脚本。
# 例2
# 文件redirection.sh
exec 5 test1
exec {fd} test2[zhangchenEDA Desktop]$ strace bash redirection.sh
*****
open(test1, O_RDONLY) 3
fcntl(5, F_GETFD) -1 EBADF (Bad file descriptor)
dup2(3, 5) 5
close(3) 0
rt_sigprocmask(SIG_BLOCK, NULL, [], 8) 0
open(test2, O_RDONLY) 3
fcntl(3, F_DUPFD, 10) 10
close(3)
***** 可以看出在系统调用open打开文件test1和test2时返回的文件描述符都是其实3但是系统调用dup2(3, 5)和fcntl(3, F_DUPFD, 10)将其复制为了文件描述符5和10。系统调用open的参数O_RDONLY表示以只读模式打开。 如果在交互式bash中将标准输入重定向为了其他文件则终端会直接退出如例3所示。
# 例3
[zhangchenEDA Desktop]$ exec 0 test # 终端会直接退出
[zhangchenEDA Desktop]$ exec 0 test; sleep 5 # 终端会在等待5秒后退出 下面的命令可以关闭已打开的文件描述符如例4所示。
exec [number|varname] -
exec [number|varname] -
# 两种命令效果是一样的并不区分输入还是输出
# 它们唯一的区别在于不指定number或varname时
# -默认指的是关闭标准输入描述符即0--默认指的是关闭标准输出描述符即1-
# [number|varname]和、和之间不能有空格和-间可以有
# 例4
[zhangchenEDA Desktop]$ exec 5 - # 关闭文件描述符5
[zhangchenEDA Desktop]$ exec {fd} - # fd的值为10因此关闭文件描述符10输出重定向
exec [number|varname][|] filename
# 如果不使用exec则无法影响当前Bash进程
# [number|varname]和h和[|]之间不能有空格 输出重定向会首先将文件名进行拓展如参数扩展和命令替换如果使用number会在文件描述符number上以写模式打开该文件如果文件不存在则会创建它如果使用varname则会自动分配一个大于等于10的文件描述符并将其数字赋值给变量varname如果未指定number或varname则默认为标准输出文件描述符1。 如果重定向操作符是并且启用了noclobber选项通过命令set -o noclobber启用则如果目标文件已经存在且是常规文件则重定向会失败。 如果重定向操作符是|或者使用但未启用noclobber选项则如果目标文件已经存在会将其截断为零字节。 例5展示了输出重定向过程中的系统调用由于strace无法直接在交互式bash中追踪内建命令exec我们选择编写一个测试脚本。
# 例5
# 文件redirection.sh
set -o noclobber
exec 5 test1 # 重定向失败
exec {fd}| test2[zhangchenEDA Desktop]$ strace bash redirection.sh
*****
write(2, redirection.sh: line 2: test1: c..., 62redirection.sh: line 2: test1: cannot overwrite existing file
) 62
open(test2, O_WRONLY|O_CREAT|O_TRUNC, 0666) 3
fcntl(3, F_DUPFD, 10) 10
close(3)
***** 系统调用open的参数O_WDONLY表示以只写模式打开参数O_CREAT表示如果文件不存在则创建它参数O_TRUNC表示如果文件已存在则将其内容截断为零字节。 例6展示了输出重定向后后续命令的输出都不出现在终端。
# 例6
[zhangchenEDA Desktop]$ exec test1 # 标准输出文件描述符1重定向到文件test1
[zhangchenEDA Desktop]$ echo 123456789 # 向标准输出文件描述符1输出文本
[zhangchenEDA Desktop]$ exec - # 关闭标准输出文件描述符1
[zhangchenEDA Desktop]$ cat test1 # 向标准输出文件描述符1输出文本
cat: standard output: Bad file descriptor # 标准输出文件描述符1已被关闭
[zhangchenEDA Desktop]$ exec /dev/pts/0 # 重新让标准输出文件描述符1指向终端
[zhangchenEDA Desktop]$ cat test1 # 向标准输出文件描述符1输出文本
123456789 # 成功输出文本 例6中还存在一个插曲当将标准输出重定向到test1并写入文本12345678后使用exec -关闭文件描述符此时如果尝试使用cat输出test1文件的内容会报错这是因为此时标准输出即文件描述符0并未指向有效的终端因此需要将标准输出重定向回终端此时才能正常显示。 输出追加重定向
exec [number|varname] filename
# 如果不使用exec则无法影响当前Bash进程
# [number|varname]和之间不能有空格 与输出重定向类似不同的是如果文件已经存在则新的输出将附加到文件末尾而不会清空原有内容。 例7展示了输出追加重定向过程中的系统调用由于strace无法直接在交互式bash中追踪内建命令exec我们选择编写一个测试脚本。
# 例7
# 文件redirection.sh
exec 5 test1[zhangchenEDA Desktop]$ strace bash redirection.sh
*****
open(test1, O_WRONLY|O_CREAT|O_APPEND, 0666) 3
fcntl(5, F_GETFD) -1 EBADF (Bad file descriptor)
dup2(3, 5) 5
close(3) 0
rt_sigprocmask(SIG_BLOCK, NULL, [], 8) 0
***** 系统调用open的参数O_WDONLY表示以只写模式打开参数O_CREAT表示如果文件不存在则创建它参数O_APPEND表示在写入数据时所有数据都会追加到文件的末尾而不是从文件开头开始写入。 例8展示了输出追加重定向后输出的内容是追加到文件末尾的。
# 例8
[zhangchenEDA Desktop]$ cat test1
123456789
[zhangchenEDA Desktop]$ exec test1 # 标准输出文件描述符1重定向到文件test1
[zhangchenEDA Desktop]$ echo 123456789 # 向标准输出文件描述符1输出文本
[zhangchenEDA Desktop]$ exec - # 关闭标准输出文件描述符1
[zhangchenEDA Desktop]$ exec /dev/pts/0 # 重新让标准输出文件描述符1指向终端
[zhangchenEDA Desktop]$ cat test1 # 向标准输出文件描述符1输出文本
123456789 # 追加输出
123456789 标准输出和标准错误重定向
exec filename # 更好的格式
exec filename
# 如果不使用exec则无法影响当前Bash进程
# 和之间不能有空格 标准输出和标准错误重定向会首先将文件名进行拓展如参数扩展和命令替换然后将标准输出文件描述符1和标准错误输出文件描述符2都重定向到同一个文件。 需要注意的是使用时文件不能扩展为number或-如果是则会被当作是复制文件描述符见后这是为了兼容性考虑。 例9展示了标准输出和标准错误重定向过程中的系统调用由于strace无法直接在交互式bash中追踪内建命令exec我们选择编写一个测试脚本。
# 例9
# 文件redirection.sh
exec test1[zhangchenEDA Desktop]$ strace bash redirection.sh
*****
open(test1, O_WRONLY|O_CREAT|O_TRUNC, 0666) 3
dup2(3, 1) 1
close(3) 0
dup2(1, 2) 2
***** 在系统调用open打开文件test1时返回的文件描述符是3而dup2(3, 1)将其复制为了文件描述符1进一步dup2(1, 2)将文件描述符1复制为了文件描述符2此时文件描述符1和2都指向test1文件。 例10展示了标准输出和标准错误重定向后后续命令的输出不出现在终端。
# 例10
# 文件redirection.sh
exec test1
echo This is standard output # 标准输出
ls non_existent_file # 这将导致错误产生标准错误
echo This will also be standard output # 另一个标准输出[zhangchenEDA Desktop]$ bash redirection.sh
[zhangchenEDA Desktop]$ cat test
This is standard output
ls: cannot access non_existent_file: No such file or directory
This will also be standard output 标准输出和标准错误追加重定向
exec filename
# 如果不使用exec则无法影响当前Bash进程
# 和之间不能有空格 与标准输出和标准错误重定向类似不同的是如果文件已经存在则新的输出将附加到文件末尾而不会清空原有内容。 例11展示了标准输出和标准错误追加重定向过程中的系统调用由于strace无法直接在交互式bash中追踪内建命令exec我们选择编写一个测试脚本。
# 例11
# 文件redirection.sh
exec test1[zhangchenEDA Desktop]$ strace bash redirection.sh
*****
open(test1, O_WRONLY|O_CREAT|O_APPEND, 0666) 3
dup2(3, 1) 1
close(3) 0
dup2(1, 2) 2
***** 在系统调用open打开文件test1时返回的文件描述符是3而dup2(3, 1)将其复制为了文件描述符1进一步dup2(1, 2)将文件描述符1复制为了文件描述符2此时文件描述符1和2都指向test1文件。 例12展示了标准输出和标准错误追加重定向后输出的内容是追加到文件末尾的。
# 例12
# 文件redirection.sh
exec test1
echo This is standard output # 标准输出
ls non_existent_file # 这将导致错误产生标准错误
echo This will also be standard output # 另一个标准输出[zhangchenEDA Desktop]$ cat test
12345678
[zhangchenEDA Desktop]$ bash redirection.sh
[zhangchenEDA Desktop]$ cat test
12345678
This is standard output
ls: cannot access non_existent_file: No such file or directory
This will also be standard output 复制文件标识符
exec [number|varname] filename
exec [number|varname] filename
# 两种命令效果是一样的并不区分输入还是输出但建议与被复制关闭的文件描述符方向一致
# 它们唯一的区别在于不指定number或varname时
# filename默认指的是被复制关闭的标准输入描述符即0 filename filename默认指的是被复制关闭的标准输出描述符即1 filename
# [number|varname]和、和之间不能有空格
如果filename展开为数字则其表示要被复制的文件描述符那么文件描述符number指定或varname自动分配将成为该文件描述符的副本即指向同一个文件。如果filename展开为-则其表示要关闭文件描述符。如果filename展开文件名则其表示标准输出和标准错误重定向。其他情况下会出现错误。 例13展示了复制文件标识符过程中的系统调用由于strace无法直接在交互式bash中追踪内建命令exec我们选择编写一个测试脚本。
# 例13
# 文件redirection.sh
exec 3 test1
exec 4 3[zhangchenEDA Desktop]$ strace bash redirection.sh
*****
open(test1, O_WRONLY|O_CREAT|O_TRUNC, 0666) 3
rt_sigprocmask(SIG_BLOCK, NULL, [], 8) 0
fcntl(4, F_GETFD) -1 EBADF (Bad file descriptor)
dup2(3, 4) 4
***** 在系统调用open打开文件test1时返回的文件描述符是3此时不再需要系统调用dup2调整了因为这就是我们指定的数字而dup2(3, 4)将其复制为了文件描述符4此时文件描述符3和4都指向test1文件。 移动文件描述符
exec [number|varname] number-
exec [number|varname] number-
# 两种命令效果是一样的并不区分输入还是输出但建议与被移动的文件描述符方向一致
# 它们唯一的区别在于不指定number或varname时
# number-默认指的是移动到标准输入描述符即0 number- number-默认指的是标准输出描述符即1 number-
# [number|varname]和、和之间不能有空格number和-之间不能有空格与和number之间可以有空格 该命令将文件描述符number复制为文件描述符number指定或varname自动分配并在此后关闭文件描述符number。 例14展示了移动文件描述符过程中的系统调用由于strace无法直接在交互式bash中追踪内建命令exec我们选择编写一个测试脚本。
# 例14
# 文件redirection.sh
exec 3 test1
exec 4 3-[zhangchenEDA Desktop]$ strace bash redirection.sh
*****
open(test1, O_WRONLY|O_CREAT|O_TRUNC, 0666) 3
rt_sigprocmask(SIG_BLOCK, NULL, [], 8) 0
fcntl(4, F_GETFD) -1 EBADF (Bad file descriptor)
fcntl(4, F_GETFD) -1 EBADF (Bad file descriptor)
dup2(3, 4) 4
fcntl(3, F_GETFD) 0
close(3) 0
***** 可以看到在系统调用dup2将文件描述符3赋值为了文件描述符4后紧接着就是用系统调用close关闭了文件描述符3。 输入和输出重定向
exec [number|varname] filename
# 如果不使用exec则无法影响当前Bash进程
# [number|varname]和和之间不能有空格 以读写方式打开一个文件是用文件描述符number指定或varname自动分配如果未指定number或varname则默认为标准输入文件描述符0。 例15展示了移动文件描述符过程中的系统调用由于strace无法直接在交互式bash中追踪内建命令exec我们选择编写一个测试脚本。
# 例15
# 文件redirection.sh
exec 3 test1[zhangchenEDA Desktop]$ strace bash redirection.sh
*****
open(test1, O_RDWR|O_CREAT, 0666) 3
***** 系统调用open的参数O_RDWR表示以读写模式打开参数O_CREAT表示如果文件不存在则创建它。 叠加使用 上面的八种重定向命令可以多个混合使用此时从左往右依次执行如下所示。
exec filename 等价于 exec filename 2 1或exec filename 2 1不建议
exec filename 等价于 exec filename 2 1或exec filename 2 1不建议 命令重定向 全局重定向的影响范围很广所有后续的命令都会受到影响因为文件描述符继承但命令重定向只针对一条命令而言重定向只发生在子进程中其他都是相同的。 下面给了一个例子将echo命令的标准输出文件描述符1重定向至文件test1。
[zhangchenEDA Desktop]$ echo test_message test1
[zhangchenEDA Desktop]$ cat test1
test_message 下面展示了命令重定向过程中的系统调用情况。
# 文件redirection.sh
ls test1
echo 111111111111111111111
[zhangchenEDA Desktop]$ strace -f bash redirection.sh # -f选项很重要加上它才能追踪子进程的系统调用
*****
[pid 71192] open(test1, O_WRONLY|O_CREAT|O_TRUNC, 0666) 3
[pid 71192] dup2(3, 1) 1
[pid 71192] close(3) 0
[pid 71192] execve(/usr/bin/ls, [ls], 0x12f4bb0 /* 66 vars */) 0
*****
write(1, 111111111111111111111\n, 22111111111111111111111 # 后面一串是命令的输出
) 22
***** 可以看到系统调用open是在子进程[pid 71192]中进行的echo的输出使用原本的标准输出文件描述符1即还是原来的终端所以在后面看到了命令的输出。 细心的人可能会发现echo命令并没有创建子进程虽然echo命令不是内建命令但它是直接在原bash进程中执行的如果重定向它的标准输入输出岂不是会影响全局其实不会下面举例说明。
# 文件redirection.sh
echo 111111111111111111111 test1
echo 222222222222222222222[zhangchenEDA Desktop]$ strace -f bash redirection.sh # -f选项很重要加上它才能追踪子进程的系统调用
open(test1, O_WRONLY|O_CREAT|O_TRUNC, 0666) 3
fcntl(1, F_GETFD) 0
fcntl(1, F_DUPFD, 10) 10
fcntl(1, F_GETFD) 0
fcntl(10, F_SETFD, FD_CLOEXEC) 0
dup2(3, 1) 1
close(3) 0
fstat(1, {st_modeS_IFREG|0664, st_size0, ...}) 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) 0x7f6e4f095000
write(1, 111111111111111111111\n, 22) 22
dup2(10, 1) 1
fcntl(10, F_GETFD) 0x1 (flags FD_CLOEXEC)
close(10) 0
rt_sigprocmask(SIG_BLOCK, NULL, [], 8) 0
write(1, 222222222222222222222\n, 22222222222222222222222
) 22
***** 原来在使用dup2函数将标准输出文件描述符1指向test1前先使用了fcntl(1, F_DUPFD, 10)将文件描述符1原本指向的终端保存了下来第一个echo执行后又使用了dup2(10, 1) 将其还原