使用终端输出的内容命名文件

Tri*_*ran 1 command-line

这个线程在这里讨论了如何输出终端内容到一个文件中。特别是,与此:

command |& tee output.txt
Run Code Online (Sandbox Code Playgroud)

问题:是否可以利用部分输出内容来命名文件。例如,假设内容逐行打印如下:

action_1_last_time_2021_06_15_21_34_56
action_2_last_time_2021_06_15_21_35_23
action_3_last_time_2021_06_15_21_43_45
...
action_320032_last_time_2021_06_15_23_59_14
Run Code Online (Sandbox Code Playgroud)

是否可以使用最后一行的内容来命名文件,而不是out.txt在命令行上?也许是某种变量?在这里,最后一行被假定定义为在文件关闭之前出现的行(并且命令完成运行)。

ste*_*ver 5

无论您如何解决这个问题,您都必须缓冲命令输出,直到您可以读取最后一行,以便知道将它写在哪里。

我能想到的唯一明智的方法是使用临时文件,然后重命名它:

tmpfile=$(mktemp)
outfile=$(command | tee "$tmpfile" | tail -n 1)
mv "$tmpfile" "$outfile"
Run Code Online (Sandbox Code Playgroud)

如果您真的想同时捕获 stdout 和 stderr,您可以更改||&- 但请注意,这可能会导致在错误消息后命名输出文件(尽管可能有一种方法可以使用聪明的文件描述符 fu 来避免这种情况)。

可以使用sponge命令(来自 package moreutils)实现替代解决方案,但这可能在幕后使用相同的技术。事实上,手册页说

   When possible, sponge creates or updates the output file atomically by
   renaming a temp file into place.
Run Code Online (Sandbox Code Playgroud)

另一种选择可能是使用rev反转行,以便您可以先读取最后一行,然后rev再次恢复输出顺序。然而,这涉及两次缓冲整个输出。