LinuxQuestions.org
Register a domain and help support LQ
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 06-02-2011, 04:10 PM   #1
dokkalf
LQ Newbie
 
Registered: Apr 2007
Posts: 18

Rep: Reputation: 0
bash: format select options


I have a formatted file of tab-separated fields, four fields per line, a field can contain spaces. I want to use this to generate a menus in a bash script using select. However, since an entire line is too long, I want to format the line across two lines without select making each individual line an option.

Here's what I've got:

data.txt
Header1<tab>Header2<tab>Header3<tab>Header4
field11<tab>field12<tab>field13<tab>field14<newline>
field21<tab>field22<tab>field23<tab>field24<newline>
field31<tab>field32<tab>field33<tab>field34<newline>
field41<tab>field42<tab>field43<tab>field44<newline>

script.sh
#!/bin/bash

formatline()
{
current=$1
field2=$(echo $1 | cut -f 2)
field3=$(echo $1 | cut -f 3)
field4=$(echo $1 | cut -f 4)

echo -e "Field 2 = $field2\tField 4 = $field4\n\tField 3 = $field3\n"
}

OLDIFS=$IFS
IFS=$'\012'

select lchoice in $(for i in $(awk (NR > 1)); do formatline $i; done)
do
echo $lchoice
done
IFS=$OLDIFS
#end of script

What I want to see:
1) Field 2 = field12 <tab> Field 4 = field14
<tab> Field 3 = field13
2) Field 2 = field22 <tab> Field 4 = field24
<tab> Field 3 = field23
3) Field 2 = field32 <tab> Field 4 = field34
<tab> Field 3 = field33
4) Field 2 = field42 <tab> Field 4 = field44
<tab> Field 3 = field43

What I actually see:
1) Field 2 = field12 <tab> Field 4 = field14
2) <tab> Field 3 = field13
3) Field 2 = field22 <tab> Field 4 = field24
4) <tab> Field 3 = field23
5) Field 2 = field32 <tab> Field 4 = field34
6) <tab> Field 3 = field33
7) Field 2 = field42 <tab> Field 4 = field44
8) <tab> Field 3 = field43

Is there any way to get select to do what I want - maybe by playing games with IFS?

Last edited by dokkalf; 06-02-2011 at 04:12 PM. Reason: forgot header line in data file
 
Old 06-02-2011, 10:48 PM   #2
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Debian sid + kde 3.5 & 4.4
Posts: 6,823

Rep: Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950
The problem is that the entries you want to print contain newlines also, so you get one entry for each newline-separated field, not each line output from the function.

One solution is to specify a unique delimiter that can be used instead of newline.

Here's a version that appears to do what you want. I've also taken the liberty of rearranging things to make it cleaner and removed the need to call on external tools like awk and cut.
Code:
formatline() {

local IFS=$'\t'

while read line ; do

     [[ $line == Header* ]] && continue
     local farray=( $line )
     echo -en "Field 2 = ${farray[1]}\tField 4 = ${farray[3]}\n\tField 3 = ${farray[2]}@"
     #last character echoed is the delimiter you want to use.
     
done <"$1"

}

IFS="@"

select lchoice in $( formatline data.txt ); do

     echo "$lchoice"

done
Edit: I almost forgot...please use [code][/code] tags around your code, to preserve formatting and to improve readability.

Last edited by David the H.; 06-02-2011 at 11:00 PM. Reason: minor fixes + addendum
 
Old 06-03-2011, 01:29 PM   #3
dokkalf
LQ Newbie
 
Registered: Apr 2007
Posts: 18

Original Poster
Rep: Reputation: 0
This works - thanks.

I knew there had to be something better than that ugly awk/cut combo, but once I had it, I couldn't think of anything else. That'll probably be more useful to me.

As for the code tags - oops.
 
Old 06-04-2011, 06:38 AM   #4
grail
Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 7,648

Rep: Reputation: 1963Reputation: 1963Reputation: 1963Reputation: 1963Reputation: 1963Reputation: 1963Reputation: 1963Reputation: 1963Reputation: 1963Reputation: 1963Reputation: 1963
Just another alternative for you:
Code:
#!/usr/bin/awk -f

BEGIN{  OFS=FS="\t" }

NR > 1{
    n = NR - 1
    print line[n] = sprintf("%d) Field 2 = %s\tField 4 = %s\n\tField 3 = %s",n,$2,$4,$3)
}

END{
    printf "Please select the corresponding number # "
    getline choice < "-"
    
    print "Your choice was:\n"line[choice]

}
 
Old 06-05-2011, 07:43 AM   #5
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Debian sid + kde 3.5 & 4.4
Posts: 6,823

Rep: Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950
When all you need to do is print certain fields in a string, bash arrays and/or parameter substitution can often be good alternatives to awk, sed, grep, and cut. The external tools are generally better (and often more efficient) when more complex processing is required, such as when complex regex patterns are required to match text or when targeting only certain lines in a file or such.

By the way, I was wondering why you were using IFS=$'\012' in your script instead of IFS=$'\n'. That seemed a bit odd to me, since you used \n elsewhere in the script.


@grail: As usual, another nice solution. But he did mention that this was for inclusion in a larger script. It would have to be converted to a stand-alone command for in-script use, and the output likely captured in a bash variable for further use.
 
Old 06-05-2011, 10:18 AM   #6
grail
Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 7,648

Rep: Reputation: 1963Reputation: 1963Reputation: 1963Reputation: 1963Reputation: 1963Reputation: 1963Reputation: 1963Reputation: 1963Reputation: 1963Reputation: 1963Reputation: 1963
Quote:
But he did mention that this was for inclusion in a larger script.
Missed that bit The awk could of course be shortened to just the essentials to return the desired output, but if we stay with bash I would employ
your solution but ditch the select all together and have the while loop handle it.

Guess ultimately it will depend on the overall algorithm the OP is searching for
 
Old 06-06-2011, 02:52 PM   #7
dokkalf
LQ Newbie
 
Registered: Apr 2007
Posts: 18

Original Poster
Rep: Reputation: 0
@grail: several years ago, I created a database for my personal library using Carlo Strozzi's NoSQL database and tools. Periodically, I attempt to create complex query scripts for it that are shell-based (in keeping with NoSQL's theory of close integration with UNIX and the idea of the shell as a 4GL). This particular script will, when finished (or if), allow me to get information on a series based on just a few title words and/or author.

@David: I developed the habit of using octal notation when assigning a value like newline or tab to variable like IFS because many of the sample scripts in the Advanced Bash-scripting Guide by Mendel Cooper did so.
 
Old 06-06-2011, 09:45 PM   #8
grail
Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 7,648

Rep: Reputation: 1963Reputation: 1963Reputation: 1963Reputation: 1963Reputation: 1963Reputation: 1963Reputation: 1963Reputation: 1963Reputation: 1963Reputation: 1963Reputation: 1963
Thanks for the information ... if we can help any further just ask away
 
  


Reply


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
bash script: using "select" to show multi-word options? (like "option 1"/"o zidane_tribal Programming 6 03-21-2013 11:35 AM
Select options from website to initiate download from script (wget alternative?) hattori.hanzo Programming 1 11-18-2010 09:17 AM
need a php script to format and display a select amount of text from a file steve51184 Linux - Software 27 01-27-2009 03:29 PM
select partitions or format during install junme Solaris / OpenSolaris 4 12-24-2004 07:13 AM
Select boot options in shutdown menu? dominik81 Mandriva 7 02-21-2004 04:21 AM


All times are GMT -5. The time now is 06:30 PM.

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