1

I am using Ubuntu 14.04 LTS.

I am playing around with grep and I hit an issue piping grep to ls. All examples are limited to a current directory, non-recursive.

If I want to list all files containing a digit in their name:

ls | grep [0-9]

If I want to list all files containing "d", "h", "m" as a first letter:

ls | grep ^[dhm]

If I want to list all files containing a digit as their first letter:

ls | grep ^[0-9]

However, when I try to use ! inside [], the ! is not included:

user@host:~$ ls | grep [0-9]
1.log
2.log
3.log
hs_err_pid4015.log
Untitled 1.odt
v1.odt

user@host:~$ ls | grep [!0-9]
1.log
2.log
3.log
hs_err_pid4015.log
Untitled 1.odt
v1.odt

The same implies if I try to use it with ^

user@host:~$ ls | grep ^[0-9]
1.log
2.log
3.log

user@host:~$ ls | grep ^[!0-9]
1.log
2.log
3.log

I have spent several days reading other posts, man pages, articles etc regarding grep and wildcards, but I can't figure it out. I have tried putting them in ' and ", combining both wildcards flags (^ and !) in [[]] etc.

Nothing shows different output that the examples above.

Please, don't show me the solution. Explain my mistakes and let me figure it out on my own.

  • grep uses regular expressions, not wildcards - that's the first thing you should know. Second, always quote your expressions - the shell uses wildcards and your expression could be expanded by the shell if it fits something. For example, [!0-9] is a shell expression meaning any file with a single character name that isn't a digit. So, if you had a file named d, ls | grep [!0-9] would actually be ls | grep d. So do: ls | grep '[!0-9]'. (Of course, considering heemayl's answer.) – muru Jan 5 '17 at 5:02
4

The Regex token inside character class for negation is ^, not !.

So you need:

ls | grep '^[^0-9]'

If you do ls | grep ^[!0-9], then within [], ! is treated literally and 0-9 is expanded in the usual manner.

Also for this kind of trivial tasks, use shell globbing, Regex is a bit too much for these, and also don't parse ls; you could simply do:

ls [^[:digit:]]*
ls [![:digit:]]*

Note that, bash supports both ^, and ! as pattern negation token inside character class while globbing.

If you don't want to depend on you locale:

ls [^[0-9]]*
ls [![0-9]]*
  • I read that in here: <br/> tldp.org/LDP/GNU-Linux-Tools-Summary/html/x11655.htm <br/> But I never assumed it will need two ^s. However, it worked, thank you :) – Iliyan Stankov Jan 5 '17 at 5:03
  • @IliyanStankov No problem. Just remember shell globbing and Regex are two different entities. I suggest you to have a go through these two to get a better understanding. – heemayl Jan 5 '17 at 5:04

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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