Archive for Shell Scripting

Eternal Bash History - super duper useful

I come accross this nice little article! Me and Simon have wondered how to do this for a while.. well, now we know how! wohoo!

Many times I’ve found myself using Ctrl-R in Bash to get a old command four times the terminal width, just to find out that too many days have passed and it’s no longer in the .bash_history file. Here are two lines that will keep track of every command line you type at the bash prompt and use no external processes at all, just plain bash.

My first approach to this problem was increasing the maximum number of lines in the history to a very large quantity. But no matter how large it was, there was always a moment when I needed a long command I typed many months ago and it had already left the history. The current solution came to my mind when I learned about the PROMPT_COMMAND variable, a command that bash executes before showing each prompt. Here are the two lines:

export HISTTIMEFORMAT=”%s ”
PROMPT_COMMAND=”${PROMPT_COMMAND:+$PROMPT_COMMAND ; }”‘echo $$ $USER \
“$(history 1)” >> ~/.bash_eternal_history’

One goal I set to myself was to achieve it without using any external process, so bash wouldn’t have to fork a new process after every ENTER pressed at its prompt. The first line sets the format of history lines to include the date as a Unix timestamp, so you can now when you typed every command. The second line, which is the core of the solution, first ensures that, if a previous PROMPT_COMMAND was set, it gets executed before our stuff and then appends a line of the format:

PID USER INDEX TIMESTAMP COMMAND

to a file called .bash_eternal_history in the current user home.

Adding the username, which at first seemed unnecesary, became useful later to distiguish between “sudo -s” sessions and normal sessions which retain the same value for “~/”, and so append lines to the same .bash_eternal_history file.

I hope some of you find these two lines as useful as I do. :-)

Source: debian-administration.org
Author: Andy Teijelo

Comments (3)

using ssh on multiple servers at one time

The possibilities for this app are endless. Yum.

Lots of us have many server to manage and we perform the same tasks on each of the machine every day, if you want to save time the package cssh will make you happy!

Simply install the clusterssh package:

host:/# apt-get install clusterssh

Now if you want to perform the same command on the three servers one, two, & three simply run:

host:/# cssh one two three

This will open three console, one for each server, over an ssh connection, and one little console to type your command.

Enjoy !
Source of article: Debian-Administration.org

Comments (1)

Writing a Shell Script that executes Locally OR Remotely

There are a lot of times when it is useful to have a single shell script run both upon the local host, and also upon remote hosts. Here we’ll show a simple trick which allows you to accomplish this easily.

To execute shell scripts remotely the most obvious approach is to copy it there, with scp, and then use ssh to actually execute it. This is similar to running simple commands remotely using ssh directly:

skx@mine:~$ ssh yours uptime
07:12:25 up 3 days, 18:15,  0 users,  load average: 0.00, 0.00, 0.08
skx@mine:~$

With that in mind the solution becomes:

  • Write a simple shell script which will be useful.
  • Determine whether it should run remotely, and if so:
    • Copy itself there.
    • Execute itself there.

As an example we’ll look at a simple script which will report upon the uptime of the system it is executed upon:

Here is the script:

#!/bin/sh

#
#  Are we installing locally?  Or remotely?
#
if [ ! -z $1 ]; then

#  Hostname
host=$1

#  Create a secure temporary file.
file=`mktemp`

#  Create a temporary file, and copy the contents of ourself into
# it.  Making sure it has a shebang.
echo "#!/bin/sh"                > "${file}"
grep -A2000 '^#-=-MARKER-=' $0 >> "${file}"
chmod 755 "${file}"

#  Copy the file to the remote host, and invoke it
scp "${file}" ${host}:
ssh "${host}" ./`basename ${file}`

#  Cleanup remotely and locally.
ssh "${host}" /bin/rm `basename ${file}`
rm ${file}

#  All done - the rest of the script will occur remotely.
exit
fi

## THE NEXT LINE IS IMPORTANT     - DO NOT EDIT.  DO NOT REMOVE.
#-=-MARKER-=-
## THE PREVIOUS LINE IS IMPORTANT - DO NOT EDIT.  DO NOT REMOVE.

uptime

Here you can see that the script detects whether to run remotely or not based upon the presence of a command line argument, so this is local execution:

skx@mine:~$ ./uptime.sh
14:05:10 up  4:59,  4 users,  load average: 0.05, 0.05, 0.07

Whereas this is remote:

skx@mine:~$ ./uptime.sh cfmaster.my.flat
tmp.RRjRSx9137                                100%   98     0.1KB/s   00:00
14:05:28 up 430 days, 20:02,  0 users,  load average: 9.72, 6.58, 4.26

Neat huh?

The key to this script is that it can separate out the “real” work of the script so that only the end of the script is copied to the remote host - the part after the argument processing. This is achieved with the following command:

grep -A2000 '^#-=-MARKER-=' $0

This uses the “-A” option of GNU grep to cause it to print out a number of line after the line beginning “#-=-MARKER-=” - this is the part of the script that actually reports on the system uptime, and this is the part you’d replace with your own code.

The relevant lines are then placed into a temporary file and copied to the host upon which it should execute them. (If you didn’t have key-based authentication setup you’d be prompted for your password three times; the first time for the copy, the second time for the execution, and the final time to cleanup the file which was copied.)

Using a simple system like this you could easily write scripts that would preform tasks like installing CFEngine locally or remotely.

Comments