1

一段代码使用 freopen 将 stdout 与 C 中的文件联系起来。在这段代码之后,将执行一个启动 shell 的脚本。现在的问题是所有 stdout 输出都进入该文件,因此在该 shell 中运行的任何命令都被放置在该文件中。

我已经找到了启动 shell 的脚本:

/bin/sh 1>&2 2>&1

虽然它打印到屏幕上,但我不确定如何验证它实际上是打印到 stdout 还是 stderr。有人可以验证我的 IO 重定向正确吗?

编辑:我无权访问调用 freopen 的程序,只有要运行的脚本。

4

1 回答 1

1

你的外壳片段:

  • 使标准输出 ( 1) 转到标准错误 ( 2) 当前所在的位置;和
  • 使标准错误 ( 2) 转到标准输出 ( 1) 当前所在的位置。

不需要第二次操作。

原始答案

更严重的是,如果调用这段代码时其标准错误会转到一个文件,那么 shell 的输出将转到同一个文件。如果你真的想让它和原始标准输出到同一个地方,你需要在重定向之前保留原始标准输出freopen()。你会这样做:

int fd1 = dup(FILENO_STDOUT);

...now do freopen...


dup2(fd1, FILENO_STDOUT);
close(fd1);

...now launch shell...without I/O redirection

修改后的答案

鉴于场景:

  • 登录 shell 用于运行程序 Program-A(您没有源代码,并且freopen()在标准输出中使用)
  • Program-A 运行 Program-B(这是一个最终启动交互式 shell 的 shell 脚本,使用/bin/sh 1>&2 2>&1符号)

并且假设您希望交互式 shell 的标准输出转到原始标准输出,那么您可以使用以下代码执行此操作:

launch.sh

运行带有额外 I/O 重定向和环境变量集的 Program-A:

set -x
fd -n 32
exec 3>&1
echo "$0: $@"
fd -n 32
FD_COPY_STDIN=3 exec ./Program-A "$@"

fd程序打印o打开的-文件描述符和关闭的文件描述符。指定“前 32 个文件描述符的-n 32打印状态”(默认情况下,它会打印所有可能的文件描述符,但由 64 个破折号组成的数百行读起来非常无聊)。

程序-A

模拟您的不可修改程序的 Shell 脚本。它在将标准输出更改为文件 ( standard.output) 后运行 Program-B。

set -x
echo "$0: $@"
# Simulate freopen("./standard.output", "w", stdout);
exec 1> ./standard.output
echo "$0: $@"
fd -n 32
exec ./Program-B "$@"

(如果您愿意,可以删除最后一个exec,然后在Program-B退出后回显某些内容。)

程序-B

这是您修改后的脚本 - 运行的程序Program-A

echo "$0: $@"
fd -n 32

exec 1>&${FD_COPY_STDOUT:-3}
exec 3>&- 2>&1
echo "$0: $@"
fd -n 32
exec ${SHELL} -i

(同样,可以删除最终exec版本,然后在脚本中执行其他操作。)

-i选项调用交互式外壳。将2>&1标准错误重定向到标准输出所在的位置。交互式 shell 提示标准错误(正如我再次发现困难的方式 - 尽管我之前遇到过这种行为)。

示例运行

isodate命令等效于date +'%Y-%m-%d %H:%M:%S'. 我在机器上的标准提示osirisOsiris JL:.

没有标准错误重定向到文件:

Osiris JL: ls
launch.sh  Program-A  Program-B
Osiris JL: bash launch.sh $(isodate)
+ fd -n 32
ooo-----------------------------
+ exec
+ echo 'launch.sh: 2014-05-20' 17:03:59
launch.sh: 2014-05-20 17:03:59
+ fd -n 32
oooo----------------------------
+ FD_COPY_STDIN=3
+ exec ./Program-A 2014-05-20 17:03:59
+ echo '/home/jleffler/soq/New/Program-A: 2014-05-20' 17:03:59
/home/jleffler/soq/New/Program-A: 2014-05-20 17:03:59
+ exec
+ echo '/home/jleffler/soq/New/Program-A: 2014-05-20' 17:03:59
+ fd -n 32
+ exec ./Program-B 2014-05-20 17:03:59
/home/jleffler/soq/New/Program-B: 2014-05-20 17:03:59
ooo-----------------------------
jleffler@osiris:~/soq/New$ ls -l
total 16
-rwxr----- 1 jleffler eng 100 May 20 17:02 launch.sh
-rwxr----- 1 jleffler eng 158 May 20 17:02 Program-A
-rwxr----- 1 jleffler eng 121 May 20 17:02 Program-B
-rw-r----- 1 jleffler eng 208 May 20 17:03 standard.output
jleffler@osiris:~/soq/New$ exit
exit
Osiris JL:

将标准错误重定向到文件:

Osiris JL: bash launch.sh $(isodate) 2>standard.error
ooo-----------------------------
launch.sh: 2014-05-20 17:05:11
oooo----------------------------
/home/jleffler/soq/New/Program-A: 2014-05-20 17:05:11
/home/jleffler/soq/New/Program-B: 2014-05-20 17:05:11
ooo-----------------------------
jleffler@osiris:~/soq/New$ ls -l
total 20
-rwxr----- 1 jleffler eng 100 May 20 17:02 launch.sh
-rwxr----- 1 jleffler eng 158 May 20 17:02 Program-A
-rwxr----- 1 jleffler eng 121 May 20 17:02 Program-B
-rw-r----- 1 jleffler eng 343 May 20 17:05 standard.error
-rw-r----- 1 jleffler eng 208 May 20 17:05 standard.output
jleffler@osiris:~/soq/New$ exit
exit
Osiris JL: cat standard.error
+ fd -n 32
+ exec
+ echo 'launch.sh: 2014-05-20' 17:05:11
+ fd -n 32
+ FD_COPY_STDIN=3
+ exec ./Program-A 2014-05-20 17:05:11
+ echo '/home/jleffler/soq/New/Program-A: 2014-05-20' 17:05:11
+ exec
+ echo '/home/jleffler/soq/New/Program-A: 2014-05-20' 17:05:11
+ fd -n 32
+ exec ./Program-B 2014-05-20 17:05:11
Osiris JL: cat standard.output
/home/jleffler/soq/New/Program-A: 2014-05-20 17:05:11
oooo----------------------------
/home/jleffler/soq/New/Program-B: 2014-05-20 17:05:11
oooo----------------------------
Osiris JL: 
于 2014-05-20T22:57:21.203 回答