Alex Rivera | Logout

bash "map" equivalent: run command on each file

Asked 2010-04-14T19:25:11.217
16

I often have a command that processes one file, and I want to run it on every file in a directory. Is there any built-in way to do this?

For example, say I have a program data which outputs an important number about a file:

./data foo
137
./data bar
42

I want to run it on every file in the directory in some manner like this:

map data `ls *`
ls * | map data

to yield output like this:

foo: 137
bar: 42
Edit
Report

2 Answers

9

If you just want to run a command on every file you can do this:

for i in *; do data "$i"; done

If you also wish to display the filename that it is currently working on then you could use this:

for i in *; do echo -n "$i: "; data "$i"; done
answered 2010-04-14T19:27:20.700
3

The common methods are:

ls * | while read file; do data "$file"; done

for file in *; do data "$file"; done

The second can run into problems if you have whitespace in filenames; in that case you'd probably want to make sure it runs in a subshell, and set IFS:

( IFS=$'\n'; for file in *; do data "$file"; done )

You can easily wrap the first one up in a script:

#!/bin/bash
# map.bash

while read file; do
    "$1" "$file"
done

which can be executed as you requested - just be careful never to accidentally execute anything dumb with it. The benefit of using a looping construct is that you can easily place multiple commands inside it as part of a one-liner, unlike xargs where you'll have to place them in an executable script for it to run.

Of course, you can also just use the utility xargs:

find -maxdepth 0 * | xargs -n 1 data

Note that you should make sure indicators are turned off (ls --indicator-style=none) if you normally use them, or the @ appended to symlinks will turn them into nonexistent filenames.

answered 2010-04-14T19:30:18.193

Your Answer