在 stdout 中的輸出之前插入命令列文字(用於管道/重定向)

在 stdout 中的輸出之前插入命令列文字(用於管道/重定向)

考慮以下bash結構:

ls /usr/include/asm > list-redir.txt
ls /usr/include/asm | tee list-tee.txt

在這種情況下,list-redir.txtlist-tee.txt是相同的,並且將包含預期的文件清單;例如

$ head -5 list-redir.txt
a.out.h
auxvec.h
bitsperlong.h
boot.h
bootparam.h [...]

我的問題是 - 我怎麼能編寫這樣的命令,並將命令列文字作為標準輸出中的第一件事插入 - 以便文件最終以命令行開頭?例如,list-redir.txt在這種情況下,該文件將如下所示:

$ head -5 list-redir.txt
# ls /usr/include/asm
a.out.h
auxvec.h
bitsperlong.h
boot.h [...]

....這也意味著字元 # 可以加入到插入的命令列前面。

有什麼我可以使用的東西 - 但在輸入原始命令行方面的變化最小(ls /usr/include/asm > list-redir.txt...)?

答案1

一個簡單(且醜陋)的技巧是將其添加到您的~/.bashrc

echorun(){
    echo "# $@";
    "$@"
}

然後你可以運行你的命令

echorun ls /usr > list-redir.txt

這不會讓您區分ls /usr >foo和 ,ls /usr | tee foo但它會附加# ls /usr到 的開頭foo

答案2

你可以這樣做:

{   cmd="ls /usr/include/asm"
    echo "$cmd" ; $cmd
} >./list-redir.txt

至少我認為這就是你想要做的。這會產生以下結果:

 $ cat <./list-redir.txt

 ###OUTPUT###

   ls /usr/include/asm
 #output of above command#
   ...

答案3

您也可以查看script將記錄您的終端機會話的命令,包括您鍵入的內容和所有輸出。但有時它可能會有點混亂,因為它會記錄您輸入的所有內容,包括任何退格鍵等。

$ script
Script started, file is typescript
$ ls /usr/include/asm
a.out.h          ioctl.h      mtrr.h             setup.h         termios.h
auxvec.h         ioctls.h     param.h            shmbuf.h        types.h
bitsperlong.h    ipcbuf.h     poll.h             sigcontext32.h  ucontext.h
boot.h           ist.h        posix_types_32.h   sigcontext.h    unistd_32.h
bootparam.h      kvm.h        posix_types_64.h   siginfo.h       unistd_64.h
byteorder.h      kvm_para.h   posix_types.h      signal.h        unistd.h
debugreg.h       ldt.h        prctl.h            socket.h        vm86.h
e820.h           mce.h        processor-flags.h  sockios.h       vsyscall.h
errno.h          mman.h       ptrace-abi.h       statfs.h
fcntl.h          msgbuf.h     ptrace.h           stat.h
hw_breakpoint.h  msr.h        resource.h         swab.h
hyperv.h         msr-index.h  sembuf.h           termbits.h
$ exit
exit
Script done, file is typescript
$ cat typescript
Script started on Sat 29 Aug 2015 10:32:52 AM EDT
$ ls /usr/include/asm
a.out.h          ioctl.h      mtrr.h             setup.h         termios.h
auxvec.h         ioctls.h     param.h            shmbuf.h        types.h
bitsperlong.h    ipcbuf.h     poll.h             sigcontext32.h  ucontext.h
boot.h           ist.h        posix_types_32.h   sigcontext.h    unistd_32.h
bootparam.h      kvm.h        posix_types_64.h   siginfo.h       unistd_64.h
byteorder.h      kvm_para.h   posix_types.h      signal.h        unistd.h
debugreg.h       ldt.h        prctl.h            socket.h        vm86.h
e820.h           mce.h        processor-flags.h  sockios.h       vsyscall.h
errno.h          mman.h       ptrace-abi.h       statfs.h
fcntl.h          msgbuf.h     ptrace.h           stat.h
hw_breakpoint.h  msr.h        resource.h         swab.h
hyperv.h         msr-index.h  sembuf.h           termbits.h
$ exit
exit

Script done on Sat 29 Aug 2015 10:33:00 AM EDT

答案4

實際上,剛剛意識到@terdon 的答案可能不適用於更複雜的命令管道;所以我想出了以下別名(命名er為 @tendon's 的縮寫echorun):

#alias er=' cat <(echo "# cmd: $(history 1)") - | tee' # last tee is not needed, so:
alias er=' cat <(echo "# cmd: $(history 1)") -'

基本上,這個想法|er應該插入到命令列中最後一個管道或重定向之前;那麼,這確實是一個幸運的巧合,在這一點上,history 1恰好指的是當前命令列!因此,它可以在標準輸入的其餘部分(當時的內容)之前首先通過 進行回顯cat。因此,我們現在可以執行以下操作:

$ ls /usr/include/asm | grep 'p*.h' | grep 'osix' |er | tee mylist.txt
# cmd:   125  ls /usr/include/asm | grep 'p*.h' | grep 'osix' |er | tee mylist.txt
posix_types_32.h
posix_types_64.h
posix_types.h
$ ls /usr/include/asm | grep 's*.h' | grep 'ig' |er >> mylist.txt
$ cat mylist.txt 
# cmd:   125  ls /usr/include/asm | grep 'p*.h' | grep 'osix' |er | tee mylist.txt
posix_types_32.h
posix_types_64.h
posix_types.h
# cmd:   126  ls /usr/include/asm | grep 's*.h' | grep 'ig' |er >> mylist.txt
sigcontext32.h
sigcontext.h
siginfo.h
signal.h

因此,我們擁有多個管道的完整命令行 - 而且我們不必擔心轉義任何內容 - 基本上,只需添加er到最後一個管道即可。唯一的小問題是歷史編號(它並沒有太困擾我,否則我會awk在別名中添加一個附加價值)。

相關內容