Bash: ls * without folder grouping
Solution 1:
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
)
Solution 2:
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
Solution 3:
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 thels
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 abash
ism, beware — it might not be present in all versions of bash. -
If
fonts
orimages
has subdirectories,**
will list them all, recursively, all the way down. One (somewhat kludgy and unreliable) way to limit the depth isls -d --file-type -- source/** | grep -v '\(/.*\)\{3\}'
which removes lines containing three or more
/
characters.