1

I am writing a script to act on files given to the script using the $1 variable. What is the best way to loop through these files. At the moment I have hard coded the script using something like

for file in *.pdf
do 
   act on $file
done

However I would rather do this using the $1 variable Thanks Barry

1
  • you can do for file in $1 inside the code... to ensure, shell doesn't expand *, put that argument inside single quotes
    – user93868
    Commented Aug 9, 2015 at 12:10

2 Answers 2

4

$1 is simply the first parameter passed to your shell script. So if you have a script myscript and I call it like this:

myscript somefile

Then $1 will be somefile. If I call it like this:

myscript *

And there happen to be files in my current directory named:

foo bar baz

Then $1 will be foo. In either case, $1 only has a single value and there is nothing to loop over.

There are a couple of ways to loop over the arguments. The most common is:

for file in "$@"; do
  echo doing something with "$file"
done

Note that $@ is not the same as "$@"; the latter is a special construct that will correctly deal with filenames that contain spaces. You could also do something like:

while [ -n "$1" ]; do
  echo doing something with "$1"
  shift
done

Here, the shift command drops the first parameter, and $2 becomes $1 (and so on). This will loop as long as $1 is non-empty. You could also use $# for this (a variable which contains the number of command line arguments):

while [ $# -gt 0 ]; do
    echo arg: "$1"
    shift
done
3
  • Note that the canonical (and most portable) way to write for file in "$@" is for file do. Commented Aug 9, 2015 at 17:32
  • I have honestly never seen that syntax used in practice. Are you aware of any Bourne-ish shells that don't work properly given for file in "$@"?
    – larsks
    Commented Aug 9, 2015 at 17:40
  • It doesn't work properly in some versions of the Bourne shell when $# is 0. It doesn't work with the Bourne shell or pdksh when $IFS is empty (doesn't contain space for the Bourne shell). Commented Aug 9, 2015 at 17:46
1

If you do

script *.pdf

*.pdf is already expanded on the command line, and $1 will only refer to the first file

for file in $1

will therefore not do what you need. You could use

for file in "$@"

instead.

See the section Special Parameters in the man bash

1
  • Arrgghhh!  Don't say for file in $@; that will fail if arguments contain spaces or various other special characters.  Use for file in "$@", or just plain for file for short. Commented Aug 9, 2015 at 13:56

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .