出于文档目的,我的意思是从我执行的命令重定向到文件 stdout 和 stderr。例如,我会运行(我的命令比别名不那么简单,ll
但可能并不重要):
$ ll > out-err.dat 2>&1
$ cat out-err.dat
drwxr-xr-x 39 us00001 us00001 4096 jul 31 14:57 ./
drwxr-xr-x 3 root root 4096 feb 2 06:06 ../
-rw------- 1 us00001 us00001 62226 jul 31 11:56 .bash_history
...
另外出于文档目的,我想将我使用的命令行存储在同一个输出文件中。预期的行为和输出是
$ [NEW COMMAND LINE]?
$ cat out-err.dat
[NEW COMMAND LINE] <- This first line would contain the command line used
drwxr-xr-x 39 us00001 us00001 4096 jul 31 14:57 ./
drwxr-xr-x 3 root root 4096 feb 2 06:06 ../
-rw------- 1 us00001 us00001 62226 jul 31 11:56 .bash_history
...
如何才能做到这一点? 我知道我可以编写一个 bash 脚本并执行它,因此该命令将单独记录。我可以进一步编写一个脚本来将命令行回显到文件,然后通过重定向到同一文件来执行它。我正在寻找一种可能的无脚本解决方案。
编辑:反馈一个很好的答案。这不适合作为评论。
我用命令测试了echo_command ll echo_command.sh ../dir > out-err.dat 2>&1
。 我的
Script包含函数的定义。 是一个不存在的目录,强制某些输出到.echo_command.sh
source
../dir
stderr
方法一:效果很好,除了两个问题:
它不理解别名(
ll
在本例中;用它替换时ls
有效)。它不记录重定向部分。
方法二: 效果不太好。现在重定向部分也被打印,但是命令行被打印到屏幕而不是重定向到文件。
编辑:对发布的有关实用程序的评论的反馈script
。它的用途非常广泛,对于scriptreplay
.
script
可以单独调用,这会生成一个交互式 shell(它不会保留父 shell 的最近历史记录),
也可以称为script -c <command> <logfile>
.最后一种形式与 OP 的目标相对应,但它不会将命令本身存储到日志文件中。它产生(至少在基本情况下)与 相同的输出<command> > <logfile> 2>&1
。
所以看来这在这里没有用。
答案1
你可以使用这样的函数:
echo_command() { printf '%s\n' "${*}"; "${@}"; }
例子:
$ echo_command echo foo bar baz
echo foo bar baz
foo bar baz
$ echo_command uname
uname
Linux
正如蒂姆·肯尼迪所说,还有一个非常有用的script
命令:
$ script session.log
Script started, file is session.log
$ echo foo
foo
$ echo bar
bar
$ echo baz
baz
$ exit
exit
Script done, file is session.log
$ cat session.log
Script started on 2018-07-31 16:30:31-0500
$ echo foo
foo
$ echo bar
bar
$ echo baz
baz
$ exit
exit
Script done on 2018-07-31 16:30:43-0500
更新
如果您还需要记录重定向和基本上每个 shell 语法(请注意,我添加了一条小Command line:
消息以轻松识别正在执行的命令):
echo_command() {
local arg
for arg; do
printf 'Command line: %s\n' "${arg}"
eval "${arg}"
done
}
请记住,您应该非常小心地引用所eval
使用的内容:
$ echo_command 'echo foo > "file 2"; cat "file 2"'
Command line: echo foo > "file 2"; cat "file 2"
foo
它还可以同时接受多个命令,而不是只接受一个命令:
$ echo_command 'echo foo' 'echo bar' 'echo baz'
Command line: echo foo
foo
Command line: echo bar
bar
Command line: echo baz
baz
答案2
您可以使用xtrace
shell 将其正在执行的命令打印到 stdout 的机制:
(set -x; ls -l) > out-err.dat 2>&1
$PS4
如果您不喜欢它,请将其默认值(在大多数 shell 中)更改"+ "
为其他任何值(如果您不需要前缀,请将其留空)。
作为一个函数:
log_into() ( # args: output-file command args
exec > "$1" 2>&1
shift
PS4='Running: '
set -o xtrace
"$@"
)
log_into out-err.dat ls -l