List only regular files (but not directories) in current directory

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.

Asked By: daniel kullmann

||

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)
Answered By: daisy

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-.).

Answered By: Ulrich Dangel

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)

e.g.

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.

Answered By: cas

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 ;
Answered By: Don R
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.
Answered By: kurtm
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.

Answered By: Athul Biju

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.

Debian/Ubuntu

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
Answered By: kenorb

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

ls -al | grep '^-' | awk '{print $9}'
Answered By: R J

My favourite sollution:

#!/bin/bash
for f in *
do
        if [ -f $f ]; then echo "$f"; fi
done

It can be done as one liner:
for f in *; do [ -f $f ] && echo "$f"; done; You can run it in the subshell and cd to the target directory. I would use ls for directories with a lot of files as it is quicker than find in this case (which makes it more elegant in my opinion). You would ideally use printf instead of echo for maximum security.

Answered By: nethero
Categories: Answers Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.