1

First I would like to say thanks ahead of time to all of you, that I hope to be a part of some day. So I have a file that is a list of lines that are 5 parameters long. Such as

Bob:Wilson:Nebraska:34:yes

I need to write a program in BASH that will allow me to view the standard out put horizontally and will allow me to call the lines of text in the file like

$sh filename.sh 1
Bob
Tom
Dave
etc..

or

$sh filename.sh 1 3 4 2
Bob:Nebraska:34:Wilson
Tom:Iowa:27:Anderson
etc..

What I have written so far is

cut -d : -f$1,$2,$3,$4,$5 somefile.txt | paste -s

The problem is if the user puts in less then 5 parameters after sh filename.sh I get an error code. The user is not required to put in 5 but can call up to 5.

Socowi
  • 25,550
  • 3
  • 32
  • 54
Grunt
  • 47
  • 1
  • 6

3 Answers3

0

awk to the rescue!

awk -F: -v c="$1 $2 $3 $4 $5" 'BEGIN {n=split(c,a," ")} 
                                     {for(i=1;i<n;i++) printf "%s", $a[i] FS; 
                                      printf "%s\n", $a[n]}' file

try and let me know if you need clarification.

karakfa
  • 66,216
  • 7
  • 41
  • 56
  • I see the use of "awk" a lot to answer these question on this board (I have been creeping for a while) but we have yet to cover it in class so I not familiar with it enough to use it but thank you very much for your input!! I am learning this on line and it leaves a lot to be desired. – Grunt Apr 05 '17 at 21:02
0

Expand Only Existing Parameters

IFS=,
cut -d : -f"$*" somefile.txt

$* expands to 1st parameter $IFS 2nd parameter $IFS ... $IFS last parameter, that is $1,$2 if two parameters were given, $1,$2,$3 if three were given, and so on.

Allow Rearranging

The command from above has a problem: cut cannot rearrange columns. cut -f1,2 is equivalent to cut -f2,1. See rearrange columns using cut. Therefore we use awk instead.

If the parameters were filename.sh 1 3 4 2, then we would need the following awk command:

awk -F: -v OFS=: '{ print $1, $3, $4, $2 }' somefile.txt

-F sets the field seperator for reading the file. -v OFS=: sets the field seperator of the output. print $1, $3, ... means »print the first field, then the third, ...«. Note that '$1' is not the first argument of your script, but a literal string that is interpreted by awk.

We use the same trick as before to build an awk-command from the given parameters.

IFS=,
awk -F: -v OFS=: "{ print ${*/#/$} }" somefile.txt

${*/#/$} prepends $ to each parameter. The expansion will be $ 1st parameter , $ 2nd parameter , ... , $ last parameter.

Community
  • 1
  • 1
Socowi
  • 25,550
  • 3
  • 32
  • 54
  • I forgot to add the ". Thanks – Grunt Apr 05 '17 at 22:01
  • Your script doesn't give the requested output. When called `./script 1 3 4 2` it will output `Bob:Wilson:Nebraska:34` instead of `Bob:Nebraska:34:Wilson`. – reflective_mind Apr 06 '17 at 01:10
  • `cut` cannot change the order of fields. See [this question](http://stackoverflow.com/q/2129123/6770384). Since Grunt asked primarily about the parameters instead of the actual cutting I assumed that wasn't a problem for him/her. But you are right, I should fix this. – Socowi Apr 06 '17 at 08:43
  • Thanks to inferno for letting me know that cut will not rearrange the order. – Grunt Apr 10 '17 at 22:08
0

Personally I would always avoid text processing with shell scripts. There are better tools like sed, awk or perl to name a few. This is how I would do it in pure bash since that seems to be what you are looking for (*):

#!/bin/bash
#file: script.sh

for line in $(<somefile.txt); do
   array=( ${line//:/ } )
   counter=1
   for elem in $@; do
      echo -n "${array[$elem-1]}"
      [ $counter -ne $# ] && echo -n ":"
      ((counter++))
   done
   echo
done

(*): Don't be confused by the syntax highlighting, which recognizes everything after $# as a comment (gray text). It's all syntactically correct in the example script.

Explanation:

The script reads somefile.txt, splits each line at the : characters and stores the resulting fields/elements in the array array. Then it outputs the fields in the order specified by your script arguments ($@).

Here is the output, exactly how you want it:

$ ./script.sh 1
Bob
Tom

$ ./script.sh 1 3 4 2
Bob:Nebraska:34:Wilson
Tom:Iowa:27:Anderson

Also note the following:

In your example you possibly execute your script with the Bourne Shell (sh) and not bash. The script above however requires bash because it uses the substring replacement feature.

reflective_mind
  • 1,475
  • 3
  • 15
  • 28