0

Hi I am trying to convert this source file:

source --------

    [ODBC Data Sources]
C334_DEV_MD=Micro ODBC Driver for SQL Server Wire Protocol
C334_PRD_ST=Micro ODBC Driver for SQL Server Wire Protocol

[ODBC]
Trace=0
TraceFile=odbctrace.out
TraceDll=/home/mstr/Micro/install/lib32/MYtrcXX.so
InstallDir=/home/mstr/Micro/install
IANAAppCodePage=106
UseCursorLib=0

[C334_DEV_MD]
HostName=C334WM01NA02
PortNumber=1433
Database=C334_DEV_MD
DoubleToStringPrecision=17

[C334_PRD_ST]
HostName=C334WM01NA02
PortNumber=1433
Database=C334_PRD_ST
DoubleToStringPrecision=17

source----------

Into this file with a script.

destination--------

C334_DEV_MD=Driver description|HostName=C334WM01NA02;PortNumber=1433;Database=C334_DEV_MD;DoubleToStringPrecision=17|na01liwp01c334
C334_PRD_ST=Driver description|HostName=C334WM01NA02;PortNumber=1433;Database=C334_PRD_ST;DoubleToStringPrecision=17|na01liwp01c334

destination---------

ODBC entry is not important here.

This is a pattern the output should follow.

DSN_entry=Driver Description|Parameter1=value;Parameter2=value;Parameter3=value|Server_Name

Servername could be taken from file name of the source file.

This is what I did so far, but I am stuck.

#!/bin/bash
flag=0
sourcefile=$1
destfile=$2
sed -n '2,/^$/p' $sourcefile | awk -F"=" '{print$1}' | sed '$d' | \
while read line; do
        #echo $line
        grep -E ''"^${line}"'|'"^\[${line}"'' $sourcefile
done
fuzzy186
  • 27
  • 1
  • 7

2 Answers2

0

I would use awk:

# Record definitions
BEGIN {
  FS="\n"; OFS="|"; RS="\n\n"; ORS="\n"
}

# Parse data source descriptions
$1 ~ /ODBC Data Source/ {
    for(i=2; i<= NF; i++) {
        split($i, a, "=")
        n[a[1]]=a[2]
    }
}

# Output the result record. Replace the datasource id
# by the description
$1 ~ /DSN_entry/{
    gsub(/\[|\]/,"",$1)
    print n[$1],$2,$3,$4
}

Save the above script into a file translate.awk and call it like this:

awk -f translate.awk input.file
hek2mgl
  • 152,036
  • 28
  • 249
  • 266
  • It doesn't produce any output for me. I saved your code in translate.awk file and run awk -f translate.awk input.file. No output. – fuzzy186 Mar 31 '15 at 13:15
  • Hmm. I've tested it with the data shown in the question. Can you post your exact input data? (Are you using Linux, meaning `gawk`?) – hek2mgl Mar 31 '15 at 13:19
  • This is my input data. – fuzzy186 Mar 31 '15 at 13:28
  • Input data pasted in my first post just a moment ago. – fuzzy186 Mar 31 '15 at 13:33
  • Also because I have many such files, I would like to convert them one by one by running your command with 2 parameters. awk -f translate.awk input.file output.file. Input file is named odbci_na01liwp01c334.ini and has the name of the server which is to be added at the end of the output lines. – fuzzy186 Mar 31 '15 at 13:35
  • Sorry, I was AFK. We need a dynamic match against the contents of `n`. I can extend the answer later. – hek2mgl Apr 01 '15 at 06:31
0

It might be possible to hack something together for this with awk, but I think the saner alternative is to use a proper INI file parser. For example, using Perl and Config::IniFiles:

#!/usr/bin/perl

use Config::IniFiles;

# We expect the INI file to be given as first parameter.
scalar(@ARGV) > 0 || die "Missing parameter";

my $hostname = $ARGV[0];
$hostname =~ s/odbci_(.*)\.ini/\1/;

# You may want to also pass -nocase => 1 here, for case-insensitive matching
my $cfg = Config::IniFiles->new( -file => $ARGV[0]);

my @sources = $cfg->Parameters('ODBC Data Sources');

foreach $source (@sources) {
    my $line = "$source=" . $cfg->val('ODBC Data Sources', $_);
    my @params = $cfg->Parameters($source);

    my $sep = "|";
    foreach (@params) {
        $line .= "$sep$_=" . $cfg->val($source, $_);
        $sep = ";";
    }

    print "$line|$hostname\n";
}

The same in Python 2:

#!/usr/bin/python

import ConfigParser
import re
import sys

if len(sys.argv) < 2:
    print "Need input file parameter"
    sys.exit(1)

inifile = sys.argv[1]
hostname = re.search('odbci_(.*)\.ini', inifile, re.IGNORECASE).group(1)

cfg = ConfigParser.SafeConfigParser()
cfg.optionxform = lambda option: option
cfg.read(inifile)

for source in cfg.options('ODBC Data Sources'):
    line = source + '=' + cfg.get('ODBC Data Sources', source)
    sep = '|'
    for param in cfg.options(source):
        line = line + sep + param + '=' + cfg.get(source, param)
        sep = ';'

    print line + '|' + hostname

...and in Python 3:

#!/usr/bin/python3

import configparser
import re
import sys

if len(sys.argv) < 2:
    print("Need input file parameter")
    sys.exit(1)

inifile = sys.argv[1]
hostname = re.search('odbci_(.*)\.ini', inifile, re.IGNORECASE).group(1)

cfg = configparser.SafeConfigParser()
cfg.optionxform = lambda option: option
cfg.read(inifile)

for source in cfg['ODBC Data Sources']:
    line = source + '=' + cfg['ODBC Data Sources'][source]
    sep = '|'
    for param in cfg[source]:
        line = line + sep + param + '=' + cfg[source][param]
        sep = ';'

    print(line + '|' + hostname)

All of these expect to be called as scriptname odbci_hostname.ini.

Wintermute
  • 42,983
  • 5
  • 77
  • 80
  • The name of the "na01liwp01c334" comes from the name of the source file - odbci_na01liwp01c334.ini – fuzzy186 Mar 31 '15 at 12:37
  • In that case, you could do something like `my $hostname = $ARGV[0]; $hostname =~ s/odbci_(.*)\.ini/\1/;` and later `print "$line|$hostname\n";`. – Wintermute Mar 31 '15 at 12:44
  • I would really like to avoid using perl. It seems like I would need to install it on the servers, which I can't do. – fuzzy186 Mar 31 '15 at 13:13
  • 1
    Perl is part of every GNU/Linux distributuion by default. However, the `Config::IniFiles` package will likely not being installed. – hek2mgl Mar 31 '15 at 13:22
  • It is rare to see a UNIX machine that doesn't have Perl, but okay. If I were you, I'd see what tools I have at my disposal and if one of them includes an INI parser (such as Python's [configparser](https://docs.python.org/3/library/configparser.html), although Python is probably too much to hope for on a machine that doesn't have Perl). You can see that the script is just a few lines where nothing special happens, so it's easily translatable. What I *wouldn't* do unless I had no other choice is to try to parse the INI file with flat-text tools; that's bound to break when formatting changes. – Wintermute Mar 31 '15 at 13:30
  • Possibly relevant (to use `Config::IniFiles` when it is not installed on the system and root permissions are not had): https://stackoverflow.com/questions/2980297/how-can-i-use-cpan-as-a-non-root-user – Wintermute Mar 31 '15 at 13:39
  • Actually the perl is there but i have some problems with installing cpan install Config::IniFiles. I am root, but I don't think our policy permits installing it. – fuzzy186 Mar 31 '15 at 13:52
  • Do you have Python, and if so, version 2 or 3? There's an INI parser in Python's standard library. – Wintermute Mar 31 '15 at 14:08
  • Python 2 is installed there. – fuzzy186 Mar 31 '15 at 14:16
  • It worked great :), thanks Wintermute. But can I have one more small request. Can it create output file (given as a parameter) instead of just standard output ? I used python 2 version. – fuzzy186 Mar 31 '15 at 14:33
  • Can't you just say `scriptname odbci_hostname.ini > output.whatever`? – Wintermute Mar 31 '15 at 14:36
  • Ok. that will do, Thanks very much Wintermute :) – fuzzy186 Mar 31 '15 at 14:43