filmov
tv
Unix & Linux: How do I loop through only directories in bash? (10 Solutions!!)

Показать описание
Unix & Linux: How do I loop through only directories in bash?
The Question: I have a folder with some directories and some files (some are hidden,
beginning with dot).
for d in *; do
echo $d
done
will loop through all files, but I want to loop only through directories. How
do I do that?
Solutions: Please watch the whole video to see all solutions, in order of how many people found them helpful
== This solution helped 395 people ==
You can specify a slash at the end to match only directories:
for d in */ ; do
echo "$d"
done
== This solution helped 12 people ==
You can use pure bash for that, but it's better to use find:
find . -maxdepth 1 -type d -exec echo {} ;
(find additionally will include hidden directories)
== This solution helped 87 people ==
You can test with -d:
for f in *; do
if [ -d "$f" ]; then
# $f is a directory
fi
done
== This solution helped 3 people ==
You can loop through all directories including hidden directories (beginning
with a dot) in one line and multiple commands with:
for file in */ .*/ ; do echo "$file is a directory"; done
If you want to exclude symlinks:
for file in *; do
if [[ -d "$file" && ! -L "$file" ]]; then
echo "$file is a directory";
fi;
done
----
note: using the list */ .*/ works in bash, but also displays the folders . and
.. while in zsh it will not show these but throw an error if there is no hidden
file in the folder
A cleaner version that will include hidden directories and exclude ../ will be
with the dotglob option:
shopt -s dotglob
for file in */ ; do echo "$file is a directory"; done
( or setopt dotglob in zsh )
you can unset dotglob with
shopt -u dotglob
== This solution helped 7 people ==
This is done to find both visible and hidden directories within the present
working directory, excluding the root directory:
to just loop through directories:
find -path './*' -prune -type d
to include symlinks in the result:
find -L -path './*' -prune -type d
to do something to each directory (excluding symlinks):
find -path './*' -prune -type d -print0 | xargs -0 <cmds>
to exclude hidden directories:
find -path './[^.]*' -prune -type d
to execute multiple commands on the returned values (a very contrived example):
find -path './[^.]*' -prune -type d -print0 | xargs -0 -I '{}' sh -c "printf
'first: %-40s' '{}'; printf 'second: %sn' '{}'"
instead of 'sh -c' can also use 'bash -c', etc.
== This solution helped 24 people ==
If you need to select more specific files than only directories use find and
pass it to while read:
shopt -s dotglob
find * -prune -type d | while IFS= read -r d; do
echo "$d"
done
Use shopt -u dotglob to exclude hidden directories (or setopt dotglob/unsetopt
dotglob in zsh).
IFS= to avoid splitting filenames containing one of the $IFS, for example: 'a
b'
----
edit:
In case you need to create an exit value from within the while loop, you can
circumvent the extra subshell by this trick:
while IFS= read -r d; do
if [ "$d" == "something" ]; then exit 1; fi
done < <(find * -prune -type d)
The Question: I have a folder with some directories and some files (some are hidden,
beginning with dot).
for d in *; do
echo $d
done
will loop through all files, but I want to loop only through directories. How
do I do that?
Solutions: Please watch the whole video to see all solutions, in order of how many people found them helpful
== This solution helped 395 people ==
You can specify a slash at the end to match only directories:
for d in */ ; do
echo "$d"
done
== This solution helped 12 people ==
You can use pure bash for that, but it's better to use find:
find . -maxdepth 1 -type d -exec echo {} ;
(find additionally will include hidden directories)
== This solution helped 87 people ==
You can test with -d:
for f in *; do
if [ -d "$f" ]; then
# $f is a directory
fi
done
== This solution helped 3 people ==
You can loop through all directories including hidden directories (beginning
with a dot) in one line and multiple commands with:
for file in */ .*/ ; do echo "$file is a directory"; done
If you want to exclude symlinks:
for file in *; do
if [[ -d "$file" && ! -L "$file" ]]; then
echo "$file is a directory";
fi;
done
----
note: using the list */ .*/ works in bash, but also displays the folders . and
.. while in zsh it will not show these but throw an error if there is no hidden
file in the folder
A cleaner version that will include hidden directories and exclude ../ will be
with the dotglob option:
shopt -s dotglob
for file in */ ; do echo "$file is a directory"; done
( or setopt dotglob in zsh )
you can unset dotglob with
shopt -u dotglob
== This solution helped 7 people ==
This is done to find both visible and hidden directories within the present
working directory, excluding the root directory:
to just loop through directories:
find -path './*' -prune -type d
to include symlinks in the result:
find -L -path './*' -prune -type d
to do something to each directory (excluding symlinks):
find -path './*' -prune -type d -print0 | xargs -0 <cmds>
to exclude hidden directories:
find -path './[^.]*' -prune -type d
to execute multiple commands on the returned values (a very contrived example):
find -path './[^.]*' -prune -type d -print0 | xargs -0 -I '{}' sh -c "printf
'first: %-40s' '{}'; printf 'second: %sn' '{}'"
instead of 'sh -c' can also use 'bash -c', etc.
== This solution helped 24 people ==
If you need to select more specific files than only directories use find and
pass it to while read:
shopt -s dotglob
find * -prune -type d | while IFS= read -r d; do
echo "$d"
done
Use shopt -u dotglob to exclude hidden directories (or setopt dotglob/unsetopt
dotglob in zsh).
IFS= to avoid splitting filenames containing one of the $IFS, for example: 'a
b'
----
edit:
In case you need to create an exit value from within the while loop, you can
circumvent the extra subshell by this trick:
while IFS= read -r d; do
if [ "$d" == "something" ]; then exit 1; fi
done < <(find * -prune -type d)