11

I am new to shell script. I have a file app.conf as :

[MySql]
user = root
password = root123
domain = localhost
database = db_name
port = 3306

[Logs]
level = logging.DEBUG

[Server]
port = 8080

I want to parse this file in shell script and want to extract mysql credentials from the same. How can I achieve that?

exAres
  • 4,806
  • 16
  • 53
  • 95

4 Answers4

12

I'd do this:

pw=$(awk '/^password/{print $3}' app.conf)

user=$(awk '/^user/{print $3}' app.conf)


echo $pw
root123

echo $user
root

The $() sets the variable pw to the output of the command inside. The command inside looks through your app.conf file for a line starting password and then prints the 3rd field in that line.

EDITED

If you are going to parse a bunch of values out of your config file, I would make a variable for the config file name:

CONFIG=app.conf
pw=$(awk '/^password/{print $3}' "${CONFIG}")
user=$(awk '/^user/{print $3}' "${CONFIG}")

Here's how to do the two different ports... by setting a flag to 1 when you come to the right section and exiting when you find the port.

mport=$(awk '/^\[MySQL\]/{f=1} f==1&&/^port/{print $3;exit}' "${CONFIG}")
sport=$(awk '/^\[Server\]/{f=1} f==1&&/^port/{print $3;exit}' "${CONFIG}")
Mark Setchell
  • 191,897
  • 31
  • 273
  • 432
  • Thanks a lot, but I am getting an error : `user: not found`. My shell script file is : `#!/bin/sh user = $(awk '/^user/{print $3}' /root/app/config/app.conf)` – exAres Mar 27 '14 at 09:54
  • Remove the spaces around the equals sign. – Mark Setchell Mar 27 '14 at 10:03
  • 1
    Are you on Windows? If so, try changing the single quotes into doube quotes. If that fails, try checking your file has no weird characters with "cat -vet yourfile". If that fails, edit your answer and post the exact code you are having trouble with and I'll take a look. – Mark Setchell Mar 27 '14 at 10:56
  • Thanks a lot Mark. It is working. It was my stupid mistake in understanding what you were saying (apparently I was removing spaces from app.conf, as I never thought that spaces in assignment statements in shell script would matter). Now what I understood is spaces are not allowed in shell script for `var=value` and `$n` gives me the nth part separated by space in a line matched by a regex provided to awk. Also `$0` would give me the entire line where the match was found. – exAres Mar 27 '14 at 11:00
  • Exactly! You are on your way - happy shell scripting! – Mark Setchell Mar 27 '14 at 11:01
  • 1
    I added some hints to the end of my answer... for your next question ;-) – Mark Setchell Mar 27 '14 at 14:08
  • hehe, thanks. I did use the variable to store the file name. And I was needing only username and password. Though, your updated was definitely helpful as I would have surely stuck there if that would have been my use case. Interesting stuff..! – exAres Mar 28 '14 at 03:01
6

You will want to search for "shell ini file parser". I would start with something like this:

ini_get () {
    awk -v section="$2" -v variable="$3" '
        $0 == "[" section "]" { in_section = 1; next }
        in_section && $1 == variable {
            $1=""
            $2=""
            sub(/^[[:space:]]+/, "")
            print
            exit 
        }
        in_section && $1 == "" {
            # we are at a blank line without finding the var in the section
            print "not found" > "/dev/stderr"
            exit 1
        }
    ' "$1"
}

mysql_user=$( ini_get app.conf MySql user )
glenn jackman
  • 238,783
  • 38
  • 220
  • 352
5

Using awk:

awk -F ' *= *' '$1=="user"||$1=="password"{print $2}' my.cnf
root
gogslab
anubhava
  • 761,203
  • 64
  • 569
  • 643
  • Yes sure. This awk uses field separator as `=` with optional spaces on either side. Once field are separated it prints 2nd field when 1st field is either `user` OR `password` – anubhava Mar 27 '14 at 09:42
2

I ran in a similar problem yesterday and thought the best solution might be, if you get an associative array like "key - value" after parsing the file.

I you like to see a running example have a look at https://github.com/philippkemmeter/set-resolution/blob/master/set-resolution.

Adapted to your problem, this might work:

function receive_assoc_declare_statement {
    awk -F '=' 'BEGIN {ORS=" "}
    { 
        gsub(/[ \t]+/, "", $1); 
        gsub(/[ \t]+/, "", $2);
        print "[" $1 "]=" $2
    }' app.conf
}

eval 'declare -A CONF=('`receive_assoc_declare_statement`')'

You then have access to for instance user via ${CONF[user]}.

The gsub is trimming keys and values, so that you can use tab etc. to format your config file.

It's lacking sections, but you could add this functionality using sed to create one config array per section:

sed -n '/\[MySql\]/, /\[/ {p}' test.removeme | sed '1 d; $ d'

So answering your question in total, this script might work:

MYSQL=`sed -n '/\[MySql\]/, /\[/ {p}' app.conf | sed '1 d; $ d' | awk -F '=' 'BEGIN {ORS=" "}
{
    gsub(/[ \t]+/, "", $1); 
    gsub(/[ \t]+/, "", $2);
    print "[" $1 "]=" $2
}' `
eval 'declare -A MYSQL=('$MYSQL')'

The other sections correspondingly.

Phil
  • 3,282
  • 1
  • 20
  • 16