Grabbing value from piped file contents

Viewed 52

Let's say I have the following file:

credentials:
  [default]
  key_id = AKIAGHJQTOP
  secret_key = alcsjkf
  [default2]
  key_id = AKIADGHNKVP
  secret_key = njprmls

I want to grab the value of [default] key_id. I'm trying to do it with awk command but I'm open to any other way if it's more efficient and easier. Instead of passing a file name to awk, I want to pass the file contents from environmental variable FILE_CONTENTS

I tried the following:

$export VAR=$(echo "$FILE_CONTENTS" | awk '/credentials.default.key_id/ {print $2}')

But it didn't work. Any help is appreciated.

5 Answers

You can use awk like this:

cat srch.awk

BEGIN { FS = " *= *" }
{ sub(/^[[:blank:]]+/, "") }
/:[[:blank:]]*$/ {
   sub(/:[[:blank:]]*$/, "")
   k = $1
}
/^[[:blank:]]*\[/ {
   s = k "." $1
}
NF == 2 {
   map[s "." $1] = $2
}
key in map {
   print map[key]
   exit
}

# then use it as
echo "$FILE_CONTENTS" |
awk -v key='credentials.[default].key_id' -f srch.awk

AKIAGHJQTOP

# or else
echo "$FILE_CONTENTS" |
awk -v key='credentials.[default].secret_key' -f srch.awk

alcsjkf

With your shown samples, please try following awk code. Written and tested in GNU awk.

awk -v RS='(^|\\n)credentials:\\n[[:space:]]+\\[default\\]\\n[[:space:]]+key_id = \\S+' '
RT && num=split(RT,arr," key_id = "){
  print arr[num]
}
'   Input_file

Here is the Online demo for used regex(its bit changed from regex used in awk code as escaping is done in program not in site).

Assumptions:

  • no spaces between labels and :
  • no spaces between [ the stanza name and ]
  • all lines with attribute/value pairs have exactly 3 space-delimited fields as shown (ie, attr = value; value has no embedded spaces)
  • the contents of OP's variable (FILE_CONTENTS) is an exact copy (data and format) of the sample file provided by OP

NOTE: if the input file format can differ from these assumptions then additional code must be added to address said differences; as mentioned in comments ... writing your own parser is doable but you need to insure you address all possible format variations

One awk idea:

awk -v label='credentials' -v stanza='default' -v attr='key_id' '
/:/             { f1=0; if ($0 ~ label ":")      f1=1 }
f1 && /[][]/    { f2=0; if ($0 ~ "[" stanza "]") f2=1 }
f1 && f2 && /=/ { if ($1 == attr) { print $3; f1=f2=0 } }
' 

This generates:

AKIAGHJQTOP
$ awk 'f{print $3; exit} /\[default]/{f=1}' <<<"$FILE_CONTENTS"
AKIAGHJQTOP

If that's not all you need then edit your question to provide more truly realistic sample input/output including cases where the above doesn't work.

open to any other way if it's more efficient and easier

I suggest taking look at python's configparser, which is part of standard library. Let FILE_CONTENTS environment variable be holding

credentials:
  [default]
  key_id = AKIAGHJQTOP
  secret_key = alcsjkf
  [default2]
  key_id = AKIADGHNKVP
  secret_key = njprmls

then create file getkeyid.py with content as follows

import configparser
import os
config = configparser.ConfigParser()
config.read_string(os.environ["FILE_CONTENTS"].replace("credentials","#credentials",1))
print(config["default"]["key_id"])

and do

python3 getkeyid.py

to get output

AKIAGHJQTOP

Explanation: I retrieve string from environmental variable and replace credentials with #credentials at most 1 time in order to comment that line (otherwise parser will fail), then parse it and retrieve value corresponding to desired key.

Related