Tas
Tas

Reputation: 115

Concatenating remaining arguments beyond the first N in bash

I did not have to write any bash script before. Here is what I need to do.

My script will be run with a set of string arguments. Number of stings will be more than 8. I will have to concatenate strings 9 and onward and make a single string from those. Like this...

myscript s1 s2 s3 s4 s5 s6 s7 s8 s9 s10....(total unknown)

in the script, I need to do this...

new string = s9 + s10 + ...

I am trying something like this...(from web search).

 array="${@}"
 tLen=${#array[@]}
 # use for loop  to read string beyond 9
 for (( i=8; i<${tLen}; i++ ));
 do
   echo ${array[$i]}  --> just to show string beyond 9
 done

Not working. It prints out if i=0. Here is my input.

./tastest 1 2 3 4 5 6 7 8 A B C

I am expecting A B C to be printed. Finally I will have to make ABC.

Can anyone help?

Upvotes: 3

Views: 2635

Answers (3)

mklement0
mklement0

Reputation: 439477

# Create a 0-index-based copy of the array of input arguments.
# (You could, however, work with the 1-based pseudo array $@ directly.)
array=( "${@}" )

# Print a concatenation of all input arguments starting with the 9th
# (starting at 0-based index 8), which are passed *individually* to
# `printf`, due to use of `@` to reference the array [slice]
# `%s` as the `printf` format then joins the elements with no separator 
# (and no trailing \n).
printf '%s' "${array[@]:8}"

# Alternative: Print the elements separated with a space:
# Note that using `*` instead of `@` causes the array [slice] to be expanded
# to a *single* string using the first char. in `$IFS` as the separator,
# which is a space by default; here you could add a trailing \n by using
# '%s\n' as the `printf` format string.
printf '%s' "${array[*]:8}"

Note that array="${@}" does not create an array - it simply creates a string scalar comprising the concatenation of the input array's elements (invariably) separated by a space each; to create an array, you must enclose it in (...).

To create a space-separated single string from the arguments starting with the 9th enclosed in double quotes, as you request in your follow-up question, use the following:

printf -v var10 '"%s"' "${array[*]:8}"

With the last sample call from your question $var10 will then contain literal "A B C", including the double quotes.


As for assigning arguments 1 through 8 to individual variables.:

Jonathan Leffler's helpful answer shows how to save the first 8 arguments in individual variables.

Here's an algorithmic alternative that creates individual variables based on a given name prefix and sequence number:

n=8  # how many arguments to assign to individual variables

# Create n 'var<i>' variables capturing the first n arguments.
i=0  # variable sequence number
for val in "${array[@]:0:n}"; do
  declare "var$((++i))=$val" # create $var<i>, starting with index 1
done

# Print the variables created and their values, using variable indirection.
printf "\nvar<i> variables:\n"
for varName in "${!var@}"; do
  printf '%s\n' "$varName=${!varName}"
done

Upvotes: 3

Jonathan Leffler
Jonathan Leffler

Reputation: 754590

It should be a lot simpler than the looping in the question:

shift 8
echo "$*"

Lose arguments 1-8; print all the other arguments as a single string with a single space separating arguments (and spaces within arguments preserved).

Or, if you need it in a variable, then:

nine_onwards="$*"

Or if you can't throw away the first 8 arguments in the main shell process:

nine_onwards="$(shift 8; echo "$*")"

You can check that there are at least 9 arguments, of course, complaining if there aren't. Or you can accept an empty string instead — with no error.

And if the arguments must be concatenated with no space (as in the amendment to the question), then you have to juggle with $IFS:

nine_onwards="$(shift 8; IFS=""; echo "$*")"

If I'm interpreting the comments from below this answer correctly, then you want to save the first 8 arguments in 8 separate simple (non-array) variables, and then arguments 9 onwards in another simple variable with no spaces between the argument values.

That's trivially doable:

var1="$1"
var2="$2"
var3="$3"
var4="$4"
var5="$5"
var6="$6"
var7="$7"
var8="$8"
var9="$(shift 8; IFS=""; echo "$*")"

The names don't have to be as closely related as those are. You could use:

teflon="$1"
absinthe="$2"
astronomy="$3"
lobster="$4"
darkest_peru="$5"
mp="$6"
culinary="$7"
dogma="$8"
concatenation="$(shift 8; IFS=""; echo "$*")"

You don't have to do them in that order, either; any sequence (permutation) will do nicely.

Note, too, that in the question, you have:

array="${@}"

Despite the name, that creates a simple variable containing the arguments. To create an array, you must use parentheses like this, where the spaces are optional:

array=( "$@" )

Upvotes: 9

lostbard
lostbard

Reputation: 5220

You are close - something like this would work:

array=( ${*} )
# use for loop  to read string beyond 9
for (( i=8; i<${#array[*]}; i++ ));
do
   echo -n ${array[$i]}
done

Upvotes: -1

Related Questions