Reputation: 322
There are already many answers for this similar question. But none of them satisfy my requirements. I want
List all directories under a directory without using glob (*
) syntax, i.e. I want to directly use lsdir somedir
Output should containing basename of the directories like when you just use ls
, like:
$ lsdir path/to/some/dir
dir1 dir2 dir3 dir4
but not this:
$ lsdir path/to/dir
path/to/dir/dir1 path/to/dir/dir2 path/to/dir/dir3 path/to/dir/dir4
To satisfy requirement 1, it seems feasible to define a function, but anyway we are going to use -d
option, to list the directories themselves of the ls
command parameters.
And when using -d
option, ls
list directory names with its parent prepended, like above.
ls
format (color, align, sort) should be preserved.
To satisfy requirement 2, we can use find
but in this way we lose all the ls
output format, like coloring (based on customized dircolors theme), alignment (output in aligned columns), sorting (sorting customized with various flags and in a column-first manner), and maybe some other things.
I know it's too greedy to want this many features simultaneously, and indeed I can live without all of them.
It's possible to emulate ls
output format manually but that's too inconsistent.
I wonder if there is a way to achieve this and still utilize ls
, i.e. how to achieve requirement 2 using ls
.
Upvotes: 0
Views: 839
Reputation: 322
Based on @M. Nejat Aydin's excellent answer, I am going to improve a little more to make it a useful command, especially with respect to processing options and multiple directories.
list_directories() {
local opts=()
local args=()
for i in $(seq $#); do
if [[ "${!i}" == -* ]]; then
opts+=("${!i}")
else
args+=("${!i}")
fi
done
(( ${#args[@]} == 0 )) && args=('.')
local -i args_n_1=${#args[@]}-1
for i in $(seq 0 $args_n_1); do
if (( ${#args[@]} > 1 )); then
(( i > 0 )) && echo
echo "${args[i]}:"
fi
(
shopt -s nullglob
cd "${args[i]}" &&
dirs=(*/) &&
(( ${#dirs[@]} > 0 )) &&
ls -d "${opts[@]}" "${dirs[@]%?}"
)
done
}
alias lsd=list_directories
This lsd
can be used with any number of ls
options and directories freely mixed.
$ lsd -h dir1 dir2 -rt ~
Note: Semantic meaning changes when you use globs with lsd
.
lsd path/to/dir*
list all directories under each directory starting with "path/to/dir".
To list all directories starting with "path/to/dir", use plain old ls -d path/to/dir*
.
Upvotes: 0
Reputation: 10123
This may be what you're looking for:
cd path/to/dir && dirs=(*/) && ls -d "${dirs[@]%?}"
or, perhaps
(shopt -s nullglob; cd path/to/dir && dirs=(*/) && ((${#dirs[@]} > 0)) && ls -d "${dirs[@]%?}")
The second version runs in a subshell and prints nothing if there is no any subdirectory inside path/to/dir
.
Upvotes: 1