9

Why doesn't this work?

find . -maxdepth 1 -type f -print0 | xargs -0 .

All I get is xargs: .: Permission denied.

Will Vousden
  • 32,488
  • 9
  • 84
  • 95

2 Answers2

18

When you run . file, you invoke a the shell builtin . . Your xargs variant tries to execute the current directory.
Even if that did invoke the builtin, that command runs in a subshell, so all the "sourcing" would be useless.

Use shell globbing and a loop for that:

for file in * ; do
  if [ -f "$file" ] ; then
    . "$file"
  fi
done
Mat
  • 202,337
  • 40
  • 393
  • 406
  • Clean solution; good to know that you cannot use builtins with `xargs` (and `find`'s `-exec` primary, for that matter). Here's the equivalent one-liner: `for f in *; do [[ -f "$f" ]] && . "$f"; done` – mklement0 Sep 14 '12 at 17:18
  • If you still want to use find: `while IFS= read -r -d $'\0' f; do echo "$f"; done < <(find . -maxdepth 1 -type f -print0)` – mattalxndr Dec 11 '21 at 05:09
1

@Mat's solution is the cleanest, but in case you're interested in some bash-fu for the fun of it, the following solution, based on the original find command, works, too:

eval $(find . -maxdepth 1 -type f -exec echo . \'{}\'';' \;)
  • find is used with -exec to construct a sourcing command for each file found, e.g. . './foo';. Note the escaped single quotes to ensure that filenames with special chars. are handled properly.
  • find will return a newline-separated list of sourcing commands; by using command substitution ($()) without double-quoting, the shell folds these lines into a single line using a space each as the separator.
  • Finally, eval executes the full list of sourcing commands in the context of the current shell (verified on OS X 10.8.1).

NOTE: One potential problem with this solution is that the command string can get large - possibly too large - with many files and/or long filenames present.

mklement0
  • 382,024
  • 64
  • 607
  • 775