6

This should be an absurdly easy task: I want to take each line of the stdout of any old command, and use each to execute another command with it as an argument.

For example:

ls | grep foo | applycommand 'mv %s bar/'

Where this would take everything matching "foo" and move it to the bar/ directory.

(I feel a bit embarrassed asking for what is probably a ridiculously obvious solution.)

jameshfisher
  • 34,029
  • 31
  • 121
  • 167

3 Answers3

17

That program is called xargs.

ls | grep foo | xargs -I %s mv %s bar/
C. K. Young
  • 219,335
  • 46
  • 382
  • 435
  • 4
    xargs also lets you insert arguments in the middle of the command by specifying a substitution string. i.e. `xargs -I FILE mv FILE bar/` – Martin Mar 04 '10 at 01:28
  • @Martin: Thanks, I learnt something new! Will update my answer accordingly. – C. K. Young Mar 04 '10 at 01:38
  • 1
    also mv has a --target option. so just: | xargs mv --target=bar/ – pixelbeat Mar 04 '10 at 10:33
  • @pixelbeat: Thanks! I was trying to model my answer after what the OP wanted (with `%s` and all), but obviously in this case, your solution is even better. – C. K. Young Mar 04 '10 at 17:23
  • this doesn't execute a command for each line of stdin. It just bundles it together in one shot. The OP mentions this case only as an example. :\ – Karthick Dec 07 '13 at 01:50
  • @Karthick Correct, the question title is an [XY problem](http://meta.stackexchange.com/q/66377/13), so I solved the _real_ problem with my answer. – C. K. Young Dec 07 '13 at 02:10
7
ls | grep foo | while read FILE; do mv "$FILE" bar/; done

This particular operation could be done more simply, though:

mv *foo* bar/

Or for a recursive solution:

find -name '*foo*' -exec mv {} bar/ \;

In the find command {} will be replaced by the list of files that match.

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
  • Almost right: when doing `-exec ... +`, the `{}` must immediately precede the `+`. You can use the `;` form though: `-exec mv {} bar/ ';'`. – C. K. Young Mar 04 '10 at 01:25
0

for your case, do it simply like this.

for file in *foo*
do
   if [ -f "$file" ];then
      mv "$file" /destination
   fi
done

OR just mv it if you don't care about directories or files

mv *foo* /destination
ghostdog74
  • 327,991
  • 56
  • 259
  • 343