I have a folder with files that have extensions, such as .txt
, .sh
and .out
.
However, I want a list of files that have only .txt
extension, with the file names not containing certain characters.
For example, the .txt
files are named L-003_45.txt
and so on all up to L-003_70.txt
. Some files have a change in the L-003
part to lets say L-004
, creating duplicates of lets say file 45, so basically both L-003_45.txt
and L-004_45.txt
exist. So I want to get a list of text files that don't have 45 in their name.
How would I do that?
I tried with find
and ls
and succeeded but I would like to know how to do a for loop
instead.
I tried:
for FILE in *.txt; do ls -I '*45.txt'; done
but it failed.
Would be grateful for the help!
CodePudding user response:
Or you use Bash's ext
endedglob
ing
#!/usr/bin/env bash
# Enables extended globing
shopt -s extglob
# Prevents iterating patterns if no match found
shopt -s nullglob
# Iterates files not having 45 or 57 before .txt
for file in !(*@(45|57)).txt; do
printf '%s\n' "$file"
done
CodePudding user response:
I would advise you to use the find
command to find all files with the required extensions, and later filter out the ones with the "strange" characters, e.g. for finding the file extensions:
find ./ -name "*.txt" -o -name "*.sh" -o name "*.out"
... and now, for not showing the ones with "45" in the name, you can do:
find ./ -name "*.txt" -o -name "*.sh" -o name "*.out" | grep -v "45"
... and if you don't want "45" nor "56", you can do:
find ./ -name "*.txt" -o -name "*.sh" -o name "*.out" | grep -v "45" | grep -v "56"
Explanation:
-o
stands forOR
grep -v
stands for "--invert-match" (not showing those results)
CodePudding user response:
Setup:
$ touch L-004_23.txt L-003_45.txt L-004_45.txt L-003_70.txt
$ ls -1 L*txt
L-003_45.txt
L-003_70.txt
L-004_23.txt
L-004_45.txt
One idea using !
to negate a criteria:
$ find . -name "*.txt" ! -name "*_45.txt"
./L-003_70.txt
./L-004_23.txt
Feeding the find
results to a while
loop, eg:
while read -r file
do
echo "file: ${file}"
done < <(find . -name "*.txt" ! -name "*_45.txt")
This generates:
file: ./L-003_70.txt
file: ./L-004_23.txt
CodePudding user response:
The proposed solution with extglob
is a very good one. In case you need to exclude more than one pattern you can also test and continue. Example to exclude all *45.txt
and *57.txt
:
declare -a excludes=("45" "57")
for f in *.txt; do
for e in "${excludes[@]}"; do
[[ "$f" == *"$e.txt" ]] && continue 2
done
printf '%s\n' "$f"
done