I have a text file and I want to use Unix commands (I don't care which) to print lines that contain a Chinese character OR contain the string ###.

This answer has a grep command which prints out the lines containing Chinese characters

grep -P '[\p{Han}]' filename.txt

which I understand is a Perl regular expression. And this prints out the lines containing ###:

grep '###' filename.txt

But I can't figure out how to combine (OR) them. If I do grep -e '###' -P '[\p{Han}]' as I might expect this answer would generalize, it doesn't print out the lines containing Chinese characters.

Question: How do I use Unix commands to print lines that contain Chinese characters OR lines that contain ###?

Oh, in case it helps, if the file contains

中文 keep this line
### keep this line
don't keep this line

it should output

中文 keep this line
### keep this line

3 Answers 3


In general you'd combine multiple patterns using -e pat1 -e pat2, however at least for GNU grep version 3.4, the global -P option only permits a single pattern:

$ grep -P -e '[\p{Han}]' -e '###' filename.txt
grep: the -P option only supports a single pattern

So you need to place the alternation inside the regex:

grep -P -e '[\p{Han}]|###' filename.txt

or just

grep -P '\p{Han}|###' filename.txt

(the -e is optional in the case of a single pattern, and you don't need to use a bracket expression [ ] unless you have a set of characters or properties to match on).

Alternatively you may prefer to use Perl's regexps directly, ex.

perl -CDS -ne 'print if /\p{Han}/ or /###/' filename.txt

GNU grep doesn't support multiple patterns when you use the -P option (except in the way steeldriver suggests), but ripgrep supports multiple patterns (and already has extended regex enabled):

rg -N -e '[\p{Han}]' -e '###' filename.txt

Using Raku (formerly known as Perl_6)

If you only want lines containing Han script, grep for lines containing <:Script<Han>> character(s). Use the | to provide alternation with other regex patterns:

raku -ne '.put if .grep( / <:Script<Han>>  |  \#**3 / );' 


raku -ne '.put if .grep( / <:Script<Han>> / | / \#**3 / );' 


raku -ne '.put if .grep( / <:Script<Han>> / ) | .grep( / \#**3 / );' 

Sample Input:

中文 keep this line
### keep this line
don't keep this line

Sample Output (all 3 code examples):

中文 keep this line
### keep this line

A short note on escaping characters within regexes in Raku:

Basically, all non-alnum characters have to be quoted or escaped to preserve their literal meaning. Unquoted or unescaped characters are presumed to have special meaning (e.g. . unescaped-dot means any character but \. escaped-dot means a literal dot character).

This rule applies whether an unescaped non-alnum character has an assigned regex meaning or not--effectively preserving an entire class of characters for future regex improvements.



You must log in to answer this question.

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