bdan629
bdan629

Reputation: 27

pulling information out of a string in shell script

I am having trouble pulling out the information I need from a string in my shell script. I have read and tried to come up with the correct awk or sed command to do it, but I just can't figure it out. Hopefully you guys can help.

Lets say I have a string as follows: ["ids":2817262,"isvalid":true,"name":"somename","hasproperty":false,"ids":2262,"isvalid":false,"name":"somename","hasproperty":false,"ids":28182,"isvalid":true,"name":"somename","hasproperty":true]

Now what I want to do is pull out all of these properties into individual arrays of strings. For example:

I would like to have an array of ids 2817262 2262 28182 an array of name somename somename somename an array of hasproperty false false true

Can anyone help me come up with the commands I need to pull this out. Also keep in mind the string will likely be much longer than this, so if we can not make it specific to 3 cases that would be helpful. Thanks so much in advance.

Upvotes: 1

Views: 124

Answers (7)

Ed Morton
Ed Morton

Reputation: 204548

Given your posted input, if all you wanted was the list of each type of item then this is all you'd need:

$ awk -v RS=, -F: '{gsub(/[[\]"\n]/,"")} /^ids/{print $2}' file                 
2817262
2262
28182
$ awk -v RS=, -F: '{gsub(/[[\]"\n]/,"")} /^name/{print $2}' file
somename
somename
somename
$ awk -v RS=, -F: '{gsub(/[[\]"\n]/,"")} /^hasproperty/{print $2}' file
false
false
true
$ awk -v RS=, -F: '{gsub(/[[\]"\n]/,"")} /^isvalid/{print $2}' file    
true
false
true

but it's extremely unlikely that this is the right way to approach your problem. As I mentioned in a comment, edit your question to provide more information if you'd like some real help with it.

Upvotes: 0

Costas
Costas

Reputation: 343

unset n
string='["ids":2817262,"isvalid":true,"name":"somename","hasproperty":false,"ids":2262,"isvalid":false,"name":"somename","hasproperty":false,"ids":28182,"isvalid":true,"name":"somename","hasproperty":true]'
while IFS=',' read -ra line
do
    ((n++))
    for i in "${line[@]//\"/}"
    do
        eval ${i%:*}[$n]=${i#*:}
    done
done < <(sed 's/[][]//g;s/,"ids/\n"ids/g' <<<$string)

The above will produce 4 arrays (ids,isvalid,name,hasproperty). If you need not isvalid just add:

unset n
string='["ids":2817262,"isvalid":true,"name":"somename","hasproperty":false,"ids":2262,"isvalid":false,"name":"somename","hasproperty":false,"ids":28182,"isvalid":true,"name":"somename","hasproperty":true]'
while IFS=',' read -ra line
do
    ((n++))
    for i in "${line[@]//\"/}"
    do
        [ "${i%:*}" != "isvalid" ] && eval ${i/:/[$n]=}
    done
done < <(sed 's/[][]//g;s/,"ids/\n"ids/g' <<<$string)

Upvotes: 0

NeronLeVelu
NeronLeVelu

Reputation: 10039

awk 'BEGIN {
   Field = 1
   Index = 0
   }
   {
   gsub( /[][]/,"")
   gsub( /"[a-z]*":/, "")
   FS=","

   while ( Field < NF) {
      ThisID[ Index]=$Field
      ThisName[ Index]=$(Field + 2)
      ThisProperty [ Index]=$(Field + 3)

      Index+=1
      Field+=4
      }
   }
END {
   for ( Iter=0;Iter<Index;Iter+=1) printf( "%s ", ThisID[Iter])
   printf "\n"
   for ( Iter=0;Iter<Index;Iter++) printf( "%s ", ThisName[Iter])
   printf "\n"
   for ( Iter=0;Iter<Index;Iter++) printf( "%s ", ThisProperty[Iter])
   printf "\n"
   }' YourFile

still to assign your array to your favorite variable

Upvotes: 0

user4453924
user4453924

Reputation:

Since it is tagged with awk

awk '{while(x=match($0,/"ids":([^,]+)/,a)){print a[1];$0=substr($0,x+RLENGTH)}}' file

This just keeps matching any ids then changing the line to contain only what is after the id.

Output

2817262
2262
28182

Could also do this(inspired by Wintermutes comment on another answer)

awk -v RS=",|]" 'sub(/^.*"ids":/,"")' file

Upvotes: 1

cdarke
cdarke

Reputation: 44434

Here is a pure bash solution (long-winded, isn't it? I tend to agree with @chepner):

str='["ids":2817262,"isvalid":true,"name":"somename","hasproperty":false,
"ids":2262,"isvalid":false,"name":"somename","hasproperty":false,"ids":28182,
"isvalid":true,"name":"somename","hasproperty":true]'

#Remove [ ]
str=${str/[/}
str=${str/]/}

declare -a ids
declare -a names
declare -a properties
oldIFS="$IFS"
IFS=','

for record in $str
do
    type=${record%%:*}
    value=${record##*:}

    if [[ $type == \"ids\" ]]
    then
        ids[ids_i++]="$value"
    elif [[ $type == \"name\" ]]
    then
        names[names_i++]="$value"
    elif [[ $type == \"hasproperty\" ]]
    then
        properties[properties_i++]="$value"
    else
        echo "Ignored type: '$type'" >&2
    fi
done

IFS="$oldIFS"
echo "ids: ${ids[@]}"
echo "names: ${names[@]}"
echo "properties: ${properties[@]}"

The only thing going for it is that there are no child processes.

Upvotes: 0

tommy.carstensen
tommy.carstensen

Reputation: 9622

The grep solution is beautiful. You question was tagged awk. The awk solution is ugly:

echo '["ids":2817262,"isvalid":true,"name":"somename","hasproperty":false,"ids":2262,"isvalid":false,"name":"somename","hasproperty":false,"ids":28182,"isvalid":true,"name":"somename","hasproperty":true]' \
| awk '{split(substr($0,2,length($0)-2),x,",");
 for(i=0;i<length(x);i++) {split(x[i],a,":");
 if(a[1]=="\"ids\"") print a[1],a[2]}}'

Output:

"ids" 2817262
"ids" 2262
"ids" 28182

Please choose the grep solution as the correct answer.

Upvotes: 0

Avinash Raj
Avinash Raj

Reputation: 174834

You could use grep.

grep -oP '"ids":\K\d+' file

Example:

$ echo '["ids":2817262,"isvalid":true,"name":"somename","hasproperty":false,"ids":2262,"isvalid":false,"name":"somename","hasproperty":false,"ids":28182,"isvalid":true,"name":"somename","hasproperty":true]' | grep -oP '"ids":\K\d+'
2817262
2262
28182

Upvotes: 2

Related Questions