Bash: ls * without folder grouping

Doesn't seems to be possible without output alteration, but here is an easy alternative way:

find source/ -type f

Or (specific to GNU find), to only get files at the depth in your question:

find source/ -type f -mindepth 2 -maxdepth 2

(or if you want directories like ls gives you, remove -type f)


You can simply stick to ls if you add some psychedlics (ls -d):

# mkdir test
# cd test
# mkdir A B C
# touch {A,B,C}/file*
# ls -d */*    
A/file  B/file  C/file

You may be interested in “the poor man’s find”:

shopt -s globstar

shopt -s sets the named shell option(s).  The globstar option is defined as follows in bash(1):

If set, the pattern ** used in a filename/pathname expansion context will match a files [sic] and zero or more directories and subdirectories.  If the pattern is followed by a /, only directories and subdirectories match.

So, after you’ve done shopt -s globstar, any of the following commands:

ls -d1 -- source/**                 # The character after the ‘d’ is the digit one.
ls -d -- source/** | cat            # i.e., it will write that into a pipe to any command.
printf "%s\n" source/**

will produce the output:

source/
source/fonts
source/fonts/fontello
source/images
source/images/bg1.png
source/images/eng.png
source/images/fra.png

Unfortunately, this includes the directory names, too.  It might help you a little to know that

printf "%s\n" source/**/

will produce the output:

source/
source/fonts
source/images

i.e., only the directory names.  You might redirect the output of one of the first set of commands to one file, redirect the output of the above to a second file, and then use comm, diff, or something similar, to subtract the second file from the first, leaving only the plain files (non-directories).  But don’t do that.

Another approach (that’s not much better) is

ls -d --file-type -- source/** | grep -v '/$'

The --file-type option tells ls to display a / at the end of each directory name (and other characters at the ends of other (special) file types), like this:

source//                            # Added an extra one
source/fonts/                       # Added one
source/fonts/fontello
source/images/                      # Added one
source/images/bg1.png
source/images/eng.png
source/images/fra.png

and then the grep -v '/$' removes the lines that end with /; i.e., the directory names.  Unfortunately, the --file-type option is not specified by POSIX.  If your version of ls doesn’t support it, use -F.  That is like --file-type except it also displays a * at the ends of the names of executable files, which some people find annoying.  You can eliminate them with sed:

ls -dF -- source/** | sed -e '/\/$/d' -e 's/\*$//'

If you want to do something with all the files (and only the files), you can do

for f in source/**
do
    if [ -f "$f" ]
    then
        Insert commands to be applied to plain files here.
    fi
done

Notes:

  • When ls is outputting to a terminal, and it’s not in -l (long) mode, it writes multiple names per line (unless the names are very long).  You can force it to write one name per line by specifying -1 (one), or by redirecting output to a file or a pipe.
  • You probably don’t really need the -- in the ls commands since you’re listing a directory whose contents you created.  You should use it when listing * in an unknown directory, as protection against filenames that begin with -.
  • Don’t try to parse the output from ls.
  • The globstar shell option appears not to be defined by POSIX.  (In fact, I’m not sure POSIX recognizes any shell options.)  While it seems to be a bashism, beware — it might not be present in all versions of bash.
  • If fonts or images has subdirectories, ** will list them all, recursively, all the way down.  One (somewhat kludgy and unreliable) way to limit the depth is

    ls -d --file-type -- source/** | grep -v '\(/.*\)\{3\}'
    

    which removes lines containing three or more / characters.

Tags:

Linux

Ls