Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Run expand on find results

I'm trying to run the expand shell command on all files found by a find command. I've tried -exec and xargs but both failed. Can anyone explain me why? I'm on a mac for the record.


find . -name "*.php" -exec expand -t 4 {} > {} \;

This just creates a file {} with all the output instead of overwriting each individual found file itself.


find . -name "*.php" -print0 | xargs -0 -I expand -t 4 {} > {}

And this just outputs

4 {}
xargs: 4: No such file or directory
like image 896
ChrisR Avatar asked Jul 13 '11 10:07

ChrisR


2 Answers

Your command does not work for two reasons.

  1. The output redirection is done by the shell and not by find. That means that the shell will redirect finds output into the file {}.
  2. The redirection would occur immediately. That means that the file will be written even before it is read by the expand command. So it's not possible to redirect a command's output into the input file.

Unfortunately expand doesn't allow to write it's output into a file. So you have to use output redirection. If you use bash you could define a function that executes expand, redirects the output into a temporary file and move the temporary file back over the original file. The problem is that find will run a new shell to execute the expand command.

But there is a solution:

expand_func () {
  expand -t 4 "$1" > "$1.tmp"
  mv "$1.tmp" "$1"
}

export -f expand_func

find . -name \*.php -exec bash -c 'expand_func {}' \;

You are exporting the function expand_func to sub shells using export -f. And you don't execute expand itself using find -exec but you execute a new bash that executes the exported expand_func.

like image 171
bmk Avatar answered Sep 22 '22 06:09

bmk


'expand' isn't really worth the trouble. You can just use sed instead:

find . -name "*.php" | xargs sed -i -e 's/\t/    /g'
like image 37
kliteyn Avatar answered Sep 22 '22 06:09

kliteyn