jlp
jlp

Reputation: 1706

Get tokens from a String until they are exhausted in shell script

I have a shell script that reads input strings from stdin and get only part of the value from the input. The input string can have any number of key/value pairs and is in the following format:

{"input0":"name:/data/name0.csv",
 "input1":"name:/data/name1.csv",
 ....}

So in the above example, I want to get these as the output of my script:

/data/name0.csv
/data/name1.csv
.....

I think I need two while loops, one needs to keep reading from stdin, the other one needs to extract the values from the input until there is no more. Can someone let me know how to do the second loop block ?

Upvotes: 0

Views: 63

Answers (2)

Charles Duffy
Charles Duffy

Reputation: 295619

A simple BashFAQ #1 loop works here, with jq preprocessing your string into line-oriented content:

while read -r value; do
  echo "${value#name:}"
done < <(jq -r '.[]')

That said, you can actually do the whole thing just in jq with no bash at all; the following transforms your given input directly to your desired output (given jq 1.5 or newer):

jq -r '.[] | sub("name:"; "")'

If you really want to do things the fragile way rather than leveraging a JSON parser, you can do that too:

# This is evil: Will fail very badly if input formatting changes
content_re='"name:(.*)"'
while read -r line; do
  [[ $line =~ $content_re ]] && printf '%s\n' "${BASH_REMATCH[1]}"
done

There's still no inner loop required -- just a single loop iterating over lines of input, with the body determining how to process each line.

Upvotes: 1

Simonlbc
Simonlbc

Reputation: 651

if you have

{"input0":"name:/data/name0.csv",
    "input1":"name:/data/name1.csv",
    ....}

inside a file abc.in, then you can do the following to parse your input with a command called sed:

cat abc.in | sed 's/.*"input[0-9]\+":"name:\(\/data\/name[0-9]\+.csv\)".*$/\1/g'

it basically lookup the current line with a regular expression and see if it matches one of the form Begining of line then anything"input and a number":"name:/data/name and a number.csv"anything and then end of line. The result is:

/data/name1.csv
/data/name2.csv
/data/name3.csv
/data/name4.csv
...

Upvotes: 1

Related Questions