0

I currently am working with a matrix in bash. I have, say, a 2x4 matrix inside a file:

1    2    3    4
5    6    7    8

I have read from this file, and have stored all of these elements inside an array, such as:

my_arr={1 2 3 4 5 6 7 8}

Next, I piped my echo output so that the spaces change to tabs:

echo ${my_arr[@]} | tr ' ' '\t'
**output**: 
my_arr={1    2    3    4    5    6    7    8}

My question now is, I want to have a NEW-LINE after every four elements printed; in other words, is it possible for me to print out the array line-by-line, or row-by-row?

EDIT Here is what I have in my actual code:

array=()
cols #This contains number of columns

while read line1 <&3
do
    for i in $line1
    do
        array+=($i)
    done
done 3<$2

#Now, array has all the desired values. I need to print them out.

Here is what is the desired output:

1    2    3    4
5    6    7    8

Here is what is inside my array:

(1 2 3 4 5 6 7 8)
5
  • 1
    most likely converting 2D array to 1D and back to 2D is not the right approach. Best approach depends on what do you do with the elements... Commented Jan 29, 2019 at 19:34
  • 1
    As I commented on your previous question, {...} does not create an array. my_arry is just a string. You want my_arr=(1 2 3 4 5 6 7 8). Commented Jan 29, 2019 at 19:51
  • @chepner, you're right; however, that's not what I had originally put in my code. I have the correct array with the correct elements, I just need to print them out. Commented Jan 29, 2019 at 20:11
  • It's not at all clear what you have in your code. Post what you have, not some vague description using nonstandard pseudosyntax. Commented Jan 29, 2019 at 20:13
  • Ok, my apologies. I will edit this into my original post. Commented Jan 29, 2019 at 20:19

2 Answers 2

1

Try this:

printf '%s\t%s\t%s\t%s\n' "${my_arr[@]}"

The format string has four field specifiers (all %s -- just plain strings) separated by \t (tab) and ending with \n (newline), it'll print the array elements four at a time in that format.

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

6 Comments

Alright, that's a good idea; but I don't necessarily want to print them out 4 at a time. Some matrix may have 5 elements in a row, or 2. I just want to print the array out row by row.
@DarrelGulseth What defines a row? bash arrays are inherently one-dimensional, so any other organization (e.g. rows and columns) must come from somewhere else.
So basically, my file initially has a tab-separated array, with rows and cols (as I described in my post). I read those numbers, store them in an array, and want to print them back out exactly as they appear in the file - tab-separated, with rows and cols.
In that case, I agree with @karakfa's comment: by converting the input into a one-dimensional array, you're losing the structure of the data. You might be able to separately record the "shape" of the data as you read it, then use that to control output, but it really depends on what the actual goal is. If you're just going to write it back out, it might be better to leave it in text-line format, and do any necessary processing in that form. Maybe. It really depends on what all you're going to do with the data.
Gordon, one of the requirements of the project is that I have to write it out exactly as the file.
|
1

One possible (ugly) solution would be to store the size of the matrix in separate variables rows and cols. Please try the following:

set -f                      # prevent pathname expansion
array=()
rows=0
while read line1 <&3; do
    vec=($line1)            # split into elements
    cols=${#vec[@]}         # count of elements
    array+=(${vec[@]})
    rows=$((++rows))        # increment #rows
done 3<"$2"

# echo $rows $cols          # will be: 2 and 4

ifs_back="$IFS"             # back up IFS
IFS=$'\t'                   # set IFS to TAB
for ((i=0; i<rows; i++)); do
    j=$((i * cols))
    echo "${array[*]:$j:$cols}"
done
IFS="$ifs_back"             # restore IFS

The output:

1       2       3       4
5       6       7       8

Hope this helps.

2 Comments

I'd add set -f so the "split into elements" step does not also perform path expansion.
@glenn jackman thanks. Let me incorporate your suggestion in my code.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.