Simple Contact Import Script for AtMail

Posted by Ryan Uber | Bourne-Again Shell (bash),Mail | Tuesday 20 July 2010 1:48 pm
#!/bin/bash
# AtMail Contact Import Script (Primitive)
# This will only import e-mail address, first name, and last name for each contact.
# It's an email contact directory, not an iPhone.
# FILE should be set to the path to a CSV with the following format:
# AtMailUserEmail,ContactFirstName,ContactLastName,ContactEmail

# Set configuration
FILE='./contacts.csv'
SQL_USER='user_name_here'
SQL_PASS='password_here'
SQL_DB='database_name_here'

# Run the loop
cat ${FILE} | awk -F, '{print $1 " " $2 " " $3 " " $4}' | while read USER FIRST LAST EMAIL; do
    CHAR="$(echo ${EMAIL:0:1} | tr '[[:upper:]]' '[[:lower:]]'
    mysql -u${SQL_USER} -p${SQL_PASS} ${SQL_DB} -Ne \
        "INSERT INTO Abook_${CHAR}
            (
                `Account`,
                `UserEmail`,
                `UserFirstName`,
                `UserLastName`
            )
        VALUES
            (
                '${USER}',
                '${EMAIL}',
                '${FIRST}',
                '${LAST}'
            )
        ;"
    echo "Imported for ${USER}: \"${FIRST} ${LAST}\" <${EMAIL}>"
done

# EOF

Running commands on a gob of Linux servers? No problem

Posted by Ryan Uber | Bourne-Again Shell (bash),Linux | Tuesday 1 June 2010 8:30 pm

(originally written around May 15th or so)

Today I am sitting in Phoenix at one of my employer’s datacenter locations. One of the first tasks that I got when I arrived was to log in via SSH to just over 500 customer servers and run a few commands to gather inventory information, including CPU speed, # of CPU’s, and OS version.

Now, when you look at that task with the mindset of “I have to log in to all of those?”, you will probably not be too happy about the work ahead of you. However, if you get a little creative and start looking for ways to avoid such massive repetition, you might quickly come to a solution similar to what I came up with.

I ended up using the expect command for SSH, since I did not have any SSH keys installed, and I simply could not sit and paste in passwords for hours. I got the local sysadmin to install the ‘expect’ package on our central shell server, and whipped up a quick little script to do my work for me. Keep in mind that this script will likely not apply to something you are doing, because this particular case was a customer running FreeSSH on Windows servers, but it will give you the general idea of how much you can do with so little code:

#!/usr/local/bin/expect
# =============================================================
# Filename:    GetInfo.exp
# Description: Echo's the output of systeminfo Windows command
# =============================================================

# Get variables from argv
set remote_server [lindex $argv 0]

# Spawn SSH session
spawn /usr/bin/ssh -o "StrictHostKeyChecking=no" user@$remote_server "systeminfo"
expect {
    "assword:" {
        set timeout 60
        send -- "root_password_here\r"
        send -- "\r"
    }
}

expect eof
# EOF

(more…)

Stop piping between grep, awk, and sed with bash in-line variable manipulation

Posted by Ryan Uber | Bourne-Again Shell (bash) | Wednesday 12 May 2010 2:18 am

I’ve just stumbled upon this little bash gem. In one simple line of a bash script, without invoking any external commands whatsoever, you can effectively replace and otherwise manipulate text within variables.

If you use variable protection regularly (ex: “${VAR}” versus “$VAR” ), then this will look pretty obvious to your right away — one of those “a-ha!” moments. If you aren’t familiar with variable protection, you should seriously look into it. It will make your bash scripting life easier.

Below I’ll show you a quick example of how you can eliminate calling another shell, and the #!/bin/bash
TEST=”yodawg”
echo ${TEST/yo/werd}sed command, in your bash scripts:

#!/bin/bash
TEST="yodawg"
TEST=( ${TEST/yo/werd} )
echo $TEST

You can see how similar the syntax is to using the sed command in a similar fashion. One of the nicer things about using this method, is that it parses the text within the variable. I find this particularly useful and beneficial to the cleanliness of my code. Traditionally, I would define an extra variable to hold the content of my sed-replaced variable, or call a subshell, like “$(echo ${VAR} | sed s/a/b/g)”. Below I’ll show you a comparison of the way my coding has changed since I discovered this.

Before:

VAR="this is a test"
NEWVAR=$(echo ${VAR} | sed s/test/string/g)
echo ${NEWVAR}

And after:

VAR="this is a test"
echo ${VAR/test/string}

Both achieve precisely the same effect, but the later piece of code leaves one less variable dirty, saves a line of code, looks cleaner, is smaller in size, and requires no external commands to run.

Pretty nifty, right?

The above examples only replace the first occurance of the string. If you want to replace globally in the string, you can use a double-slash instead of a single-slash, like this:

VAR="this is a test. this is another test."
echo ${VAR//test/string}

Edit: I found another extremely handy bash tip for variables — Wish I would have found it earlier, 3000 shell scripts later.

[ryan@home]$ TEST="this is a test"
[ryan@home]$ echo ${#TEST}
14

Using variable protection along with the “#” sign in front of the variable’s name will print the number of characters contained in the string variable, just like “wc”, or sizeof().

Edit:
Another useful function is the percent sign “%”. You can use it to trim a string from the end of a variable. Say I am converting a PNG image to a JPG image. I could do something like the following with the variable name to change the extension:

[ryan@home]$ FILENAME="test.png"
[ryan@home]$ echo "${FILENAME%png}jpg"
test.jpg

Edit:
Once again I stumbled upon another great bash variable feature. This one acts conditionally, and provides an easy and built-in mechanism for a “default value”. Observe the script below:

#!/bin/bash
TEST="test"
echo ${TEST-not set}

The above will output “test”. Now observe the revised script:

#!/bin/bash
#TEST="test"
echo ${TEST-not set}

The above will output “not set” because the “TEST” variable was empty. Nifty, right?

« Previous PageNext Page »