5

My /etc/environment looks like this:

cat /etc/environment
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games"

I wish to use a command (sed, awk, python, whatever....) that will make it look like this:

cat /etc/environment
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games"
JAVA_HOME="/usr/lib/jvm/java-6-sun"

Now the catch is, I would rather it be a 1 liner (in the fields of sed -XYZ /DoMagic/ /etc/environment), it needs to contain merging logic that is - either appends a new configuration record or update an existing one. Bottom line, it should prevent the file from looking like this: (Caused by in experienced shell scripters calling echo >> on each invocation)

cat /etc/environment
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games"
JAVA_HOME="/usr/lib/jvm/java-5-sun"
JAVA_HOME="/usr/lib/jvm/java-6-sun"
JAVA_HOME="/usr/lib/jvm/java-6-sun"
JAVA_HOME="/usr/lib/jvm/java-6-sun"

I guess this is a trick questions, because what I'm trying to avoid using custom scripts, such as

/usr/local/bin/PropUpdate /etc/environment JAVA_HOME "/usr/lib/jvm/java-6-sun"

/usr/local/bin/PropUpdate is the following script (written for the sake of example, may contain bugs. Comments are appreciated)

#!/bin/bash

# Append/Update a configuration record in a file
#
# Usage example:
# /usr/local/bin/PropUpdate /etc/environment JAVA_HOME "/usr/lib/jvm/java-6-sun"
#
# Author Maxim Veksler <maxim@vekslers.org>
# Version 0.5-2010-07-27


EXPECTED_ARGS=3
E_BADARGS=3
E_BADFILE=4

if [[ $# -ne ${EXPECTED_ARGS} ]]; then
  echo "Usage: `basename $0` /path/to/config.conf ParameterName newValueText" >&2
  exit $E_BADARGS
fi

CONFIGURATION_FILE="$1"
CONFIGURATION_PARAMETER="$2"
CONFIGURATION_VALUE="$3"

if [[ ! -e "${CONFIGURATION_FILE}" ]]; then
        echo "Configuration file ${CONFIGURATION_FILE} does not exist" >&2
        exit $E_BADFILE
fi

if [[ ! -w "${CONFIGURATION_FILE}" ]]; then
        echo "Can't modify ${CONFIGURATION_FILE}" >&2
        exit $E_BADFILE
fi



#########################################
## Decide what parameter we are adding ##
#########################################
__param_found=0

# First check CONFIGURATION_PARAMETER supplied by use that contains "="
if [[ ${CONFIGURATION_PARAMETER} == *=* ]]; then
        # It should exist in the file, plain
        if grep -qE "^${CONFIGURATION_PARAMETER}" "${CONFIGURATION_FILE}"; then
                __param_found=1
                SUFFIX_REGEX='[[:space:]]*'
        fi
else
        # OK, sophisticated user, did not send "=" with the parameter...
        if grep -qE "^${CONFIGURATION_PARAMETER}[[:space:]]*=" "${CONFIGURATION_FILE}"; then
                # Let's check if such configuration with Parameter + "=" exists
                __param_found=1
                SUFFIX_REGEX='[[:space:]]*=[[:space:]]*'
        elif grep -qE "^${CONFIGURATION_PARAMETER}[[:space:]]+" "${CONFIGURATION_FILE}"; then
                # If such parameter exists, at all
                __param_found=1
                SUFFIX_REGEX='[[:space:]]\+'
        fi
fi


if [[ $__param_found == 1 ]]; then
        #echo sed -i "s|^\(${CONFIGURATION_PARAMETER}${SUFFIX_REGEX}\).*$|\1${CONFIGURATION_VALUE}|g" "${CONFIGURATION_FILE}"
        sed -i "s|^\(${CONFIGURATION_PARAMETER}${SUFFIX_REGEX}\).*$|\1${CONFIGURATION_VALUE}|g" "${CONFIGURATION_FILE}"

else
        if [[ ${CONFIGURATION_PARAMETER} == *=* ]]; then
                # Configuration parameter contains "=" in it's name, good just append
                echo "${CONFIGURATION_PARAMETER}${CONFIGURATION_VALUE}" >> "${CONFIGURATION_FILE}"
        else
                # Try to guess if this file is a "param = value" or "param value" type of file.
                if grep -qE "^[[:alnum:]]+[[:space:]]*=" "${CONFIGURATION_FILE}"; then
                        # Seems like a "param = value" type of file
                        echo "${CONFIGURATION_PARAMETER}=${CONFIGURATION_VALUE}" >> "${CONFIGURATION_FILE}"
                else
                        # Seems like a "param  value" type of file
                        echo "${CONFIGURATION_PARAMETER} ${CONFIGURATION_VALUE}" >> "${CONFIGURATION_FILE}"
                fi
        fi
fi

#cat $CONFIGURATION_FILE

Thank you, Maxim.

-- Update: I actually kinda liked this script, so I've improved it a bit. It now seems to be production ready. Enjoy.

Maxim Veksler
  • 29,272
  • 38
  • 131
  • 151

3 Answers3

4

Instead of trying to parse /etc/environment file, you could instead create a file with your own name in /etc/profile.d/, as I described in my answer to a relevant question. Then you could just copy it over during installation, because it contains just your content. Let alone that it will make your scripts shorter.

Community
  • 1
  • 1
P Shved
  • 96,026
  • 17
  • 121
  • 165
  • 2
    Thanks, but I talking about the general idea of editing configuration files. Lot's of the systems involved don't implement the rc*.d design pattern. – Maxim Veksler Jul 25 '10 at 20:43
2
grep -q JAVA_HOME /etc/environment || echo 'JAVA_HOME="/usr/lib/jvm/java-5-sun"' >> /etc/environment

The grep command returns 0 (true) if the pattern is found in the file. So, the above reads:

check if JAVA_HOME is set in the file
OR set JAVA_HOME in the file

0-15:49 root@noneedto ~# cat /etc/environment
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games"
0-15:49 root@noneedto ~# grep JAVA_HOME /etc/environment && echo true
1-15:49 root@noneedto ~# grep -q JAVA_HOME /etc/environment || echo 'JAVA_HOME="/usr/lib/jvm/java-5-sun"' >> /etc/environment
0-15:49 root@noneedto ~# grep JAVA_HOME /etc/environment && echo true
JAVA_HOME="/usr/lib/jvm/java-5-sun"
true
0-15:49 root@noneedto ~# grep -q JAVA_HOME /etc/environment || echo 'JAVA_HOME="/usr/lib/jvm/java-5-sun"' >> /etc/environment
0-15:49 root@noneedto ~# cat /etc/environment
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games"
JAVA_HOME="/usr/lib/jvm/java-5-sun"

As you can see, if you invoke this one-liner multiple times, subsequent invocations do not add to the file because grep returns true before you attempt to append the file.

dannyman
  • 621
  • 1
  • 9
  • 27
  • Yes, but what about updating the file? Say I want to replace JAVA_HOME="/usr/lib/jvm/java-5-sun" with JAVA_HOME="/usr/lib/jvm/java-6-sun". This is where the real problem starts. – Maxim Veksler Jul 27 '10 at 06:04
  • `JAVA_HOME="\`find /usr/lib/jvm/ -name \\*-sun | sort -n | head -1\`"` – dannyman Jul 28 '10 at 19:52
  • Or you could `grep -q 'JAVA_HOME="/usr/lib/jvm/java-6-sun"'` . . . with shell scripts and many configuration files, the latest definition clobbers any previous definitions. Either you "would rather it be a 1 liner" as you stated in your question, in which case you evaluate the return code from grep, or you actually want a generalized configuration management system like that offered by cfengine or puppet. (I'm pretty damn sure Ubuntu handles these mundane configuration details, as well it should.) – dannyman Jul 28 '10 at 19:55
0

In my Ubuntu system, my JAVA_HOME looks like this:

JAVA_HOME=/usr/lib/jvm/default-java

Looking at that file with ls -l /usr/lib/jvm/default-java I noticed this:

lrwxrwxrwx 1 root root 24 Apr 27  2012 /usr/lib/jvm/default-java -> java-1.7.0-openjdk-amd64

In other words, the path in the soft link is the only thing you have to change.

To see the list of installed Java environments, I used this ls -l ... command:

prompt$ ls -l /usr/lib/jvm
total 20
lrwxrwxrwx 1 root root   24 Apr 27  2012 default-java -> java-1.7.0-openjdk-amd64
drwxr-xr-x 4 root root 4096 Feb 23 17:54 java-1.5.0-gcj-4.8-amd64
lrwxrwxrwx 1 root root   20 Sep  2  2012 java-1.6.0-openjdk-amd64 -> java-6-openjdk-amd64
lrwxrwxrwx 1 root root   20 Jul  3  2013 java-1.7.0-openjdk-amd64 -> java-7-openjdk-amd64
drwxr-xr-x 5 root root 4096 Oct  7  2012 java-6-openjdk-amd64
drwxr-xr-x 3 root root 4096 Oct  7  2012 java-6-openjdk-common
drwxr-xr-x 5 root root 4096 Sep 21 20:06 java-7-openjdk-amd64
drwxr-xr-x 8 root root 4096 Sep 18 21:18 java-7-oracle

So now I can switch to another default with:

sudo rm /usr/lib/jvm/default-java
sudo ln -s java-7-oracle /usr/lib/jvm/default-java

And the JAVA_HOME variable will run Java 7 from Oracle.

Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156