Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I'm trying to list all hidden dirs with the following command

ls -lhAF1 | grep -E '^d.*[0-9]{2}:[0-9]{2} \.'

which works perfectly fine

Explanation for Regex: I'm trying to get all rows that have the following Format: d, then some text, then the timestamp, then a space, then the dot and then more text

However when I try to color the ls output with this command:

ls --color -lhAF1 | grep -E '^d.*[0-9]{2}:[0-9]{2} \.'

It gives zero results, the output without --color is:

drwxr-xr-x 1 User Group 4096 Feb 1 08:48 .invisible

Why does ls / grep behave this way?

share|improve this question
where is the difference between the two invocations of ls ...? – Anthon Feb 2 at 8:53
@Anthon sorry, just copy pasted and forgot to add --colors in second code – danielr1996 Feb 2 at 9:11
I thought so, but didn't want to guess wrong and edit that in myself in case there was some commandline issue. – Anthon Feb 2 at 9:44
You may control if you call the shell built in comands or the system-wide one by giving the full path. e.g. '/usr/bin/ls -lhAF1' instead of 'ls -lhAF1'. They may behave differently – Manu H Feb 2 at 14:24
up vote 6 down vote accepted

--color adds escape sequences for the color. You can see this if you redirect the output (of ls --color) to a file.

This is what it looks like:

 drwxr-xr-x  6 root root 4.0K Jan  9 08:23 ^[[01;34m.cabal^[[0m/

To account for this, try this instead:

 ls -lhAF1 --color | grep -E '^d.*[0-9]{2}:[0-9]{2} .*\.'
share|improve this answer
Thanks, that as exactly the problem, but it only works for dirs that do not contain a dot, but dirs like hello.world would also be accepted, I tried it with ^d.*[0-9]{2}:[0-9]{2} \^\[\[.*\., which works in RegExr, but not in my shell – danielr1996 Feb 2 at 9:09
I came one step closer to the solution: grep $'\x1b' matches the ASCII Escape, but this doesn't work with double quotes around – danielr1996 Feb 2 at 9:31

Parsing ls is often a bad idea. Often, but not always. Here's another suggestion for you, which collects the required directories together before passing the set to ls.

find .* -maxdepth 0 -type d \( -name '.[^.]' -o -name '.??*' \) -exec ls -ld --color=always {} +

It's been pointed out that the original code actually limits the list of directories to those modified in the last six months. This can be handled with the following alternative solution.

find .* -maxdepth 0 -type d -mtime -180 -mtime +0 \( -name '.[^.]' -o -name '.??*' \) -exec ls -ld --color=always {} +

As ever, if your find doesn't understand the trailing + replace it with \; at the cost of efficiency.

share|improve this answer
Presumably with his grep for HH:MM, the OP wanted only the files last modified between 6 months ago and now, for which you'd also need a -mtime -180 -mtime +0 – Stéphane Chazelas Feb 2 at 11:52
@StéphaneChazelas ah, I missed that, thank you. It would have been easier if this had been included in the description of the requirement, of course. (I like the -mtime +0.) – roaima Feb 2 at 12:24
Likely it was an oversight of the OP, see the discussion on his own answer. – Stéphane Chazelas Feb 2 at 12:26

The reason is that ls always colorizes its output even if it is connected to a terminal. From man ls:

          colorize the output.   WHEN  defaults  to  'always'  or  can  be
          'never' or 'auto'.  More info below

Many other tools such as grep do not retain colors when standard output is terminal but for some reasons ls was designed to act differently. Colorizing output is achieved by using ANSI escape codes that are interpreted by your terminal. Redirect ls output to a file and open it in editor:

$ ls --color  -lhaF1  > /tmp/RESULT
$ less /tmp/RESULT
total 12K
drwxr-xr-x  3 ja   users 4.0K Feb  2 09:47 ESC[0mESC[01;34m.ESC[0m/
drwxrwxrwt 12 root root  4.0K Feb  2 09:51 ESC[30;42m..ESC[0m/
drwxr-xr-x  2 ja   users 4.0K Feb  2 09:47 ESC[01;34m.invisibleESC[0m/
-rw-r--r--  1 ja   users    0 Feb  2 08:35 a|a

If you have $LESS variable set you probably need to unset it before running less in order to see raw escape codes instead of color. So, to sum up, when using --color what grep gets is not what you see but a bunch of escape codes together with it. To fix it either don't use --colors at all or set it to --auto:

$ ls --color=auto -lhaF1 | grep  -E '^d.*[0-9]{2}:[0-9]{2} \.'
share|improve this answer

Ok I finally figured out how to list all hidden dirs while preserving the Colors and not including dirs like "hello.world":

 ls -lhAF1 --color | grep -E "^d[rwx-]{9}.*[0-9]{2}:[0-9]{2} "$'\x1b'"\[([0-9]{1,2}m?)(;[0-9]{1,2}m?)?\."
share|improve this answer
Note that rwx are not the only permissions, especially for directories where t and s are common (see /tmp for instance). Only files last modified between 6 months ago and now have their time displayed with HH:MM (in the C and most English locales at least). – Stéphane Chazelas Feb 2 at 11:59
@StéphaneChazelas well the permissions can be included easily, but how is the timestamp displayed when they were modified more than 6 month ago? – danielr1996 Feb 2 at 12:21
more than 6 months ago or in the future. Check ls -l /bin for examples. -rwxr-xr-x 1 root root 31240 Mar 14 2015 uname in a en_GB.UTF-8 locale on a GNU system, – Stéphane Chazelas Feb 2 at 12:24

Rather than applying grep to the output of ls which is not post-processable reliably anyway, I'd rather filter on the list of files passes to ls, like:

ls -lFhd --color -- .*(/)

In zsh. Or as your own approach suggests you only want the directories last modified between 6 months ago and now and not the ones with special permissions:

ls -lFhd --color -- .*(/mM-6mM+0f-7000)
share|improve this answer
if I excute this it throws the error "Syntax error near unexpected token (" Note: I'm actually using Git Bash / Cygwin on Windows – danielr1996 Feb 2 at 12:27
@danielr1996, yes, that's for zsh, not bash. Check cygwin for a better Unix-like environment for Windows (includes zsh and bash). – Stéphane Chazelas Feb 2 at 12:29
Oh well, you wrote that it's zsh, the Problem is that in our Company we can only use git bash and i was just playing arround. But at home I'm actually using zsh, can you tell me how the feature is called you're using Just as a side note: isn't git bash built on cygwin? – danielr1996 Feb 2 at 12:32
@daniel1996, they are glob qualifiers. Not sure about git-bash. I had heard it was outdated versions of some GNU utilities built for MS-Windows. It may be different now. – Stéphane Chazelas Feb 2 at 12:54

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

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