2

I have a bash script that takes three arguments, and I have a text file with three columns. I'd like the script to take the the text file's first, second, and third columns as the first, second, and third arguments of the bash script.

I'm a beginner with shell scripting, and am running fairly simple programs where efficiency is not very important, so simpler fixes would be appreciated :)

Here's an example of what I'd like to do.

I have a text file called food.txt with the following text:

fruits apples bananas
vegetables kale broccoli
meats pork beef
desserts cake pie

And I have a menu.sh script like this

#!/bin/bash

arg_1=$1
arg_2=$2
arg_3=$3

for arg_1 in $(cat food.txt)
do
    echo "${arg_1}:${arg_2},${arg_3}"
done

I would like menu.sh to output this:

fruits:apples,bananas
vegetables:kale,broccoli
meats:pork,beef
desserts:cake,pie

But instead it outputs this:

fruits:,
apples:,
bananas:,
vegetables:,
kale:,
...

Thanks in advance for the help!

5 Answers 5

3

The right way with bash's read function:

#!/bin/bash

while read -r arg_1 arg_2 arg_3; do 
    echo "${arg_1}:${arg_2},${arg_3}"
done < food.txt

https://www.gnu.org/software/bash/manual/bash.html#Bash-Builtins

Sign up to request clarification or add additional context in comments.

2 Comments

TLDP is not a good resource The TLDP bash guides are outdated, and in some cases just plain wrong. There's a reason they are not in the topic. (greybot on #bash@freenode)
@GillesQuenot, GNU version should be enough, I suppose
0

You met bash word spliting.

Check bash FAQ 1

You need to use

while read -r a1 a2 a3; do
    echo "$a1:$a2:$a3"
done < file

Comments

0
cat food.txt | while read line
do
  header="$(echo "$line" | cut -f1 -d' ')"
  fields="$(echo "$line" | cut -f2,3 -d' ' | tr ' ' ,)"
  echo "$header:$fields"
done

If you ever add another field / column you can just change that 2,3 to be 2,3,4 or 2-4. If you ever have a variable number of fields per line, you can change it to 2-.

Comments

0

Another interesting (but not optimal) way to achieve this is using IFS var(Internal Field Separator). It's used within bash to tell how to separate fields, in this case, in a for loop:

#!/bin/bash

file=$(cat food.txt)
IFS_OLD=$IFS
IFS=$'\n'
for line in $file; do
        name=$(echo "$line" | cut -d' ' -f1 )
        element1=$(echo "$line" | cut -d' ' -f2)
        element2=$(echo "$line" | cut -d' ' -f3)
        echo "$name:$element1,$element2"
done
IFS=$IFS_OLD

Note that is important to backup and restore original IFS value. As I said, is not optimal, the other answers are better, but this still being another option

Comments

0

Alternatively you could do:

#!/bin/bash

IFS=$'\n'                                                                   
for arg in $(cat food.txt); do                                           
     echo  $arg | awk '{ print $1":"$2","$3 }'                               
done 

or:

#!/bin/bash

awk '{ print $1":"$2","$3 }' food.txt

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.