0

I have a string with 3000 elements (NOT in series) in bash,

sections='1 2 4 ... 3000'

I am trying to split this string into x chunks of length n. I want x to be typically between 3-10. Each chunk may not be of the same length.

Each chunk is the input to a job.

Looking at https://unix.stackexchange.com/questions/122499/bash-split-a-list-of-files and using bash arrays, my first attempt looks like this:

#! /bin/bash

nArgs=10
nChunkSize=10

z="0 1 2 .. 1--"

zs=(${z// / })
echo ${zs[@]}

for i in $nArgs; do
  echo "Creating argument: "$i
  startItem=$i*$nChunkSize
  zArg[$i] = ${zs[@]:($startItem:$chunkSize}
done

echo "Resulting args"

for i in $nArgs; do
 echo "Argument"${zArgs[$1]}
done   

The above is far from working I'm afraid. Any pointers on the ${zs[@]:($startItem:$chunkSize} syntax?

For an input of 13 elements:

z='0 1 2 3 4 5 6 7 8 10 11 12 15'

nChunks=3 and nArgs=4 I would like to obtain an array with 3 elements, zs with content

zs[0] = '0 1 2 3'
zs[1] = '4 5 6 7'
zs[2] = '8 10 11 12 15'

Each zs will be used as arguments to subsequent jobs.

2
  • Please add sample input and your desired output for that sample input to your question. Commented Jan 27, 2017 at 20:27
  • 1
    Use shellcheck.net to identify and correct the more glaring errors. Commented Jan 27, 2017 at 20:36

1 Answer 1

2

First note: This is a bad idea. It won't work reliably with arbitrary (non-numeric) contents, as bash doesn't have support for nested arrays.


output=( )

sections_str='1 2 4 5 6 7 8 9 10 11 12 13 14 15 16 3000'
batch_size=4
read -r -a sections <<<"$sections_str"
for ((i=0; i<${#sections[@]}; i+=batch_size)); do
  current_pieces=( "${sections[@]:i:batch_size}" )
  output+=( "${current_pieces[*]}" )
done

declare -p output # to view your output

Notes:

  • zs=( $z ) is buggy. For example, any * inside your list will be replaced with a list of filenames in the current directory. Use read -a to read into an array in a reliable way that doesn't depend on shell configuration other than IFS (which can be controlled scoped to just that one line with IFS=' ' read -r -a).
  • ${array[@]:start:count} expands to up to count items from your array, starting at position start.
Sign up to request clarification or add additional context in comments.

1 Comment

This seem to do it for me! I will not have any non-numeric content. Thanks!!

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.