cat <<EOS | sed -ne '1{h;d;}' -e 'H;${G;p;}'
line 1
line 2
line 3
EOS
将其转换为所用内容的问题tail是tail需要读取整个文件以找到文件的结尾。要在您的管道中使用它,您需要
- 将文件的全部内容提供给
tail。
- 再次提供给
cat。
- 以该顺序。
棘手的一点是不复制文档的内容(tee执行此操作),而是在tail不使用中间临时文件的情况下使输出在文档的其余部分输出之前发生。
使用sed(或awk像John1024一样)通过将数据存储在内存中来消除数据的双重解析和排序问题。
sed我建议的解决方案是
1{h;d;},将第一行原样存储在保留空间中,然后跳到下一行。
H,请使用嵌入的换行符将其他各行附加到容纳空间。
${G;p;},将保留空间附加到带有嵌入式换行符的最后一行,并打印结果数据。
这完全是John1024解决方案的字面翻译sed,但需要注意的是POSIX标准仅保证保留空间至少为8192字节(8 KiB;但是建议根据需要动态分配和扩展此缓冲区,两者均由GNU sed和BSD sed正在执行)。
如果允许自己使用命名管道:
mkfifo mypipe
cat <<EOS | tee mypipe | cat <( tail -n 1 mypipe ) -
line 1
line 2
line 3
EOS
rm -f mypipe
这将使用tee发送数据下来mypipe,并在同一时间cat。该cat实用程序将首先读取来自输出tail(其从读取mypipe,其tee被写入),然后追加直接来自的文档的拷贝tee。
但是,这有一个严重的缺陷,即如果文档太大(大于管道的缓冲区大小),则在等待(未命名)管道为空时,将tee写入mypipe和cat阻塞。除非将其cat读取,否则不会清空。在完成cat之前不会从中读取tail。并且tail直到完成才tee完成。这是典型的僵局情况。
变化
tee >( tail -n 1 >mypipe ) | cat mypipe -
有同样的问题。