1

I have a script which makes use of multiple (i.e. positional) arguments from the command line, and within it a for loop that iterates through these arguments:

for i in "$@"; do 
...
done

This means that the arguments are populated into $i one by one, in the order that they're specified on the command line.

This seems to mean that it's impossible to select an argument that is not currently populating $i.

For example, in the following line in my script, I need to reference two different variables, which outside of a for loop would be 1ドル, 2ドル and 1ドル respectively:

ffmpeg -i "$i" -i "$i" ... "${i%.*}.mp4"

The script is executed in the following format:

./script.sh image.jpg *.flac

...but as I understand things, this problem would apply even to scripts that don't work with globs.

Is it possible to access positional arguments from a for loop as needed, rather than simply in the order they are specified in?

asked May 16, 2021 at 12:39
3
  • Please show some sample filenames, and the resulting ffmpeg invocations you want to run. Does the ... part involve any filenames? Commented May 16, 2021 at 12:46
  • 3
    Sounds like you want to create a variable with the value of 1ドル and then shift 1? You can also do array slicing on $@. See stackoverflow.com/questions/2701400/… Commented May 16, 2021 at 12:48
  • In bash you can select arguments out of order and in loops, by using indirect variable expansion, ${!i}, that expands to the content of the parameter whose name is stored in the i variable. Or for example ${@:3} for all arguments from the third to the end. See link. Commented May 16, 2021 at 13:55

1 Answer 1

0

I was able to figure this out in the end, although I don't consider this a perfect answer to the question because it doesn't satisfy the requirement of being able to reference the arguments from within the for loop.

In this sense I see this answer as more of a workaround, and I'm more than happy for someone else to come along and directly answer the question in a more comprehensive way. In any case, it's a workaround that works for my current script.

 img="1ドル"
 shift
 for i in "$@"; do
 ...
 ffmpeg -i "$img" -i "$i" ... "${i%.*}.mp4"
 ...
 done

As far as I can tell, this works by assigning the first argument to a variable $img outside of the for loop. Each instance of $img in the script is processed and then discarded by shift (which is the same as shift 1) before moving on to the next.

Once all $img arguments are removed from the arguments list, the for loop uses the $@ to loop through the remaining arguments as normal.

The script can then be called with something like:

./script.sh customimage.png *.flac

Or for multiple instances of the $img variable:

./script.sh customimage.png custom-image2.jpg *.flac
answered May 18, 2021 at 19:38

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.