3

I want to capture a command execution output like below:

$ o=$( git clone [email protected]:my-repo/demo.git )
Cloning into 'demo'...
remote: Counting objects: 176, done.
remote: Compressing objects: 100% (94/94), done.
remote: Total 176 (delta 84), reused 162 (delta 77)
Receiving objects: 100% (176/176), 32.98 KiB | 2.75 MiB/s, done.
Resolving deltas: 100% (84/84), done.

$ echo "$o"
    # Empty.

OK, just call me stupid, I haven't redirected the output. So:

$ o=$( git clone [email protected]:my-repo/demo.git 2>&1 )

Printed nothing in my console so I started being optimistic and continued to:

$ echo "$o"
Cloning into 'demo'...

And this is all. The other many lines printed by git were simply not stored into my humble o variable.

Then I tried to run the command in a subshell then redirect:

$ o=$( (git clone [email protected]:my-repo/demo.git) 2>&1 )

$ echo "$o"
Cloning into 'demo'...

What is it going on here?


Note: I tried to do my homework but posts like How do I store the output of a git command in a variable? just tell me exactly the first thing I've tried and failed. Many other links just repeat the same.

3
  • Does $ o=$( git clone [email protected]:my-repo/demo.git </dev/null 2>&1 | cat ) make any difference? ( That is an attempt to make git NOT have a console/terminal )
    – Hannu
    May 11, 2022 at 20:16
  • Hi @Hannu. It gives the same simplified output. A friend helped me and pointed that --progress solves the problem. I'll ask him to post an answer. Thanks!
    – j4x
    May 11, 2022 at 20:37
  • You know, you CAN post an answer to your own question! ;-)
    – Hannu
    May 11, 2022 at 20:41

1 Answer 1

4

The answer:

Add --progress to git clone to force printing progress.

Explanation:

OK, I made a lot of homework now.

Git documentation was quite subttle:

--progress Progress status is reported on the standard error stream by default when it is attached to a terminal, unless --quiet is specified. This flag forces progress status even if the standard error stream is not directed to a terminal.

So, since it was not printing progress, git, for any reason, considered that it was not connected to a terminal.

My naïve understanding tried to read this:

$ o=$( git clone [email protected]:my-repo/demo.git 2>&1 )

As if both stdout and stderr would map to the same pts so I ran some lsof in 3 different scenarios.

1: Just run command, without capturing

$ git clone [email protected]:my-repo/demo.git
$ bash -c '{ lsof -a -p $(pidof git)  -d0,1,2; }'
COMMAND   PID         USER   FD   TYPE DEVICE SIZE/OFF   NODE NAME
git     39542         j4x    0u   CHR  136,7      0t0     10 /dev/pts/7
git     39542         j4x    1w  FIFO   0,13      0t0 233734 /dev/pts/7
git     39542         j4x    2w  FIFO   0,13      0t0 233734 /dev/pts/7

2: Capture output, no redirection

$ o=$( git clone [email protected]:my-repo/demo.git )
~ $ bash -c '{ lsof -a -p $(pidof git)  -d0,1,2; }'
COMMAND   PID         USER   FD   TYPE DEVICE SIZE/OFF   NODE NAME
git     39859         j4x    0u   CHR  136,7      0t0     10 /dev/pts/7
git     39859         j4x    1w  FIFO   0,13      0t0 233734 /dev/pts/7
git     39859         j4x    2w  FIFO   0,13      0t0 233734 pipe

I sillily expected it to print the same way as "1:", but I was wrong and discovered that Bash uses a pipe to capture the process output and write it to a variable.

I didn't know that!

3: Capture output, redirect stderr

$ o=$( git clone [email protected]:my-repo/demo.git 2>&1 )
~ $ bash -c '{ lsof -a -p $(pidof git)  -d0,1,2; }'
COMMAND   PID         USER   FD   TYPE DEVICE SIZE/OFF   NODE NAME
git     40170         j4x    0u   CHR  136,7      0t0     10 /dev/pts/7
git     40170         j4x    1w  FIFO   0,13      0t0 233734 pipe
git     40170         j4x    2w  FIFO   0,13      0t0 233734 pipe

Now it all makes sense!

A pipe is not a tty (isatty()) and since git checks for a tty on stderr, progress won't print. You need to force it with --progress.

I hope this will be useful for anyone else.

References

0

You must log in to answer this question.

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