14

I want to display a line matching a search term and all the remaining lines in the file.

For example, if I use:

more text.txt | egrep show

it will only show the line that has "show" in it, while I would wish for something like a start command:

more text.txt | start show

that will show all the lines after the first line that matches the search term.

However, it's not working on my Ubuntu. How can I install it or anything similar to it?

8
  • Do you have any link to a description of that syntax, or is it just something you would like to have ? I can't find any command start in Ubuntu. And what comes directly after the pipe sign must be a command. – Soren A Apr 5 at 11:24
  • 1
    One very crude way would be to do grep -A 10000 show text.txt, showing the line containing show and 10000 lines after it, which would work if your file is less than 10000 lines. – Jos Apr 5 at 11:24
  • @SorenA , it is something I want to achieve, a keyword and show everything after it, trim everything before it – Omar Almomani Apr 5 at 11:31
  • @Jos, that is a great workaround, thanks, but if I found such a command it would be awesome or if we can craft a script for it! – Omar Almomani Apr 5 at 11:31
  • @Jos, very good suggestion which deserves to end up in an answer. Make an alias, e.g. alias start="grep -A 10000" to have your single command. No need to pipe. – vanadium Apr 5 at 11:37
15

If your file is less than, say, 10000 lines, you can do this:

grep -A 10000 show text.txt

The -A flag will show the line containing the search string (show) and the next 10000 lines.

However, I played around with the -A flag a bit, and I noticed grep will intelligently combine the output, so you don't get 10001 lines for each time the string show is found. So basically, it will show you the whole file once, starting from the line that contains show. If your file contains more than 10000 lines, adjust the parameter appropriately.

You can use the alias command to create your own custom command to achieve the same result.

EDIT: a slightly more elegant solution would be to use

 grep show -A $(wc -l < text.txt) text.txt

which will use the actual length of the file as the -A flag. This requires you to specify the file name twice. Unfortunately this will prevent the use of an alias, but you could write a shell function to do this.

Apparently, in this case you need to specify the search string first to avoid an error.

12
  • 1
    +1 :) -A for After, -B for before if you want to see lines before the match. – Rinzwind Apr 5 at 12:04
  • 3
    "This requires you to specify the file name twice (which certainly calls for an alias).": that is where an alias won't cut it anymore - a bash function could be used. – vanadium Apr 5 at 12:39
  • @vanadium yes, you are right. I never use aliases but assumed you could enter a parameter here or there, but you can't. I will modify my remark. – Jos Apr 5 at 12:45
  • 1
    wc -l text.txt will output count filename wc -l < text.txt is probably what you want – bac0n Apr 5 at 12:56
  • 1
    Note that you can shorten your grep command to grep show -A $(wc -l text.txt), since wc prints the file name, you don't have to pass it to grep manually. The only downside of this is handling names that require quoting – Ferrybig Apr 6 at 8:30
23

If you don't particularly need grep, you could use sed or awk for this:

sed -n '/show/,$p' text.txt
awk '/show/ {display=1} display {print}' text.txt
  • sed usually outputs all lines, but -n prevents that. /show/,$ is a line-range starting at the first line matching the regular expression show and ending at the last line ($). The print (p) command prints that line-range.
  • awk uses sequences of condition { action } pairs (usually on separate lines for readability), so /show/ is the condition that matches the regular expression show anywhere in an input line, and display=1 defines a variable named display to 1. Obviously condition display is a short form for display != 0, and print does what everyone expects, i.e.: print the input line.
6
  • those 2 are more elegant and also more portable as they don't depend on a gnu version of grep (-A option to grep is not posix) – Olivier Dulac Apr 6 at 15:10
  • 1
    The awk code can also be short: awk 'd=d||/show/'. – JoL Apr 6 at 21:41
  • Actually I wanted to suggest echo '/show/,$p' | ed -s text.txt, but using sed is even easier! – U. Windl Apr 7 at 6:57
  • 1
    @BeastOfCaerbannog @JoL So does awk 'var=var || /show/'... The idea is to evaluate /show/ only once and print that line... then make awk assume it is true after that and print the remaining lines without evaluating..."If the value of the entire expression var=var || /show/ is determinable from evaluating just the lefthand side of ||, the righthand side is not evaluated."... This is the nature of the awk logical operators. – Raffa Apr 7 at 14:57
  • 1
    @BeastOfCaerbannog Raffa's use of whitespace is a little misleading. The precedence of = is lower than ||, so the expression is evaluated as var=(var || /show/). The assignment operator = returns the value of the right-hand side, and unassigned variables are falsy. Finally, there's no accompanying action for that matching condition because the default is {print}, which is what we want. – JoL Apr 7 at 15:45
4
awk '/show/,0' text.txt

Awk allows specifying a range condition-expression , condition-expression, where the action-code is evaluated for each line between where the first condition returns true, until the second condition returns true.

By using constant false 0 as the second condition, the default action { print } will run for the matching line and every line after that.

In case you want to define your start command, awk allows passing string variables, so here you go:

start() {
  awk -v regex="$1" '$0 ~ regex, 0' "${@:2}"
}

$0 ~ regex is used to match a string as if it were a regex. $0 in awk refers to the whole line. "${@:2}" is all command arguments after the first one if there are any. That way, you can optionally specify files to start, or else let it read from piped input.

1

In Bash:

word="show"
e=0

while read line
do
    [[ $line =~ "$word" ]] && e=1
    [ $e -eq 1 ] && echo "$line"
done < text.txt

That can be added as a function to ~/.bashrc like so:

grep2end () {

word="$1"
e=0

while read line
do
    [[ $line =~ "$word" ]] && e=1
    [ $e -eq 1 ] && echo "$line"
done < "$2"

}

and used like so:

grep2end "show" "text.txt"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.