15

I used to work for a company who had a customised shell for management of one of their products that was running on Linux and I'm looking to replicate a key feature of this shell.

All the work was done by a background process and the output from the log displayed to all connected users.

The log would tail in the background to your shell, and the prompt line would always stay perfectly at the bottom.

For e.g.

Log line 1
Log line 2
Log line 3
![ROOT@PRODUCT51-LIVE]:~/ #

The way I tried to do this with bash was to start a detached tail in the users .bashrc file, but when the output from the command is sent to stdout - it comes in under the bash prompt, e.g.

![ROOT@PRODUCT51-LIVE]:~/ #Log line 1
Log line 2
Log line 3

And the user would have to press enter or CtrlC for a clean prompt line.

I'm out of ideas on how to make the prompt always jump to the bottom of the output and I think I'm using the wrong terminology to find anything on Google as I'm having no luck - does anyone know how to do this with bash?

Flup
  • 7,688
  • 1
  • 31
  • 43
iamacarpet
  • 310
  • 2
  • 12
  • 1
    You want the output update instantly or when you get a new prompt? – ahilsend Aug 06 '13 at 10:54
  • Instantly, so it's as identical as possible to just running "tail -f", but with the prompt at the bottom. – iamacarpet Aug 06 '13 at 10:56
  • What happens to the `tail -f` output and the prompt and the command output when you enter a command that has a significant amount of output, especially when your background process is actively sending its output? – Dennis Williamson Aug 06 '13 at 20:10
  • In their case, the commands that would run only caused output via the background process, not on their own, so it wasn't an issue. In this case, once we get a solution that gives the desired effect, I think it'd be a case of playing and seeing how bad the output getting mixed would be on an implementation-to-implementation basis. – iamacarpet Aug 07 '13 at 10:38
  • 1
    Then I strongly support the suggestion of using screen or tmux. The output won't get mixed or fight for screen space and you can resize the windows (move the split) and scroll them independently. If your objection is to the header/footer/status lines being to "heavy", there's some ability to configure that. No wheels reinvented. – Dennis Williamson Aug 07 '13 at 15:08

2 Answers2

11

The answer is screen or tmux is been used

I will explain how you could configure such using screen

1) Install screen using either apt-get install screen on Ubuntu/Debian or yum install screen RedHat derivates.

2) screen -S shell_and_logs

3) Then press Ctrl+a, followed by S (capital S).
A horizontal screen will appear

4) Press Ctrl+a followed by TAB
This will jump to the second split window.

5) Create another window in here so you get the command prompt by pressing Ctrl+a release the keys then press c

6) You can resize the second windo by pressing Ctrl+a then typing :resize after which Lines: will appear. Enter the number of lines you want to show.

7) Finally you can switch between windows by Ctrl+a followed by TAB

See example below

voretaq7
  • 79,345
  • 17
  • 128
  • 213
Valentin Bajrami
  • 3,870
  • 1
  • 17
  • 25
  • Thanks val0x00ff - I like the idea, it gets the job done - but it doesn't look as clean as the experience the system in question provided. To an inexperienced user, it's not as transparent - it's obviously another shell, rather than just feeling like your main shell is keeping you updated. – iamacarpet Aug 06 '13 at 12:32
  • @iamacarpet The `tail -F /var/log/messages &` is another way of showing you messages when something changes for example when a login failure is discovered or when some service has issues. This is however not ideal since it will mess your interactive shell. – Valentin Bajrami Aug 06 '13 at 12:40
  • Yes that's exactly what I was asking - a way to do just that without messing up the interactive shell - as that's what they'd managed to do on the companies shell - but it'd be nice to not have to write a shell from scratch to accomplish it. – iamacarpet Aug 06 '13 at 15:37
  • 1
    @iamacarpet There are a bunch of other tools besides `screen` and `tmux` that can do this -- for example some of the BSDs ship with a `window` command. Given the choice though I would recommend this solution over either a custom shell or the other options available because of its flexibility. It may not be as transparent to the end user, but they really won't know the difference, and power users/sysadmins will be able to use the extra flexibility offered by `screen`. – voretaq7 Aug 06 '13 at 18:06
  • @iamacarpet `t=$(mktemp); printf '%s\n' 'screen tail -F /var/log/messages' split focus screen > "$t"; screen -S screenname -c "$t"` Put it in a script and run it each time you want. Thanks to geirha for this at #bash @ irc.freenode.org – Valentin Bajrami Aug 06 '13 at 18:15
1

The following does what you need, without using tmux or screen or other programs. Keeps the prompt at the bottom. Replace "/var/log/cron" with whatever file you need:

#!/bin/bash 
L=$(tput lines)
L1=${L}
(( L1-- ))
C=$(tput cols)
tput cup ${L} 0
tail -f /var/log/cron | while read line; do 
  tput sc
  printf "\e[1;${L1}r\e[${L1};${C}f" 
  echo; echo ${line}
  printf "\e[1;${L}r" && tput rc
done

the key to this are the ANSI control characters for the terminal. Particularly the "\e[x;y" statement which sets a new scrollable area. So, as each line of the log file is read, the bottom line in the window is excluded from the scrollable area, the line from the log file is inserted, then the bottom is added back in.

Michael Martinez
  • 2,543
  • 3
  • 20
  • 31
  • Thanks Michael, that works **beautifully** =] - I do have the occasional problem of it you're typing while there is a lot of log line scrolling by, you can't backspace all of the text on your console line (I was testing with a busy apache log), but for what I want to use it for, it shouldn't be a problem. – iamacarpet Sep 24 '13 at 12:24
  • @iamacarpet Awesome. Glad it works for you. – Michael Martinez Sep 24 '13 at 16:20