How to grep with input ansi color encoding maintained? - linux

The following grep does not maintain the input ANSI color encoding. Is there a way to maintain the original color encoding?
$ builtin printf '%s\n' $'\e[33mx\e[0m' | grep $'\e\[33m'
x

Disable grep's coloring with --color=never:
$ builtin printf '%s\n' $'\e[33mx\e[0m' | grep --color=never $'\e\[33m'
Otherwise, grep inserts an escape sequence before the searched string \e\[33m to color it, and then after inserts another sequence to reset all colorings, which in turn causes the letter x to be not colored on the output.
The default coloring mode of grep is --color=auto, which colors the output only if the output is a terminal. So, another way of disabling the coloring would be redirecting the output of grep to somewhere other than the terminal, e.g. cat:
$ builtin printf '%s\n' $'\e[33mx\e[0m' | grep $'\e\[33m' | cat

Related

I am trying to use the grep command in linux. how to grep similar words and phrases

How can I grep all lines starting by a specific letter (for instance "n")in a file ?
for the file /var/log/messages, I tried
# cat /var/log/messages | grep n*
it didn't work
All lines starting with n:
cat /var/log/messages | grep "^n"
use regular expressions for pattern
^ Indicates the beginning of an input string
$ Indicates the end of an input string
cat /var/log/messages | grep ^n
Have a look at https://www.linux.com/topic/desktop/introduction-regular-expressions-new-linux-users/

Bash: List file size using ls , awk and grep

I entered the following commands on the terminal:
ls -l someFile | awk '{print $5}' | grep [0-9]
Based on my understanding, the ls -l prints the lists of directories and files with long format (including the permissions) within the current directory, so piping the awk (to print desired field from the list, which is the size of file) and grep [0-9] gave me the correct output that I want, which is the file size highlighted in red.
For example:
drwxr-xr-x 2 zdgx6 students 103 Feb 23 2017 delosreyes_hw1
Output is 103 (since that's the size and the font is red)
However, when I tried this on my Bash script
like this: echo " $file size: $( ls -l "$file" | awk '{print $5}' | grep [0-9] ) $regfile "
it outputs the file size correctly but it's not highlighted in red. So I assume that my syntax may have been wrong but i didn't get any errors.
Any idea why that might be?
echo "$(tput setaf 1)$(stat -c '%B' file.log)$(tput sgr0)"
512
You should not use ls to parse the details of any file, you can use stat instead. You can issue stat --help to check the details of various flags provided by stat command. Also by doing this, you do not have to use any additional pipe to feed into awk.
Gnu grep will highlight the matched part of each line if:
you supply the command-line argument --color=always [Note 1], or
stdout is a terminal and you either supply the command-line argument --color=auto or do not specify --color (because auto is the default setting).
Running grep inside $(...) in order to capture the output as part of a bash expansion means that stdout will be redirected to a pipe, which is not a terminal. So unless you specify --color=always, match coloring will be disabled. That's usually want you want when you are processing the output of grep.
So you could "fix" this by using the --color=always option, but really the simpler solution is to send colour control codes directly, since that is the only reason you are using grep.
Colour codes can be sent in a reasonably portable way using the tput utility, which is part of the ncurses package and will generally be installed on any Linux/BSD system. You'll want the following codes:
tput bold # Sets boldface (Otherwise, the colour will be washed out)
tput setaf 1 # 1 is red. 2 is green, 3 yellow, 4 blue, 5 magenta, 6 cyan and 7 white
After you output the highlighted text, you'll need to reset the console to normal:
tput sgr0 # Normal colour and style
So you could do, for example:
echo "$file size: $(tput bold)$(tput setaf 1)$(ls -l "$file" | awk '{print $5}')$(tput sgr0) $regfile"
If you were doing that a lot, you might want to save the tput outputs in bash variables:
bold_red=$(tput bold)$(tput setaf 1)
reset_col=$(tput sgr0)
echo "$file size: $(tput bold)$(tput setaf 1)$(ls -l "$file" | awk '{print $5}')$(tput sgr0) $regfile"
You could also hard-code typical console codes if you know what they are:
printf "%s size: \033[1;31m%s\033m %s\n" "$file" "$(ls -l "$file" | awk '{print $5}')" "$regfile"
Notes
For the benefit of those of us with a different notion of English orthography, grep allows both --color and --colour. To avoid confusion, I used the first one in the text here, although I typically use the second out of habit.
Thanks all! I find that using the grep --color=always was the simplest solution for my question. The other suggestions worked as well but we haven't discussed those commands in class.
Here's my code:
echo " $file $( ls -l "$file" | awk '{print $5}' | grep --color=always [0-9] ) $regfile "

Color information disappears when writing a result of 'grep --color=auto' into a file

When I do as below with an aliased grep(grep --color=auto)
echo abcde | grep 'ab'
it returns abcde (ab in red).
but
echo abcde | grep 'ab' >foo.txt
foo.txt has just abcde.
I guess my terminal shows ab in red in the 1st case according to some tags by 'grep' but foo.txt does not contain them. Is it due to grep?
Does grep judge what returning value should be?
My grep is grep (GNU grep) 2.20
grep recognizes where you store the result and disables coloring in case of auto setting for redirections (colors is enabled only for terminal).
Use --color=always to force it to use it ... always, but I don't think you will find those control sequences nice to view in a text file.
With --color=auto, grep checks whether the output goes to a terminal, and switches colours on only when it does. You need to specify --color=always instead.

Grep Syntax with Capitals

I'm trying to write a script with a file as an argument that greps the text file to find any word that starts with a capital and has 8 letters following it. I'm bad with syntax so I'll show you my code, I'm sure it's an easy fix.
grep -o '[A-Z][^ ]*' $1
I'm not sure how to specify that:
a) it starts with a capital letter, and
b)that it's a 9 letter word.
Cheers
EDIT:
As an edit I'd like to add my new code:
while read p
do
echo $p | grep -Eo '^[A-Z][[:alpha:]]{8}'
done < $1
I still can't get it to work, any help on my new code?
'[A-Z][^ ]*' will match one character between A and Z, followed by zero or more non-space characters. So it would match any A-Z character on its own.
Use \b to indicate a word boundary, and a quantifier inside braces, for example:
grep '\b[A-Z][a-z]\{8\}\b'
If you just did grep '[A-Z][a-z]\{8\}' that would match (for example) "aaaaHellosailor".
I use \{8\}, the braces need to be escaped unless you use grep -E, also known as egrep, which uses Extended Regular Expressions. Vanilla grep, that you are using, uses Basic Regular Expressions. Also note that \b is not part of the standard, but commonly supported.
If you use ^ at the beginning and $ at the end then it will not find "Wiltshire" in "A Wiltshire pig makes great sausages", it will only find lines which just consist of a 9 character pronoun and nothing else.
This works for me:
$ echo "one-Abcdefgh.foo" | grep -o -E '[A-Z][[:alpha:]]{8}'
$ echo "one-Abcdefghi.foo" | grep -o -E '[A-Z][[:alpha:]]{8}'
Abcdefghi
$
Note that this doesn't handle extensions or prefixes. If you want to FORCE the input to be a 9-letter capitalized word, we need to be more explicit:
$ echo "one-Abcdefghij.foo" | grep -o -E '\b[A-Z][[:alpha:]]{8}\b'
$ echo "Abcdefghij" | grep -o -E '\b[A-Z][[:alpha:]]{8}\b'
$ echo "Abcdefghi" | grep -o -E '\b[A-Z][[:alpha:]]{8}\b'
Abcdefghi
$
I have a test file named 'testfile' with the following content:
Aabcdefgh
Babcdefgh
cabcdefgh
eabcd
Now you can use the following command to grep in this file:
grep -Eo '^[A-Z][[:alpha:]]{8}' testfile
The code above is equal to:
cat testfile | grep -Eo '^[A-Z][[:alpha:]]{8}'
This matches
Aabcdefgh
Babcdefgh

Preserve colouring after piping grep to grep

There is a simlar question in Preserve ls colouring after grep’ing but it annoys me that if you pipe colored grep output into another grep that the coloring is not preserved.
As an example grep --color WORD * | grep -v AVOID does not keep the color of the first output. But for me ls | grep FILE do keep the color, why the difference ?
grep sometimes disables the color output, for example when writing to a pipe. You can override this behavior with grep --color=always
The correct command line would be
grep --color=always WORD * | grep -v AVOID
This is pretty verbose, alternatively you can just add the line
alias cgrep="grep --color=always"
to your .bashrc for example and use cgrep as the colored grep. When redefining grep you might run into trouble with scripts which rely on specific output of grep and don't like ascii escape code.
A word of advice:
When using grep --color=always, the actual strings being passed on to the next pipe will be changed. This can lead to the following situation:
$ grep --color=always -e '1' * | grep -ve '12'
11
12
13
Even though the option -ve '12' should exclude the middle line, it will not because there are color characters between 1 and 2.
The existing answers only address the case when the FIRST command is grep (as asked by the OP, but this problem arises in other situations too).
More general answer
The basic problem is that the command BEFORE | grep, tries to be "smart" by disabling color when it realizes the output is going to a pipe. This is usually what you want so that ANSI escape codes don't interfere with your downstream program.
But if you want colorized output emanating from earlier commands, you need to force color codes to be produced regardless of the output sink. The forcing mechanism is program-specific.
Git: use -c color.status=always
git -c color.status=always status | grep -v .DS_Store
Note: the -c option must come BEFORE the subcommand status.
Others
(this is a community wiki post so feel free to add yours)
Simply repeat the same grep command at the end of your pipe.
grep WORD * | grep -v AVOID | grep -v AVOID2 | grep WORD

Resources