I\'m writing a bash script that needs to loop files inside a directory that do not match a specific extension. So far, I\'ve found that the following code loops all files th
to loop files inside a directory that do not match a specific extension
You can use extglob
:
shopt -s extglob
for f in *.!(txt); do
echo "$f"
done
pattern *.!(txt)
will match all entries with a dot and no txt
after the dot.
EDIT: Please see comments below. Here is a find
version to loop through files in current directory that don't match a particular extension:
while IFS= read -d '' -r f; do
echo "$f"
done < <(find . -maxdepth 1 -type f -not -name '*.txt' -print0)
If you are ok for a GNU
solution, give a try to this:
for f in $(find . -maxdepth 1 -type f \! -name \*.txt) ; do
printf "%s\n" "${f}"
done
This is going to break if special chars are contained in the filenames, such as (space).
For something safe, still GNU
, try:
find . -maxdepth 1 -type f \! -name \*.txt -printf "%p\0" | xargs -0 sh -c '
for f ; do
printf "%s\n" "${f}"
done' arg0
Do
find /path/to/look -type f -not -name "*.txt" -print0 | while read -r -d '' file_name
do
echo "$file_name"
done
when your filenames may be nonstandard.
Note:
If you don't wish to recursively search for files in subfolders include -maxdepth 1
just before -type f
.
This will do:
shopt -s extglob
for f in !(*.txt) ; do
echo $f
done
You just inverse the glob pattern using !(glob_pat)
, and to use it, you need to enable extended glob.
If you want to ignore directories, then:
shopt -s extglob
for f in !(*.txt) ; do
[ -d "$f" ] && continue # This will ignore dirs
# [ -f "$f" ] && continue # This will ignore files
echo $f
done
If you wanna go into all sub-dirs then:
shopt -s extglob globstar
for f in !(*.txt) **/!(*.txt) ; do
[ -d "$f" ] && continue # This will ignore dirs
# [ -f "$f" ] && continue # This will ignore files
echo $f
done
You can pattern-match with the ==
operator.
for f in *; do
[[ $f == *.txt ]] && continue
# [[ $f != *.txt ]] || continue
...
done
If this might run in an empty directory, either use shopt -s nullglob
prior to the loop, or put [ -e "$f" ] || continue
in side the loop. (The former is preferable, as it avoids constantly checking if a file exists.)
for f in $(ls --hide="*.txt")
do
echo $f
done