Search code examples
zsh

zsh command line processing - separating the last arguments from the previous ones


I am writing a zsh script, which is invoked with a variable number of arguments, such as

 scriptname a b c d filename

Inside the script, I want first to loop over the arguments (except the last one) and process them, and finally do something with the processed data and the last argument (filename).

I got this working, but am not entirely happy with my solution. Here is what I came up with (where process and apply are some other scripts not relevant to my problem):

#!/bin/zsh
set -u
x=""
filename=$@[-1]
# Process initial arguments
for ((i=1; i<$#; i++))
do
  x+=$(process ${@[$i]}) 
done
apply $x $filename

I find the counting loop too cumbersome. If filename where the first argument, I would do a shift and then could simply loop over the arguments, after having saved the filename. However I want to keep the filename as the last argument (for consistency with other tools).

Any ideas how to write this neatly without counting loop?


Solution

  • You can slice off the last argument from the original list and save them into an array, if thats an option

    args=("${@:1:$# -1}")
    for arg in "${args[@]}"; do          # iterate over all, except the last
      printf '%s\n' "$arg"
    done
    

    Using the array as a placeholder is optional as you can iterate over the arguments slice directly i.e. for arg in "${@:1:$# -1}"; do. The syntax is even available in bash also.


    As pointed out by chepner's comment, you could use a zsh specifc syntax as

    for arg in $@[1,-2]; do
      printf '%s\n' "$arg"
    done