LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Newbie (https://www.linuxquestions.org/questions/linux-newbie-8/)
-   -   bash array substitute the value of nth element (https://www.linuxquestions.org/questions/linux-newbie-8/bash-array-substitute-the-value-of-nth-element-4175454698/)

casperdaghost 03-19-2013 09:43 AM

bash array substitute the value of nth element
 
this is the string i want to change :

random|L|N|0|0|1|0|R|0100|T|N|0|0|100|0|1|0|0|0|1|casper cap|N||N|C|0|0000994500|S|0000115500


I named the script foobaz. It greps out a stock called random, and breaks down the pipe delimited string. The only value that i need replaced is the 27th value, or third to last element of this string with value of $2. the stock name is going to be $1 and the price will be $2.
I need this price replaced and a new string printed out.

Code:

$  /tmp/foobaz random 999999999
random|L|N|0|0|1|0|R|0100|T|N|0|0|100|0|1|0|0|0|1|casper cap|N||N|C|0|0000994500|S|0000115500

waljoh@carpcoreinit03 master $


#!/bin/bash

stocks=$(egrep "^$1" /data/casper/stocks.txt)
echo "$stocks"


IFS='|' read -ra ADDR <<< "$stocks"

for i in "${ADDR[@]}";
do
    sed -e 's/$2/"${ADDR[27]}"/g'
    echo ${ADDR[@]}
    done


rigor 03-19-2013 10:34 AM

I'm not exactly sure what you are trying to represent here. But you can just assign a value to an array element directly.

grail 03-19-2013 10:36 AM

To say I am confused is an understatement.

Firstly, I think you have been using the forum long enough to know that you use code tags when displaying data or code.

Is the script supposed to be in foobaz?

Is the word 'random' a string?

What does the original data set look like? From your current output that does not contain '999999999', is this good or bad? Did the substitution work?

Lastly, in the code, what are you running sed against? I see no file no string???

casperdaghost 03-19-2013 01:24 PM

sorry guys - I am at work and had to do this on the sly
this is the data set :
random|L|N|0|0|1|0|R|0100|T|N|0|0|100|0|1|0|0|0|1|casper cap|N||N|C|0|0000994500|S|0000115500

this is the only part of the string that i need to replace : 0000994500 - all the other values need to stay the same.
if I just echo out the array it lines up nicely.
Code:

#!/bin/bash
stocks=$(egrep "^$1" /data/casper/stocks.txt)
echo "$stocks"


IFS='|' read -ra ADDR <<< "$stocks"

for i in "${ADDR[@]}";
do
   
    echo $i
    done

but again , all i need to do is change the 27th value in the pipe delimited string.

shivaa 03-19-2013 01:56 PM

Replace with what and how many times? Can't you simply do it like this:
Code:

~$ sed -e 's/0000994500/<string>/g'
OR
~$ awk 'BEGIN{FS="|"}; {gsub(/0000994500/,"<string>",$27); print $0}' infile.txt
OR
~$ echo "random|L|.....|0000994500|S|0000115500" | awk 'BEGIN{FS="|"}; {gsub(/0000994500/,"<string>",$27); print $0}'

Even you can:
Code:

~$ awk -v val=${ADDR[27]} 'BEGIN{FS="|"}; {gsub(/val/,"<string>",$27); print $0}' infile.txt

chrism01 03-19-2013 07:12 PM

Hers' one using cut
Code:

t='random|L|N|0|0|1|0|R|0100|T|N|0|0|100|0|1|0|0|0|1|casper cap|N||N|C|0|0000994500|S|0000115500'

# Grab front of rec
f=$(echo $t|cut -d'|' -f1-26)
#random|L|N|0|0|1|0|R|0100|T|N|0|0|100|0|1|0|0|0|1|casper cap|N||N|C|0

# grab end of rec
e=$(echo $t|cut -d'|' -f28-)
#S|0000115500

# create new val
new='|new_val|'

#put it all back together
echo ${f}${new}${e}


grail 03-19-2013 09:34 PM

hmmm ... whilst all the posts above would seem ample, I am curious why you do not simply replace the array item as you need?

If we assume your code works as it stands and each item of the pipe separated string is now an individual part of the ADDR array, can't you simply:
Code:

ADDR[26]='new info'
Or have I completely missed something?

casperdaghost 03-22-2013 09:42 AM

this is the sting i am working with :
Code:

random|L|N|0|0|1|0|R|0100|T|N|0|0|100|0|1|0|0|0|1|casper cap|N||N|C|0|0000994500|S|0000115500
and the script is called : /tmp/foobaz random 999999999 (it is invoked here with a $1 and $2 at the command line)
and yeah - Grail the substitution works !!!!
Code:

#!/bin/bash
stocks=$(egrep "^$1" /data/casper/stocks.txt)
echo "$stocks"


IFS='|' read -ra ADDR <<< "$stocks"

for i in "${ADDR[@]}";
do
    ADDR[26]="$2"
   
    done
echo ${ADDR[@]} | tr " " "|"

however when i put it back together - I have a problems on reassembling the string.

Code:

random|L|N|0|0|1|0|R|0100|T|N|0|0|100|0|1|0|0|0|1|casper|cap|N||N|C|0|9999999999|S|0000115500
the name 'casper cap' should have a space - but it does not.
Keep in mind - i know that i could use awk fields - but want to understand bash arrays.

"If it doesn't challenge you, it doesn't change you!"

grail 03-22-2013 12:11 PM

Ok ... I get you now. So first off, you do know that your for loop is pointless?? Firstly you never use the 'i' variable and second if you know which element to replace you do not need to loop
over anything.

So the easy answer is, use IFS more:
Code:

#!/bin/bash
stocks=$(egrep "^$1" /data/casper/stocks.txt)
echo "$stocks"

IFS='|'

ADDR=( $stocks )

ADDR[26]="$2"

echo "${ADDR[*]}"

unset IFS

The secret is in the highlighted portion ;)

casperdaghost 03-26-2013 06:43 PM

this worked great Grail
I wanted so bad to use the arrays in bash, but alas, it was not to be true.

PTrenholme 03-26-2013 06:57 PM

Quote:

Originally Posted by casperdaghost (Post 4919545)
this worked great Grail
I wanted so bad to use the arrays in bash, but alas, it was not to be true.

But gail's code does use an array. So it is "true." :scratch:

The statement ADDR=( $stocks ) loads the array ADDR with the values in ${stocks}, delimited by the pipe symbol.

David the H. 03-28-2013 04:15 AM

If you hadn't noticed, the secret is that the '*' array expansion element uses the first character of IFS as its delimiter when printing out the list (be sure to quote it).

So setting IFS to the pipe globally means that it both splits the string into the array and prints the updated array in the same way.

arrays


BTW, grail's code simply used an unquoted variable inside an "arr=()" pattern to set the array. The expanded parameter is word-split according to the current IFS setting, which is then used to set the array. However I would point out that there's a minor risk to this. Since shell globbing is also applied on unquoted parameters, some character in the input could potentially expand into a list of files existing in the PWD, which would also become part of the array.

This can be avoided by also using set +f to turn off glob expansion temporarily. Or you can continue to use read instead, which I personally recommend as the cleaner option.


All times are GMT -5. The time now is 07:23 AM.