Correct usage of find and while-read loop in different formats?

Viewed 46

After reading multiple anwers on stackoverflow I came up with the following solution to read directory paths from find's output:

find "$searchdir" -type d -execdir test -d {}/.git \; -prune -print0 | while read -r -d $'\0' dir; do
    # do stuff
done

However, most sources recommend something like the following approach:

while IFS= read -r -d '' file; do
  some command "$file"
done < <(find . -type f -name '*.mp3' -print0)

Why are they using process substitution? Does this change anything about the whole process or is it just an other way to do the same thing?

Is the read argument -d '' different from -d $'\0' or again the same thing? Does empty string always contain at least \0 so the bash specific $'' syntax is completely unnecessary?

I also tried doing it directly in find -exec/-execdir by passing it multiple times and failed. Maybe filtering and testing can be done in one command?

non working example:

find "$repositories_root_dir" -type d -execdir test -d {}/.git \; -prune -execdir sh -c "if git ls-remote --exit-code . \"origin/${target_branch_name}\" &> /dev/null; then echo \"Found branch '${target_branch_name}' in {}\"; git checkout \"${target_branch_name}\"; fi" \;

Sources:

1 Answers

In your non-working example, if you test the existence of a .git sub-directory to process only git clones and discard the other directories, then you should probably not prune because it does the exact opposite: skip only git clones.

Moreover, when using -execdir sh -c SCRIPT, you should pass positional parameters to your script instead of trying to embed the current directory name in the script with {}, which is not portable. And you could do the same for the branch name. Note that the directory name is not needed for what you try to accomplish in each git clone, because your script is executed from there.

Try this, maybe:

find "$repositories_root_dir" -type d -name '.git' -execdir sh -c '
  if git ls-remote --exit-code . "origin/$1" &> /dev/null; then
    printf "Found branch %s in " "$1"; pwd
    echo git checkout "$1"
  fi' _ "$target_branch_name" \;

(_ is assigned to positional parameter $0). Remove the echo if the result looks correct.

Related