You are not logged in.

#1 2011-04-04 22:33:25

fredre
Member
Registered: 2009-12-18
Posts: 45

a couple easy bash questions (arrays mostly)

I'm new to bash (my only programming background is a single class in C), but am working on a script right now and have run into some issues with it.

1) I have a text file containing a long list of (space separated) numbers, which I would like the script to read and place into a one dimensional array. So I could run the script with something like:

$ ./script_name text_file.txt

There will be 200 elements in the array. What's the best way to do this (read the text file into the array)?

2) I'm trying to create a new array (array2), in which each element is calculated from the elements in different array. As a simple test case of this I wrote:

array1=( 0 1 2 3 4 5 6 7 8 9 )
array2=( 0 0 0 0 0 0 0 0 0 0 )
arrayA=( 0 1 2 3 4 5 6 7 8 9 )

const1=10
constA=5

for((i=0;i<10;i++))
do
    array2[$i]+="bc 'scale=20;${array1[$i]}-${arrayA[$i]}*$const1/$constA'"        # fix this
done

However the line evaluating array2 doesn't work right. I think I need single quotes instead of double quotes around the bc command. The problem then is when the second set of quotes open up, it reads it as closing the first set. What's the correct way to do this?

Offline

#2 2011-04-04 23:54:21

fukawi2
Ex-Administratorino
From: .vic.au
Registered: 2007-09-28
Posts: 6,231
Website

Re: a couple easy bash questions (arrays mostly)

for ((i=0;i<10;i++))
do
    array2[$i]+=$(bc "scale=20;${array1[$i]}-${arrayA[$i]}*$const1/$constA")
done

The double quotes treat it as a string, not an external executable to run and return the result. Note the change of the inside quotes to double quotes. Single quotes won't allow the variables to be interpolated into their corresponding values and will pass literal '${array...}' strings to bc instead.

Offline

#3 2011-04-05 00:18:50

juster
Forum Fellow
Registered: 2008-10-07
Posts: 195

Re: a couple easy bash questions (arrays mostly)

From what I remember, bc only reads from standard input, not command line arguments. For example, like this:

echo 2+2 | bc

Offline

#4 2011-04-05 05:24:59

rockin turtle
Member
From: Montana, USA
Registered: 2009-10-22
Posts: 227

Re: a couple easy bash questions (arrays mostly)

I'm not sure why you are using bc, bash has arithmitic capabilities built in.  Is the following the equivalent of what your test script was trying to do?

#!/bin/bash

array1=( 0 1 2 3 4 5 6 7 8 9 )
arrayA=( 0 1 2 3 4 5 6 7 8 9 )

const1=10
constA=5

for((i=0;i<10;i++))
do
    (( array2[$i]=${array1[$i]}-${arrayA[$i]}*$const1/$constA ))
    echo ${array2[$i]}
done

Note the use of double parenthises (( ... )).  This is one way where bash "does" arithmetic. (There are other ways.)

Reading data from a file can be a little tricky.  The following assumes that your data is in a file named 'foo'.

If each data point is on a separate line, the following will read each data value in turn into the variable 'dp':

#!/bin/bash

i=0
while read dp
do
    (( array[$i]=$dp*2 ))
    (( i++ ))
done < foo

If each data point is separated by whitespace (spaces, tabs or newlines), the following will work:

#!/bin/bash

i=0
data=$(cat foo)

for dp in $data
do
    (( array[$i]=$dp*2 ))
    (( i++ ))
done

Edit: I see I didn't actually answer your question.  To read a data file into an array (each data point is separated by whitespace) do:

declare -a x=$(cat foo)

should do it.

Last edited by rockin turtle (2011-04-05 05:35:41)

Offline

#5 2011-04-05 07:58:43

portix
Member
Registered: 2009-01-13
Posts: 757

Re: a couple easy bash questions (arrays mostly)

For reading lines of a file into an array you can use mapfile

mapfile array < filename

and space-seperated values can be read into an array using

array=( $(< filename) ) 

Edit: i just realized that the second will work for both, space and newline seperated  data.

Last edited by portix (2011-04-05 09:23:43)

Offline

#6 2011-04-19 15:08:41

freak
Member
Registered: 2009-04-15
Posts: 17

Re: a couple easy bash questions (arrays mostly)

portix wrote:

For reading lines of a file into an array you can use mapfile

mapfile array < filename

and space-seperated values can be read into an array using

array=( $(< filename) ) 

Edit: i just realized that the second will work for both, space and newline seperated  data.

It will, to an extent. you would have to sent IFS=$'\n', and set -f, in order to keep glob characters from expanding to filenames.

The preferred way is with mapfile, or a while read loop

while read -r line; do
  array+=("$line")
done < filename

for space separated, you can use the nice read one liner:

read -rd '' -a array < filename

Last edited by freak (2011-04-19 15:10:59)

Offline

Board footer

Powered by FluxBB