Looping Over Arguments Passed to a Script

Problem

You want to take some set of actions for a given list of arguments. You could write your shell script to do that for one argument and use $1 to reference the parameter. But what if you’d like to do this for a whole bunch of files? You would like to be able to invoke your script like this:

actall *.txt

knowing that the shell will pattern match and build a list of filenames that match the *.txt pattern (any filename ending with .txt).

Solution

Use the shell special variable $* to refer to all of your arguments, and use that in a for loop like this:

#!/usr/bin/env bash
# cookbook filename: chmod_all.1
#
# change permissions on a bunch of files
#
for FN in $*
do
    echo changing $FN
    chmod 0750 $FN
done

Discussion

The variable $FN is our choice; we could have used any shell variable name we wanted there. The $* refers to all the arguments supplied on the command line. For example, if the user types:

$ ./actall abc.txt another.txt allmynotes.txt

the script will be invoked with $1 equal to abc.txt and $2 equal to another.txt and $3 equal to allmynotes.txt, but $* will be equal to the entire list. In other words, after the shell has substituted the list for $* in the for statement, it will be as if the script had read:

for FN in abc.txt another.txt allmynotes.txt
do
  echo changing $FN
  chmod 0750 $FN
done

The for loop will take one value at a time from the list, assign it to the variable $FN and proceed through the list of statements between the do and the ...

Get bash Cookbook now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.