1

Consider the following bash constructs:

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

In this case, list-redir.txt and list-tee.txt will be identical, and will contain the listing of files as expected; e.g.

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

My question is - how could I write such a command, and have the command line text inserted as the first thing in the standard output - such that the file eventually starts with the command line as first? As an example, the file list-redir.txt would in that case look like:

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

... which also implies that the character # can be prepended to the inserted command line.

Is there anything that I could use for this - but with the minimum of change in typing out in respect to the original command lines (ls /usr/include/asm > list-redir.txt ...)?

2

A simple (and ugly) hack would be to add this to your ~/.bashrc:

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

You'd then run your command as

echorun ls /usr > list-redir.txt

That will not let you differentiate between ls /usr >foo and ls /usr | tee foo but it will append # ls /usr to the beginning of foo.

  • Many thanks @terdon - I'll be accepting this, as it looks like it minimizes the amount of typing; I didn't need to differentiate between redirection and piping, so it looks good. Cheers! – sdaau Jun 23 '14 at 17:15
2

You could just do this:

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

At least I think this is what you want done. This would yield results like:

 $ cat <./list-redir.txt

 ###OUTPUT###

   ls /usr/include/asm
 #output of above command#
   ...
  • Thanks for that @mikeserv - the other answer has also a note about a shorter usage on command line, so I accepted that one. Cheers! – sdaau Jun 23 '14 at 17:16
  • 1
    Cool by me, @sddau - it's a good answer. – mikeserv Jun 23 '14 at 17:18
0

You could also look at the script command which will record your terminal session including what you type and all the output. It can get a little messy though sometimes as it will record everything you type including any backspaces etc.

$ 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
0

Actually, just realized that the answer from @terdon may not work with a more complicated command pipeline; so I came up with the following alias (named er as short for @tendon's echorun):

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

The idea is, basically, that |er should be inserted before the last pipe or redirect in a command line; then, it is a lucky coincidence indeed, that at that point, history 1 exactly refers to the current command line! Thus, it can be echoed first, before the rest of (what is at that point) standard input, by cat. And so, we can now do things like:

$ 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

Thus we have full command line of multiple pipes - and we don't have to worry about escaping anything - basically, just add er to the last pipe. The only slight nag is the history number (it doesn't bother me that much, otherwise I'd add an additional awk in the alias).

  • @sddau - you could probably do this portably like alias er=' eval "$(fc -l 0)"' I think. – mikeserv Jul 14 '14 at 21:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.