Dynamic Bash Script (i.e top) - linux

I'm wondering if there is a method to have a bash script present data to the console and consistently update it. Much like the functionality of top, but in a more simple form.

watch -n 1 <your-command>
From the watch(1) man page:
Execute a program periodically, showing output full screen

You need to use curses for this. Here's one detailed article about curses usage.

You can use "while true / clear"-loops to have constantly updated screen like:
#!/bin/bash
while true
do
clear
echo "your output"
uptime
sleep 5
done

You can use terminal escape codes. You can print them with echo -ne (drop the n if you want the newline afterwards). The escape character is \033. This will clear the screen and put your cursor at the top left:
echo -ne "\033[2J\033[f"
There are cursor-positioning codes, color codes, formatting, etc.

Related

Fish shell custom function for output text coloring

When using fish shell in a terminal-emulator (such as terminator) together with a command that outputs lots of text it could be useful to get some color coding on the output. I know that a script can add color code information to the output like "grep --color=auto". I guess it's possible to modify the fish terminal to scan through the output and add this in special places?
What I want to do is that the text "error" appearing in the output from any script always is marked red and that "warning" always is marked yellow. Anyone knows if this is possible by introducing function files in the ~/.config/fish/functions dir or similar?
This is basically a layering violation. Usually the output of external commands does not go back through the shell. It goes directly to the terminal.
Also, anything you do here has the potential to slow output down. (And because of fish issue #1396, this can be rather extreme).
That said, it's possible if you always pipe to a function like this
function colorstuff
while read -l input
switch $input
case "*error*"
set_color red
echo $input
case "*warning*"
set_color yellow
echo $input
case "*"
set_color normal
echo $input
end
end
set_color normal
end
Use it like somecommand | colorstuff. (And maybe add 2>&1 if you also wish to have stderr colored)
In my tests, this causes a noticeable slowdown, and even with that issue fixed it will still be slower since it has to match every single line.
Really, the real solution is for whatever tool you are using to color itself, since it knows what the output means. All this can do is look for keywords.
For general output colorization needs, I added the grc plugin to Tackle for precisely that purpose.

Save and restore terminal content

I am writing automation scripts (perl/bash). Many of them benefit from some basic terminal GUI. I figured I'd use standard ANSI sequences for basic drawing. Before drawing in terminal I do clear but doing that I lose some terminal command history. I want to be able to restore terminal command history when my program exists. Many terminal programs (e.g. less, man, vim, htop, nmon, whiptail, dialog etc) do exactly that. All of them restore terminal window bringing the user back to where he was prior to calling the program with all the history of commands previously executed.
To be honest I don't even know where to start searching. Is it a command from curses library? Is it an ANSI escape sequence? Should I mess with tty? I am stuck and any pointers would be really helpful.
EDIT: I'd like to clarify that I am not really asking "how to use the alternative screen". I am looking for a way to preserve terminal command history. One possible answer to my question could be "use alternative screen". The question "what is alternative screen and how to use it" is a different question which in turn already has answers posted elsewhere. Thanks :)
You should use the alternate screen terminal capability. See
Using the "alternate screen" in a bash script
An answer to "how to use the alternate screen":
This example should illustrate:
#!/bin/sh
: <<desc
Shows the top of /etc/passwd on the terminal for 1 second
and then restores the terminal to exactly how it was
desc
tput smcup #save previous state
head -n$(tput lines) /etc/passwd #get a screenful of lines
sleep 1
tput rmcup #restore previous state
This'll only work on a terminal has the smcup and rmcup capabilities (e.g., not on Linux console (=a virtual console)).
Terminal capabilities can be inspected with infocmp.
On a terminal that doesn't support it, my tput smcup simply return an exit status of 1 without outputting the escape sequence.
Note:
If you intend to redirect the output, you might want to write the escape sequences directly to /dev/tty so as to not dirty your stdout with them:
exec 3>&1 #save old stdout
exec 1>/dev/tty #write directly to terminal by default
#...
cat /etc/passwd >&3 #write actual intended output to the original stdout
#...

In a bash script, print command (as a suggestion) on the prompt after the script exit

I'd like to write a shell script that can suggest a command by printing it after the command line prompt.
Then, after the scrip exit, the user would only have to press the [enter] key to run this suggested command.
Given that I'm new to bash, I don't even know if it is possible to do this. I thought about using a copy-past command, moving the cursor, use the $PS1 variable, without finding a suitable way..
Does anyone have any clues on how such feature could be implemented ?
Following the suggestion of Landen in the comments (thanks a lot!), I've been able to produce a workaround for my problem.
This workaround needs the xautomation package (xte command, emulating key pressed), is not very robust, and may depends on the keyboard layout handling of xautomation, and system shortcuts. For example, I had to change the shortcut for the unity HUD.
But given that my command is very fast, and that is is mostly for personal use, this solution fits perfeclty my needs:
COMMAND_PASSED='sudo apt-get update'
# Displays the content of $COMMAND_PASSED on the next prompt
xte "str $COMMAND_PASSED"
sleep 0.1
tput cub ${#COMMAND_PASSED}
sleep 0.1 and tput cub ${#COMMAND_PASSED} commands are needed to prevent the keys from being also displayed before the command prompt.
sleep 0.1 makes the whole command to be printed before the prompt.
tput cub ${#COMMAND_PASSED} move the cursor backward to make sure that all unnecessary prints are erased.
Thanks everyone!

How can one put the output of a command into a konsole title bar?

Through the clever use of some escape characters, I used to put the output of arbitrary commands (e.g. "dirs") into my xterm title bar. Can I do the same thing in konsole? If so, how?
It's a little tricky to do what you want, but you can change Konsole's title bar. Go to:
Settings > Edit current profile > Tabs > Tab title format
and change it to %w which means Window Title Set by Shell. I think you need to close Konsole and reopen it for the changes to take effect.
Anyway, go to the prompt and exec:
OUTPUT=`whoami`; echo -ne "\033]2;$OUTPUT\007"
and behold!
This example sets the title of the window temporarily to whatever is outputted by whoami.
You can also do it using dbus:
qdbus $KONSOLE_DBUS_SERVICE $KONSOLE_DBUS_SESSION setTitle 1 $(dirs)
for KDE 3, using dcop:
dcop $KONSOLE_DCOP_SESSION renameSession $(dirs)

Redraw screen in terminal

How do some programs edit whats being displayed on the terminal (to pick a random example, the program 'sl')? I'm thinking of the Linux terminal here, it may happen in other OS's too, I don't know. I've always thought once some text was displayed, it stayed there. How do you change it without redrawing the entire screen?
Depending on the terminal you send control seuqences. Common sequences are for example esc[;H to send the cursor to a specific position (e.g. on Ansi, Xterm, Linux, VT100). However, this will vary with the type or terminal the user has ... curses (in conjunction with the terminfo files) will wrap that information for you.
Many applications make use of the curses library, or some language binding to it.
For rewriting on a single line, such as updating progress information, the special character "carriage return", often specified by the escape sequence "\r", can return the cursor to the start of the current line allowing subsequent output to overwrite what was previously written there.
try this shellscript
#!/bin/bash
i=1
while [ true ]
do
echo -e -n "\r $i"
i=$((i+1))
done
the -n options prevents the newline ... and the \r does the carriage return ... you write again and again into the same line - no scroling or what so ever
If you terminate a line sent to the terminal with a carriage return ('\r') instead of a linefeed ('\n'), it will move the cursor to the beginning of the current line, allowing the program to print more text over top of what it printed before. I use this occasionally for progress messages for long tasks.
If you ever need to do more terminal editing than that, use ncurses or a variant thereof.
There are characters that can be sent to the terminal that move the cursor back. Then text can be overwritten.
There is a list here. Note the "move cursor something" lines.
NCurses is a cross-platform library that lets you draw user interfaces on smart terminals.
Corporal Touchy has answered how this is done at the lowest level. For easier development the curses library gives a higher level of control than simply sending characters to the terminal.
To build on #Corporal Touchy's answer, there are libraries available that will handle some of this functionality for you such as curses/ncurses
I agree with danio, ncurses is the way to go. Here's a good tutorial:
http://tldp.org/HOWTO/NCURSES-Programming-HOWTO/

Resources