# Who needs clean configuration? Swapping server.xml

So I'm working on a project that sometimes requires me to switch my server configuration. This is due to some circumstances with database drivers and names that are "too expensive to fix" ...

That made me think though: "Why do I always copy these files around manually?"

I decided I won't and wrote this small script to help me:

#!/bin/bash

if [ $# != 1 ] then echo "you must provide a configuration to switch to" exit fi; if [ -a$TOMCAT_HOME/conf/server_$1.xml ] then rm$TOMCAT_HOME/conf/server.xml
cp $TOMCAT_HOME/conf/server_$1.xml $TOMCAT_HOME/conf/server.xml else echo "given configuration was not found. did not make any changes." fi; exit 0  Usage is dead simple: I made this available system-wide and can just call: switch-config postgres  or switch-config firebird  To make changes happen. This is built for my personal convenience, so please ignore the incredibly bad error messages, also the (nonexistent) directory structure is for simple convenience. Comments like "move the different configurations somewhere else" don't help me. In any case, what can I improve? ## 2 Answers ### Method I'd suggest, instead of rm-ing and cp-ing, keeping each configuration set as named and symlinking to them as needed. This gives you a couple of benefits: • You can tell which the current one is without opening the file, just using ls -l: lrwxrwxrwx 1 user group 4 Jul 29 07:12 server.xml -> config-for-blah.xml • Changes are (sort-of) atomic: rm and cp take time, while over-writing a symlink with a symlink is as close to instant as you can reasonably make it. • You can move the actual files anywhere later and just update the symlinks: version-control it in a repo directory, put configuration sets into separate directories, whatever. Replacing the rm and cp in your current script, that'd be: ln -sf "$TOMCAT_HOME/conf/server_$1.xml" "$TOMCAT_HOME/conf/server.xml"


(You need -f, or else ln will complain that the link you're trying to create already exists.)

You should also detect whether the main commands have completed successfully, probably using something like:

if [ $? -ne 0 ]; then echo "Oops." >&2 exit 1 fi  ### Scripting • Quote your filenames. This helps avoid accidents where variables are mis-set. • Check your test types. In [$# != 1 ], $# is being referenced as a number, but != is for strings. Use -ne for numbers. (This is just a good habit to get into.) • You don't need the semicolons after the fi. • Error messages should usually go to stderr: echo "Error" >&2 • When detecting an error and exiting, exit with an status other than 0: this lets you easily detect problems when using the script. (c.f. the check in the method section above.) • Maybe do something to avoid command aliases. Sometimes aliases for commands like rm, cp, and ln can get into scripts by accident and make scripts break. You can avoid this by making sure your use of them doesn't trigger alias expansion for the commands, either by quoting, escaping, or using the full path. I agree with @Aesin, definitely using symlinks will be much better. A few minor points on top of his review: • Your script is not using any Bash features. You could as well change the shebang to #!/bin/sh • An alternative way to validate the command line arguments: if [ ! "$1" ]. I often prefer this, as it also checks that the argument is non-empty.
• When the command line arguments are invalid, the common exit code is 2
• There's no need for the exit 0 at the end of the script

Lastly, the then clauses are a bit oddly placed. The common placement is either this way:

if [ ... ]; then


Or this way:

if [ ... ]
then

• actually.. -a seems to be a bash feature. Switching the shebang to #!/bin/sh results in "Unexpected operator -a" – Vogel612 Jul 30 '15 at 11:32
• Oh. Come to think of it, I'm not used to seeing -a. I think you can replace it with -f, which will do the same and work in non-Bash too. – janos Jul 30 '15 at 11:37
• yep that works just fine :) – Vogel612 Jul 30 '15 at 11:39