bash echo 在命令行本身(而不是在脚本中)执行的命令行

bash echo 在命令行本身(而不是在脚本中)执行的命令行

出于文档目的,我的意思是从我执行的命令重定向到文件 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.shsource
../dirstderr

方法一:效果很好,除了两个问题:

  • 它不理解别名(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

您可以使用xtraceshell 将其正在执行的命令打印到 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

相关内容