I can use ls -ld */ to list all the directory entries in the current directory. Is there a similarly easy way to just list all the regular files in the current directory? I know I can use find

find . -maxdepth 1 -type f

or stat

stat -c "%F %n" * | grep "regular file" | cut -d' ' -f 3-

but these do not strike me as being overly elegant. Is there a nice short way to list only the regular files (I don't care about devices, pipes, etc.) but not the sub-directories of the current directory? Listing symbolic links as well would be a plus, but is not a necessity.

  • 3
    What do you mean by "overly elegant"? As far as I know, the find command is the best way to do what you want. For some reliable other options, you should look into shell specific commands (and those are anything but portable)! – rahmu Sep 18 '12 at 9:58
  • @rahmu I was for something similar to ls -d */, which is short, easy to type, and easy to understand. So I'm pretty happy with Ulrich Dangel's answer, even though I'm not using zsh. – daniel kullmann Sep 18 '12 at 10:41
up vote 26 down vote accepted

With zsh and Glob Qualifiers you can easily express it directly, e.g:

echo *(.)

will either only return the list of regular files or an error depending on your configuration.

For the non-directories:

echo *(^/)

(will include symlinks (including to directories), named pipes, devices, sockets, doors...)

echo *(-.)

for regular files and symlinks to regular files.

echo *(-^/)

for non-directories and no symlinks to directories either.

Also, see the D globbing qualifier if you want to include Dot files (hidden files), like *(D-.).

  • 2
    zsh surely has some real nice features. Maybe I should switch... – daniel kullmann Sep 18 '12 at 9:05
  • 1
    Obligatory zsh one-short-liner: … Ah, good, it's here already. – Gilles Sep 18 '12 at 23:43
ls -p | grep -v / 

This command lists all non-hidden files that aren't directories (regular files, links, device files, etc.). To also include hidden files, add the -A option to ls

It assumes none of the files have newline characters in their name. Adding a -q option to ls would transform all non-printable characters including newline to ?, guaranteeing they're on one line and so suitable for feeding to a line-based utility like grep and for printing on a terminal.

  • 10
    +1, this is a good answer. Down voting a new user with no comment is pretty shocking to me, especially when a working answer is provided. The only edge case I can see where this won't work properly is if there is a newline in a filename. Also retaining colours would be a nice addition where supported. For GNU you could add --color=always to the ls, for OSX -G. – Graeme Feb 23 '14 at 10:38
  • Hi, the command you have given is great and it certainly helps me out however I was wondering if it is possible to use the above command and change the file permission at the same time? I tried adding in sudo chmod 777 at the end, and I was given errors... Any help is greatly appreciated – dissidia Sep 4 '15 at 2:14
  • 3
    If you also like to exclude symlinks that point to directories do ls -pL | grep -v /. The added -L dereferences symbolic links. – Matthias Braun Mar 7 '16 at 18:36
  • 1
    If your also like to use wildcard filter, do ls -pdL something* | grep -v /. The added -d option lists directories themselves, not their contents, so they will be excluded correctly. – Rockallite Jan 24 '17 at 2:15
  • This is best answer and easy to understand. – Sagar Dalvi Mar 29 '17 at 15:12

To list regular files only:

ls -al | grep '^-'

With symbolic links (to any type of file) included:

ls -al | grep '^[-l]'

Where the first character of the list describes the type of file, so - means that it's a regular file, for symbolic link is l.


Print the names of the all matching files (including links):

run-parts --list --regex . .

With absolute paths:

run-parts --list --regex . "$PWD"

Print the names of all files in /etc that start with p and end with d:

run-parts --list --regex '^p.*d$' /etc
  • 3
    This answer needs more love – Jonah Mar 29 '15 at 18:52

ls has no option to do that, but one of the nice things about unix & linux is that long-winded and inelegant pipelines can easily be turned into a shell script, function, or alias. and these can, in turn, be used in pipelines just like any other program.

(NOTE: there are some scope issues with functions and aliases. Scripts are available to any executable that can read and execute them. Aliases and functions are only available in the current shell - although a sub-shell's .profile/.bashrc etc may redefine them and thus make them available. Also, a script can be written in any language - including bash/sh, awk, perl, python, and others - whichever one is best for the job or that you are most familiar with)


alias lsf='find . -maxdepth 1 -type f -print0 | xargs -0r ls'

I've added xargs so that you can use use all the usual ls options, e.g. lsf -lrS

Because it uses find, all of the normally-hidden dotfiles will be displayed, and all of the filenames will be prefixed with ./ - that's about the only difference you'll notice.

You could exclude dot files with ! -iname '.*' but then you'd have to have two versions of the alias - one that displayed dot files and one that didn't.

alias lsf2='find . -maxdepth 1 -type f -a ! -iname '\''.*'\'' -print0 | xargs -0r ls'

Alternatively, if lsf was a script rather than an alias you could parse the options (perhaps with getopts or /usr/bin/getopt or similar), and exclude dotfiles unless -a was present.

  • -name is enough, you don't need -iname. – Totor Jan 2 '14 at 1:13
bash-4.2$ ls -F | grep -v '[/@=|]$' | more

The -F option to ls appends * to executables, / to directories, @ to symbolic links, = to sockets, and | to FIFOs. You can then use grep to exclude the non-regular file characters from output and you have the files. This will work in any shell, not just zsh.

The weaknesses are:

  1. Any file whose name ends in @, = or | will be excluded (but you shouldn't really have files with those characters in the name anyway)
  2. That doesn't exclude device files or some exotic types of files on some systems like doors.
  3. You will have an asterisk appended on any file that is executable. That could be handled by piping through sed to remove any '*' characters from the output.
  4. That doesn't work properly if there are file names containing newline characters.
  • On the system I'm writing this on, 10% of the files have names containing =, @ or | characters. = is common in maildir or filenames that have a base64 or quoted-printable encoded part. @ in locale definitions, for email addresses and more. It's rare for them to appear at the end of the file name though. (only 31 out of 2.2 millions on this system for instance) – Stéphane Chazelas Jul 31 '16 at 15:14

The manual stated the 'f' option is against 'regular file' only, not pipes, socket or block/char devices, which means you're already doing the right stuff.

   -type c
          File is of type c:

          b      block (buffered) special

          c      character (unbuffered) special

          d      directory

          p      named pipe (FIFO)

          f      regular file

          l      symbolic link; this is never true if the -L option or the
                 -follow option is in effect, unless the symbolic link  is
                 broken.  If you want to search for symbolic links when -L
                 is in effect, use -xtype.

          s      socket

          D      door (Solaris)

This is not particularly short but you could turn it into a script or alias if you needed to call it quickly. Using the ls command as an input array, call ls -ld on each entry piped to grep to exclude directories with the output sent to null, and if successful echo the original input:

for list in `ls` ; do ls -ld $list | grep -v ^d > /dev/null && echo $list ; done ;

You can invert the grep and conditional output, same results:

for list in `ls` ; do ls -ld $list | grep ^d > /dev/null || echo $list ; done ;

This is a bit old thread, but the cleanest way to list files only.

ls -al | grep '^-' | awk '{print $9}'

protected by slm Feb 23 '14 at 9:44

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

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