0

I'm trying to cycle through an unknown number of arguments given to a bash script (or function within), to effectively handle the odds ($1, $3, etc.) and evens ($2, $4, etc.) in different ways.

I know I can get the number of arguments using $#, and the arguments themselves using $@, and of course echo $1 $2 or printf '%s\n' "$1" both work. What I'm needing to do is effectively echo the odds echo $1 $3 $5 ... with an unknown number, then separately deal with the evens, and count the characters of these individually also, so need to get these programmatically if at all possible.

Note: Some of the input will have spaces, but where will always have quotes. An example would be 1 "This one" "Another one" "and another" "last one".

I've tried (these are just to get output for brevity):

Putting $@ into an array of itself, in both for and while arrangements (understanding this zero indexes the array):

indexedarray="$@"
for i in {0..$#..2}; do #This in itself creates an error ({0..5..2}: syntax error: operand expected (error token is "{0..5..2}")).
  echo -n "${indexedarray[$i]}
done

This produces empty output:

i=0
while [ $i -lt $# ]; do
    echo ${INDEXEDARRAY[i]}
    ((i+2))
done

And the (somewhat) obvious foibles inside of for or while loops:

  echo "${$@[$i]}"
  echo $"${i}"

None of which work.

Any ideas on how I might improve this, and get the output I need?

ScottC
  • 148
  • 1
  • 5
  • 4
    `indexedarray="$@"` does not define an array but a string. Try `indexedarray=("$@")` instead. – Socowi Jun 14 '20 at 12:19
  • `{0..$#}` does not work because braces are expanded before variables, see [this question](https://stackoverflow.com/q/19432753/6770384). For examples on how to access command line argument without `$1`, `$2`, … see [this question](https://stackoverflow.com/q/255898/6770384) or [this question](https://stackoverflow.com/q/37053780/6770384). – Socowi Jun 14 '20 at 12:24
  • @Socowi - that was it, sort of. I'd tried `($@)` in the for loop, but neglected to in the while loop. Though curiously `(((i++))` works, but `((i+2))` goes into an infinite loop, and only displays `$1`. I'll have a look and see if I can modify any of the others from the other questions, though. Thanks for that! – ScottC Jun 14 '20 at 12:40
  • 1
    `((i+2))` computes a result and discards it. You probably wanted to write `((i+=2))`. Without the assignment `i` keeps its initial value, hence the endless loop. – Socowi Jun 14 '20 at 12:44
  • Yes, that's right! My c-style arithmetic is slowly coming back to me. – ScottC Jun 14 '20 at 12:53

1 Answers1

4

It seems like you want to print every other argument. Here are some ways to do it.

My favorite (despite being a bit hacky):

printf '%s\n%.0s' "$@"

The next logical approach

while (($# > 0)); do
  echo "$1"
  shift
  shift
  # `shift 2` won't shift if there is only one argument left
done

And the most general approach

a=("$@")
for ((i=0; i<$#; i+=2)); do
  echo "${a[i]}"
done

Socowi
  • 25,550
  • 3
  • 32
  • 54
  • 1
    So I discovered from [this answer](https://stackoverflow.com/a/37054146/7831034), there's also the `${!i}` designation, which suits my needs perfectly, without having to define a seperate array. – ScottC Jun 14 '20 at 12:58
  • 3
    `while x=$1 && shift; do echo "$x"; shift; done` would work as well. The `shift` in the condition doubles as the way to move past the current argument as well as the test for if `x` was assigned a value at all. The `shift` in the body continues to skip an argument. – chepner Jun 14 '20 at 13:32
  • `for _; do echo "$1"; shift; shift; done` work as well. – Léa Gris Jun 15 '20 at 01:07