2

I have one Configuration file with section wise data, as mentioned below. Using shell script accessing each variable. I am using sed command for that, Now I facing one problem like if I forget to configure one variable example:name [APP1] it will take [APP2] name.
Config File:

[APP1]
name=Application1
StatusScript=/home/status_APP1.sh
startScript=/home/start_APP1.sh
stopScript=/home/stop_APP1.sh
restartScript=/home/restart.APP1.sh

[APP2]
name=Application2
StatusScript=/home/status_APP2.sh
startScript=/home/start_APP2.sh
stopScript=/home/stop_APP2.sh
restartScript=/home/restart.APP2.sh
logdir=/log/APP2/
.
.
.
.
.
[APPN]
name=ApplicationN
StatusScript=/home/status_APPN.sh
startScript=/home/start_APPN.sh
stopScript=/home/stop_APPN.sh
restartScript=/home/restart.APPN.sh
logdir=/log/APPN

shell command using :

sed -nr "/^\[APP1\]/ { :l /^name[ ]*=/ { s/.*=[ ]*//; p; q;}; n; b l;}"

Is there any way to solve this problem, if some variable not configured under one section it through null or 0 as the variable value.

1

You can create a shell function like this:

printSection()
{
  section="$1"
  found=false
  while read line
  do
    [[ $found == false && "$line" != "[$section]" ]] &&  continue
    [[ $found == true && "${line:0:1}" = '[' ]] && break
    found=true
    echo "$line"
  done
}

You can then use printSection like a command, and pass in the section as a parameter like:

printSection APP2

To get your parameter, you can use a much simpler sed now, like:

printSection APP2 | sed -n 's/^name=//p'

This will be operating on stdin and writing to stdout. So if your example config file were called named /etc/application.conf, and you wanted to store the name of APP2 in a variable app2name, you could write this:

app2name=$(printSection APP2 | sed -n 's/^name//p/' < /etc/applications.conf)

Or, you could build the parameter part into the function and skip sed altogether, like this:

printValue()
{
  section="$1"
  param="$2"
  found=false
  while read line
  do
    [[ $found == false && "$line" != "[$section]" ]] &&  continue
    [[ $found == true && "${line:0:1}" = '[' ]] && break
    found=true
    [[ "${line%=*}" == "$param" ]] && { echo "${line#*=}"; break; }
  done
}

Then you would assign your var like this:

app2name=$(printValue APP2 name < /etc/applications.conf)
  • 1
    I'm terribly sorry, I was adding stuff to your answer that should have been in my answer! Duh. I've restored it now. Need more coffee... – Kusalananda May 19 '18 at 8:13
2

Parse your configuration into an unambiguous format, then read it into an associative array in a recent release of bash:

awk '/^\[/ { app=substr($0,2,length-2) } /=/ { print app "." $0 }' file.conf

This finds all section headers and sets the awk variable app to the contents of these. It then prefixes each following line with that value followed by a dot.

This would create output like

APP1.name=Application1
APP1.StatusScript=/home/status_APP1.sh
APP1.startScript=/home/start_APP1.sh
APP1.stopScript=/home/stop_APP1.sh
APP1.restartScript=/home/restart.APP1.sh
APP2.name=Application2
APP2.StatusScript=/home/status_APP2.sh
APP2.startScript=/home/start_APP2.sh
APP2.stopScript=/home/stop_APP2.sh
APP2.restartScript=/home/restart.APP2.sh
APP2.logdir=/log/APP2/

If your APP2 lacked a name subsection, the APP2.name line would not show up.

Then read this into an associative array in bash:

declare -A conf
while IFS='=' read -r key value; do
    conf[$key]="$value"
done < <(awk '/^\[/ { app=substr($0,2,length-2) } /=/ { print app "." $0 }' file.conf)

You may now query the conf variable for your configuration:

printf 'The stopScript for APPN is "%s"\n' "${conf[APPN.stopScript]}"

This will return

The stopScript for APPN is "/home/stop_APPN.sh"

Querying a non-existing value will yield an empty string.


The awk command could also be replace by the following sed command:

sed -n \
    -e '/^\[/{s/[][]//g;h;}' \
    -e '/=/{H;g;s/\n/./;p;s/\..*//;h;}' file.conf

Expanded and annotated:

/^\[/{          # handle section headers
    s/[][]//g;  # remove [ and ]
    h;          # put into the hold-space
}

/=/{            # handle settings
    H;          # append the line to the hold-space with newline as delimiter
    g;          # get the hold-space
    s/\n/./;    # replace the newline with a dot
    p;          # output
    s/\..*//;   # remove everything after the dot
    h;          # put back into the hold-space
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.