Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Staying DRY with Bash Indirect References

DZone's Guide to

Staying DRY with Bash Indirect References

· DevOps Zone
Free Resource

Download the blueprint that can take a company of any maturity level all the way up to enterprise-scale continuous delivery using a combination of Automic Release Automation, Automic’s 20+ years of business automation experience, and the proven tools and practices the company is already leveraging.

I should start this post by saying I don’t recommend this method for all situations due to potential security issues, as well as some readability tradeoffs. If that didn’t scare you off, keep reading.

I was faced recently with a situation where I needed to update a MySQL clone script written in bash to pull data from multiple MySQL servers and write to a single server. We often do this to quickly copy data from environment to another for testing. The original script was written with the assumption of only one source server and looked roughly like this:

source_mysql_host="not.the.best.idea"
source_mysql_user="xxx"
source_mysql_passwd="yyy"
 
echo ; echo " ==>  Cloning databases. Source: $source_mysql_host, Destination: $dest_mysql_host"
 
DATABASES=`mysql -u${source_mysql_user} "-p${source_mysql_passwd}" -h${source_mysql_host} \
            -NBe 'show databases' | egrep -v '^information_schema|performance_schema|mysql|test|backups$'`
for db in $DATABASES; do
    echo "   ==> Cloning database '$db' .. "
 
    $mysqldump_cmd -u${source_mysql_user} "-p${source_mysql_passwd}" -h${source_mysql_host} --add-drop-database --database ${db} | \
    mysql -u${dest_mysql_user} "-p${dest_mysql_passwd}" -h${dest_mysql_host}
done

(The full block of code was 26 lines. Much of it has been left out since it is not relevant to this article)

In order to update this script to clone data from multiple servers we could simply duplicate the entire 26 line block of code and change the variables so that the first block uses $OLAP_mysql_host and the other uses $OLTP_mysql_host, and so on, but that would not be very DRY.

What I ended up doing was wrapping the block of code into a new for loop and using bash’s indirect references to switch between the source MySQL servers. Note the ugly bash indirect references. It works and we stay DRY. Was it worth it? Maybe, Maybe not. =)

OLTP_source_mysql_host="not.the.best.idea"
OLTP_source_mysql_user="xxx"
OLTP_source_mysql_passwd="yyy"
 
OLAP_source_mysql_host="not.the.best.idea.2"
OLAP_source_mysql_user="xxx"
OLAP_source_mysql_passwd="yyy"
 
for type in "OLTP" "OLAP"; do
 
    # use bash's indirect references. very ugly, but helps us stay DRY
    _mysql_source_host=$(eval "echo \$$(echo ${type}_source_mysql_host)")
    _mysql_source_user=$(eval "echo \$$(echo ${type}_source_mysql_user)")
    _mysql_source_passwd=$(eval "echo \$$(echo ${type}_source_mysql_passwd)")
    _schema_only_tables=$(eval "echo \$$(echo ${type}_SCHEMA_ONLY_TABLES)")
 
    echo ; echo " ==> Cloning ${type} databases. Source: $_mysql_source_host, Destination: $dest_mysql_host"
 
    # get a list of databases, excluding the mysql system db's (ie: mysql, test, ...)
    DATABASES=`mysql -u${_mysql_source_user} "-p${_mysql_source_passwd}" -h${_mysql_source_host} \
                -NBe 'show databases' | egrep -v '^information_schema|performance_schema|mysql|test|backups$'`
    for db in $DATABASES; do
        echo "   ==> Cloning database '$db' .. "
 
        $mysqldump_cmd -u${_mysql_source_user} "-p${_mysql_source_passwd}" -h${_mysql_source_host} --add-drop-database --database ${db} | \
        mysql -u${dest_mysql_user} "-p${dest_mysql_passwd}" -h${dest_mysql_host}
    done
done

Download the ‘Practical Blueprint to Continuous Delivery’ to learn how Automic Release Automation can help you begin or continue your company’s digital transformation.

Topics:

Published at DZone with permission of Joe Miller, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}