LinuxQuestions.org
View the Most Wanted LQ Wiki articles.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices

Reply
 
Search this Thread
Old 01-14-2012, 05:31 PM   #1
Dick Dastardly
LQ Newbie
 
Registered: Jul 2011
Posts: 23

Rep: Reputation: Disabled
(BASH) How to assign 2 variables to same line?


Hello to all.
I'm trying to write a small bash funtion that retrieves Xbox Live Deal of the Week info.

Here's what i have so far:

Code:
xbox()
{
  # get xbox live deals of the week game titles
  xbox_name=$(curl -s http://marketplace.xbox.com/en-US/Promotion/dealoftheweek|grep -i "a class"|grep -i "title="|cut -d"\"" -f6)

  # get deal prices
  xbox_price=$(curl -s http://marketplace.xbox.com/en-US/Promotion/dealoftheweek|grep -i "mspoints goldprice"|cut -d">" -f3|cut -d"<" -f1)

  # display info
  echo -e "$xbox_name""\n$xbox_price"
}
I'm not very proficient so my method of obtaining the title and price may be a bit crude but grep and cut are tools i'm familiar with. I'd love to hear any other ways to do it.

My issue is getting the title and price on the same line. As of now, the output looks like this:

Code:
Defense Grid
Orcs Must Die!
Dungeon Defenders
South Park
400
600
800
400
I'd like it to look like this:

Code:
Defense Grid        400
Orcs Must Die!      600
Dungeon Defenders   800
South Park          400
Should i be trying to put both the title and price inside it's own variable (if so how would one achieve this?) or is there a way to echo it?

Any help is much obliged.

Last edited by Dick Dastardly; 01-14-2012 at 05:39 PM.
 
Click here to see the post LQ members have rated as the most helpful post in this thread.
Old 01-14-2012, 06:56 PM   #2
Roken
Member
 
Registered: Oct 2011
Location: Bolton, UK
Distribution: Arch local, Debian on VPS
Posts: 252

Rep: Reputation: 40
This will do it:

Code:
#!/bin/bash
IFS='
'

xbox_name=($(curl -s http://marketplace.xbox.com/en-US/Promotion/dealoftheweek|grep -i "a class"|grep -i "title="|cut -d"\"" -f6))
xbox_price=($(curl -s http://marketplace.xbox.com/en-US/Promotion/dealoftheweek|grep -i "mspoints goldprice"|cut -d">" -f3|cut -d"<" -f1))
loop=${#xbox_name[*]}
for ((counter=0; counter<=$loop; counter++))
do
  echo "${xbox_name[$counter]}" "${xbox_price[$counter]}"
done
"IFS=" forces bash to delimit at line breaks rather than spaces
The next two lines read name and price into arrays
loop= gets the number of array items
And the rest iterates through the array, echoing the name and corresponding price on each line.

I didn't bother looking at how you are reading the input since it seems to do the job.

Note, if you want to tabulate it like your example you'll have to play with your formatting for the echo - but I'm not doing everything for you

Last edited by Roken; 01-14-2012 at 06:57 PM.
 
3 members found this post helpful.
Old 01-14-2012, 07:22 PM   #3
Dick Dastardly
LQ Newbie
 
Registered: Jul 2011
Posts: 23

Original Poster
Rep: Reputation: Disabled
Thanks for the solution Roken
Been tinkering with the echo to no avail....yet!
This is what i'd assume it to be but it doesn't seem right.

Code:
echo -e "${xbox_name[$counter]}" "\t\t${xbox_price[$counter]} MSP"
 
Old 01-14-2012, 08:30 PM   #4
Roken
Member
 
Registered: Oct 2011
Location: Bolton, UK
Distribution: Arch local, Debian on VPS
Posts: 252

Rep: Reputation: 40
OK, try this:

Code:
#!/bin/bash
IFS='
'

xbox_name=($(curl -s http://marketplace.xbox.com/en-US/Promotion/dealoftheweek|grep -i "a class"|grep -i "title="|cut -d"\"" -f6))
xbox_price=($(curl -s http://marketplace.xbox.com/en-US/Promotion/dealoftheweek|grep -i "mspoints goldprice"|cut -d">" -f3|cut -d"<" -f1))
loop=${#xbox_name[*]}
for ((counter=0; counter<$loop; counter++))
do
  name="${xbox_name[$counter]}\t"
  if [ "${#xbox_name[$counter]}" -lt 16 ]; then
     name="$name\t"
  fi

  echo -e "$name${xbox_price[$counter]} MSP"
done
The extra test is to allow for longer names. Two tabs added for less than 16 characters, only one for more than 16 characters.
 
1 members found this post helpful.
Old 01-14-2012, 09:43 PM   #5
Dick Dastardly
LQ Newbie
 
Registered: Jul 2011
Posts: 23

Original Poster
Rep: Reputation: Disabled
Thank you a million times!
I couldn't work it out so went for this in the end (though i'll use yours now)

Code:
....
for ((counter=0; counter<="$loop"; counter++)); do
    echo -e "${xbox_name[$counter]}"; echo -e "${xbox_price[$counter]} MSP"; echo
done|head -n -4
 
Old 01-14-2012, 11:19 PM   #6
grail
Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 7,513

Rep: Reputation: 1895Reputation: 1895Reputation: 1895Reputation: 1895Reputation: 1895Reputation: 1895Reputation: 1895Reputation: 1895Reputation: 1895Reputation: 1895Reputation: 1895
Just in case it doesn't have to be bash:
Code:
#!/usr/bin/awk -f

BEGIN{	FS = "[<>]" 
	OFS = "|" }

/ProductBox/{
	gsub(/.*=/,"",$2)
	title[++i] = $2
}

/ProductPrices/{ price[i] = $5	}

END{
	for( x = 1; x <= i; x++ )
		print title[x],price[x]
}
And you can run it like so for results:
Code:
$ curl -s http://marketplace.xbox.com/en-US/Promotion/dealoftheweek | ./d.awk | column -t -s "|"
"Defense Grid"       400
"Orcs Must Die!"     600
"Dungeon Defenders"  800
"South Park"         400
 
2 members found this post helpful.
Old 01-15-2012, 01:35 AM   #7
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Debian sid + kde 3.5 & 4.4
Posts: 6,823

Rep: Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947
I'd like to point out that, for efficiency purposes, it's generally better to download the entire data set only once, and parse the saved text as needed.

Code:
xdata=$( curl -s http://marketplace.xbox.com/en-US/Promotion/dealoftheweek | grep -e "ProductBox" -e "GoldPrice" )

mapfile -t titles < <( sed -rn 's/.*title="([^"]*)".*/\1/p' <<<"$xdata" )
mapfile -t prices < <( sed -rn 's/.*GoldPrice ProductPrice">([^<]+)<.*/\1/p' <<<"$xdata" )

for i in "${!titles[@]}"; do

	tabs='\t'
	(( ${#titles[i]} <= 16 )) && tabs='\t\t'

	printf "%s$tabs%s\n" "${titles[i]}" "${prices[i]}"

done
I used bash 4's new mapfile command to set the arrays instead of the IFS technique Roken used above, and I've simplified his loop a bit. Otherwise it's the same basic procedure. You might even want to add more tabs and more tests for them in case you get some really long tiles.

Other expressions used above (mostly bash-specific):
process substitution
here strings
the ${!array[@]} substitution pattern for listing index numbers
arithmetic evaluation
printf

Edit: I just want to say, grail's use of the column command to format the output is an excellent suggestion. You can modify the loop above to use it like this:

Code:
for i in "${!titles[@]}"; do

	printf "%s|%s\n" "${titles[i]}" "${prices[i]}"

done | column -t -s '|'

Last edited by David the H.; 01-15-2012 at 01:53 AM. Reason: as stated
 
2 members found this post helpful.
Old 01-15-2012, 02:42 AM   #8
grail
Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 7,513

Rep: Reputation: 1895Reputation: 1895Reputation: 1895Reputation: 1895Reputation: 1895Reputation: 1895Reputation: 1895Reputation: 1895Reputation: 1895Reputation: 1895Reputation: 1895
Nice work David ... I will have to read up on mapfile as I tried a bash solution but suffered word splitting without setting IFS.
 
Old 01-15-2012, 03:51 AM   #9
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Debian sid + kde 3.5 & 4.4
Posts: 6,823

Rep: Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947
Yeah, ever since I realized that mapfile could also be used internally for parsing lines from commands, I've found myself using it more and more. It can often be quite a bit less hassle than running it through a while+read loop.

Speaking of which, I'd also written up a traditional loop version that replaced the sed commands with bash regexes, but eventually decided it wasn't worth cluttering up my post with it. I guess it won't hurt to post it now, though.

Code:
tregex='title="([^"]*)"'
pregex='GoldPrice ProductPrice">([^<]+)<'

while read line; do
     [[ $line =~ $tregex ]] && titles+=( "${BASH_REMATCH[1]}" )
     [[ $line =~ $pregex ]] && prices+=( "${BASH_REMATCH[1]}" )
done <<<"$xdata"
Thanks in return for reminding me about column.
 
1 members found this post helpful.
Old 01-15-2012, 07:27 AM   #10
Roken
Member
 
Registered: Oct 2011
Location: Bolton, UK
Distribution: Arch local, Debian on VPS
Posts: 252

Rep: Reputation: 40
Quote:
Originally Posted by David the H. View Post
I'd like to point out that, for efficiency purposes, it's generally better to download the entire data set only once, and parse the saved text as needed.
I agree. As I mentioned in my original reply, I didn't really look at the data gathering code since it worked, and I assumed that this is an occasional script anyway, so not big deal re the extra download.

Having said that, mapfile and column I wasn't even aware of. Couple of new things for me to become familiar with
 
Old 01-15-2012, 09:17 AM   #11
Dick Dastardly
LQ Newbie
 
Registered: Jul 2011
Posts: 23

Original Poster
Rep: Reputation: Disabled
Thanks for all the great info. I love the way there's always more than one way to do it.
I'll have to do a lot of reading to understand most of what you guys are telling me.
I'll have a play around and see what i come up with.
 
  


Reply

Tags
bash, echo, function, variables


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
[SOLVED] Simple Modify of Variables in bash file + Inject one line. Dimitriy Programming 18 05-03-2011 03:11 AM
[SOLVED] Bash gurus: Using 'cut' to assign multiple shell variables? forbin Programming 9 08-08-2010 11:15 AM
assign commands to Variables tazbv Programming 2 08-03-2007 02:07 AM
Perl + Java assign variables arash8m Programming 1 07-17-2007 01:37 PM
Using letters/strings to assign variables in python Colonel Panic Programming 0 09-14-2001 10:13 PM


All times are GMT -5. The time now is 11:30 AM.

Main Menu
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration