Reputation: 47061
The directory tree is like this:
.
├── A_123
│ └── 123.txt
├── A_456
│ ├── tmp
│ └── tmp.log
└── A_789
└── 789.txt
There're 3 directories (A_123, A_456, A_789).
The pattern of a directory name is: A_{numbers}
and the file I'm interested in is {numbers}.txt
.
I was wondering whether there's a way to get the directories A_{numbers}
that has no {numbers}.txt
file in them. For example above, this script should return:
./A_456
as A_456
doesn't have 456.txt
in its folder but A_123
and A_789
have their {numbers}.txt
files in the relevant folder.
Anyone has ideas about this? Thanks!
Upvotes: 3
Views: 155
Reputation: 246799
A slight variation on a couple of other answers: use bash extended pattern matching:
shopt -s extglob nullglob
for dir in A_+([0-9]); do
files=($dir/+([0-9]).txt)
(( ${#files[@]} == 0 )) && echo $dir
done
Upvotes: 1
Reputation: 64308
Here's one approach:
for dir in *;do
if [ $(find "$dir" -maxdepth 1 -regex '.*/[0-9][0-9]*\.txt' | wc -l) = 0 ]; then
echo $dir
fi
done
Upvotes: 4
Reputation: 8398
for file in *; do
if [[ "$file" =~ ^A_([0-9]+)$ && ! -f "$file/${BASH_REMATCH[1]}.txt" ]]; then
echo $file;
fi
done
How it works:
=~
) that the file/folder's name is "A_" followed by number.${BASH_REMATCH[1]}
{number}.txt
.Upvotes: 0
Reputation: 34924
Since the A_[0-9] directories are not nested, you can easily do this with a glob in a loop. This implementation is pure bash, and does not spawn in external utilities:
for d in A_[0-9]*/; do # the trailing / causes only directories to be matched
files=("$d"/[0-9]*.txt) # populate an array with matching text files
((!${#files})) && echo "$d" # echo $d if the array is empty
done
There are some problems with this implementation. It will match a file such as "12ab.txt" and requires loading all the filenames for a directory into the array.
Here is another method in bash that does a more accurate filename matching:
re='^[0-9]+[.]txt$'
for d in A_[0-9]*/; do
for f in *; do
if [[ -f $f && $f =~ $re ]]; then
echo "$d"
break
fi
done
done
Upvotes: 1