1

i'm learning bash on linux, i found script for "while loop reading from a file" and modified a bit as below, i 'm trying to read a list file containing all the git repos, and i wanted to iterate all those git repos and run git status for all of them:

while read line; 
    do  echo $line;
        cd $line;
        git status;
done < repo.list

this part works fine, i can see status of each repo in stdout, but when i tried to write output to another file, it doesn't work:

while read line; 
    do  echo $line;
        cd $line;
        git status;
done < repo.list
> status.txt

how can i consolidate all git status output and write to a file? thanks!

ilkkachu
  • 138,973
jerry
  • 143
  • i'm new to this, can this be done without loop? i googled a bit and found this find mydir -name .git -type d , i write this to repo.list file – jerry Mar 04 '21 at 10:51

3 Answers3

4

With the redirection on a new line, it applies to the empty command; to fix this, place it on the done line:

while IFS= read -r line; 
    do  echo "$line"
        (cd "$line"; git status)
done < repo.list > status.txt

See also Understanding IFS and Understanding "IFS= read -r line" and the linked questions for information on subtleties affecting read.

Using a subshell for the cd and git status together means that the changing directories won’t affect subsequent iterations of the loop, or even the shell running the while.

Stephen Kitt
  • 434,908
3

i googled a bit and found this find mydir -name .git -type d

You could do something like this, maybe:

find . -name '.git' -type d -print -execdir git status \;

That would look for directories called .git, then for each, print the path to it, and go to the containing directory and run git status there. (find -exec would run the command in the original directory, -execdir goes to where the matching file/directory was.)

You get output like

./this-stuff/.git
On branch master
Your branch is up to date with 'origin/master'.

and it would need some more trickery to post-process the .git out of it. (E.g. -exec sh -c 'echo "${1%.git}"' sh {} \; instead of the -print.)

In general, find may work if you want to do something on all files/directories in some subtree, matching some condition that is evident from the metadata of the files. But if you have an existing list, a shell loop is as good a way as any to process it.

ilkkachu
  • 138,973
  • 1
    -printf '%h\n' would do the trick with GNU find. – Stephen Kitt Mar 04 '21 at 11:10
  • This answer doesn't show how to redirect the output, which is what the question is about. – Barmar Mar 04 '21 at 17:10
  • @Barmar, You are absolutely correct. The answer says exactly nothing at all about redirections. – ilkkachu Mar 04 '21 at 17:11
  • wow, thanks a lot, i'm learning new stuff, i didn't know this could be done with 1 line of command, i added > status.txt, it output paths and status of all git reps – jerry Mar 05 '21 at 02:47
1

Your issue is a simple typo as explained by Stephen already.

The task of running git status in each directory given by the line in a file could be done using xargs as well:

xargs -I {} git -C {} status <repo.list >status.txt

This calls git -C {} status for each line in the file repo.list. The {} will be replaced by the line read from the file, and the -C option to git will make the utility use an alternative directory for the status sub-command in place of the current one.

To have the repository path outputted before each call to git status, call a sh -c script:

xargs -I {} sh -c 'printf "REPOSITORY: %s\n" "$1"; git -C "$1" status' sh {} <repo.list >status.txt

Inside the sh -c script, the repository pathname is given by "$1".

Kusalananda
  • 333,661