22

I have following output from git status, how do I grep for everything after Untracked files:

[alexus@wcmisdlin02 Test]$ git status 
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached <file>..." to unstage)
#
#   new file:   app/.gitignore
#   new file:   app/app.iml
#   new file:   app/build.gradle
#   new file:   app/proguard-rules.pro
#   new file:   app/src/androidTest/java/org/alexus/test/ApplicationTest.java
#   new file:   app/src/main/AndroidManifest.xml
#   new file:   app/src/main/java/org/alexus/test/MainActivity.java
#   new file:   app/src/main/res/layout/activity_main.xml
#   new file:   app/src/main/res/menu/menu_main.xml
#   new file:   app/src/main/res/mipmap-hdpi/ic_launcher.png
#   new file:   app/src/main/res/mipmap-mdpi/ic_launcher.png
#   new file:   app/src/main/res/mipmap-xhdpi/ic_launcher.png
#   new file:   app/src/main/res/mipmap-xxhdpi/ic_launcher.png
#   new file:   app/src/main/res/values-w820dp/dimens.xml
#   new file:   app/src/main/res/values/dimens.xml
#   new file:   app/src/main/res/values/strings.xml
#   new file:   app/src/main/res/values/styles.xml
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#   .gitignore
#   .idea/
#   Test.iml
#   build.gradle
#   gradle.properties
#   gradle/
#   gradlew
#   gradlew.bat
#   settings.gradle
[alexus@wcmisdlin02 Test]$ 

Like this, but without specifying number of lines, like the -A parameter in GNU grep:

[alexus@wcmisdlin02 Test]$ git status | grep -A100 'Untracked files'
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#   .gitignore
#   .idea/
#   Test.iml
#   build.gradle
#   gradle.properties
#   gradle/
#   gradlew
#   gradlew.bat
#   settings.gradle
[alexus@wcmisdlin02 Test]$ 

Is there a way to do it?

[alexus@wcmisdlin02 Test]$ grep --version
grep (GNU grep) 2.20
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by Mike Haertel and others, see <http://git.sv.gnu.org/cgit/grep.git/tree/AUTHORS>.
[alexus@wcmisdlin02 Test]$ 
2
  • Why can't you use -A with a large enough number as argument?
    – kasperd
    May 29, 2015 at 17:17
  • For this example however, you should not "grep after", it would be easier & less error prone to use git's "porcelain" mode: git status --porcelain | grep '^??' | cut -f2 -d' '
    – conny
    Aug 29, 2021 at 20:32

6 Answers 6

26

With GNU grep (tested with version 2.6.3):

git status | grep -Pzo '.*Untracked files(.*\n)*'

Uses -P for perl regular expressions, -z to also match newline with \n and -o to only print what matches the pattern.

The regex explained:

First we match any character (.) zero or multiple times (*) until an occurence of the string Untracked files. Now, the part inside the brackets (.*\n) matches any character except a newline (.) zero or multiple times (*) followed by a newline (\n). And all that (that's inside the backets) can occure zero or multiple times; that's the meaning of the last *. It should now match all other lines, after the first occurence of Untracked files.

9
  • 3
    An answer that actually uses grep, I'm impressed!
    – Hyppy
    May 29, 2015 at 16:35
  • @hyppy me too) and then again, match also evolved Perl regex)
    – alexus
    May 29, 2015 at 16:38
  • 1
    This doesn't work well if the input has a lot of lines. I tested it on Ubuntu 14.04, and if the match is longer than about 8000 lines, it segfaults.
    – kasperd
    May 29, 2015 at 17:49
  • 2
    @kasperd I think with 8000+ lines, grep isn't the right tool. But otherwise this question is (i think) for the user to see only the relevant output, what you obviously don't have at 8000+ lines, greped or not.
    – chaos
    May 29, 2015 at 17:53
  • 1
    @chaos I also tested grep -A999999999 'Untracked files' with 1000000 lines before the match and 1000000 lines after the match. That approach worked just fine. So grep can do it. The problem with your approach is that you are forcing it to perform a single match on the entire file rather than on individual lines.
    – kasperd
    May 29, 2015 at 17:58
18

If you don't mind using sed, here is a possible solution

git status | sed -n -e '/Untracked files/,$p'
1
  • This has the advantage that it works with plain UNIX grep and sed, while the accepted solution requires GNU grep. May 29, 2015 at 20:11
8

I would use awk for this:

git status | awk '/Untracked files/,0'

This /Untracked files/,0 is a range exression. It evaluates to True from the first time Untracked files and until 0 evaluates to True. Since this never happens, it prints the rest of the file.

Note that awk's behaviour to a True is to print the current record (line, normally), that's why we don't have to explicitly call print.

3

You may try:

git status | grep -A99 Untracked

where -A would print lines of trailing context after the match.

Alternatively use more or less, for example:

git status | less +/Untracked

For scripting purposes, I'd use ex/vi:

git status | ex -s +"/Untracked/norm d1G" +%p -cq! /dev/stdin

To include line with Untracked files, use kd1G instead of d1G.

Or without piping and /dev/stdin, the syntax would be: ex ... <(git status).

3
  • I did included -A in my original question, but I do like more +/Untracked part of your answer.
    – alexus
    May 29, 2015 at 16:37
  • @alexus If you're writing a script, I've added the version with ex which is equivalent to vi -e.
    – kenorb
    May 29, 2015 at 16:47
  • thank you, I believe more/less is very useful)
    – alexus
    May 29, 2015 at 16:50
1

For a one-liner with parenthesis to spawn a subshell so you avoid retaining the variables:

(while read LINE ; do [[ "$LINE" =~ "Untracked files" ]] && MATCHED=1 ; \
   [[ "$MATCHED" = 1 ]] && echo "$LINE" ; done < <(git status))

You can just pipe at the end of that into whatever else you need to do with it.

Or you can use it in whatever shell script

while read LINE ; do
    [[ "$LINE" =~ "Untracked files" ]] && MATCHED=1
    [[ "$MATCHED" = 1 ]] && echo "$LINE"
done < <(git status)

Replace the echo "$LINE" with whatever you want to do with the data. If you want to skip the "Untracked files" line, then just switch the two tests.

0

you can use something like this, I used Perl, the following command set count = 1 if I match some string in the current line and when the while loop is finished I check the count variables and I print the range of lines from where match happen to the last line

ls -al | perl -e '@LINES = (); $n = 0 ; $nline = 0; while(<>){ push(@LINES, $_); $n++; if($_ =~ m/mirror/i) { $count = 1; $nline = $. - 1 };};  if($count != 0){ foreach $i($nline..$n-1){ print "\t$LINES[$i]\n";}}'
1
  • 1
    Much too complicated. A simple Perl solution is here: stackoverflow.com/a/18167194/111036. A variation which includes the line to match could be: perl -ne 'print if /Untracked files:/ .. 0'
    – mivk
    Jul 23, 2016 at 16:47

You must log in to answer this question.

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