1

I'm trying to write a bash line that will look at all the subdirectories in my current folder and tell me if any do NOT contain a ".git". Pseudo:

for subdir in currentdir
  if .git does not exist
    print subdir

Here's the one-liner I'm trying, which isn't working and seems to print all the subdirectories:

find . -maxdepth 1 -type d -execdir $SHELL -c '[ ! -d ".git" ] && echo "not git repo:" {}' $SHELL -c '{}' ';'

I've found some solutions that let me print all subdirectories that HAVE a .git, like this one -- I'm trying to do the opposite.

What am I doing wrong? Is this possible?

2 Answers 2

5

First, the -execdir command looks wonky (2x $SHELL -c?):

$SHELL -c '[ ! -d ".git" ] && echo "not git repo:" {}' $SHELL -c '{}' ';'

Also, -execdir runs the command in the directory containing the matched entity, (so the parent directory of the directory that it is checking right now), which is . for all subdirectories. The test is run in the wrong directory. And:

  • You shouldn't reuse {} in exec/-execdir commands.
  • There's no reason to use $SHELL. That's the user's login shell, and it doesn't have any special significance for usage in scripts and such. Just use sh, or bash or ksh if those are your shells of choice, directly.

This might work:

find . -maxdepth 1 -type d -exec sh -c '! [ -d "$1/.git" ] && echo "not git repo: $1"' _ {} \;

The -exec command checks for the existence of .git in the argument passed in, which is each subdirectory in turn. You might also want to use -mindepth 1 to exclude the current directory:

find . -maxdepth 1 -mindepth 1 -type d -exec sh -c '! [ -d "$1/.git" ] && echo "not git repo: $1"' _ {} \;

Or, just using bash, enabling dotglob to match hidden directories:

(shopt -s dotglob; for d in ./*/; do [[ -d $d/.git ]] || echo "not git repo: $d"; done)
2
  • Thank you! I found the $SHELL bit (somewhere...) as a solution to "you can't do test using exec" but as these answers prove, that appears to have been incorrect. Can you explain why I shouldn't reuse {} in exec/execdir? Jun 18, 2019 at 11:52
  • 1
    It may not work correctly depending on the version of find: stackoverflow.com/a/12965441/2072269
    – muru
    Jun 18, 2019 at 11:56
2

muru’s answer explains what’s wrong with your approach. The answers to the question you referred to suggest a simpler approach with no shell involved:

find . -maxdepth 1 -type d -exec test '!' -e '{}/.git' ';' -printf "not git repo: %p\n"

(assuming your find supports -printf), or

find . -maxdepth 1 -type d -exec test '!' -e '{}/.git' ';' -print

This negates the test run using -exec test to get the desired result.

1
  • Thank you! The negated test is a much simpler approach as well. Jun 18, 2019 at 11:54

You must log in to answer this question.

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