简体   繁体   中英

Using shell to finds directories that do not have a specified pattern of files in the folder

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!

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

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

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
for file in *; do
  if [[ "$file" =~ ^A_([0-9]+)$ && ! -f "$file/${BASH_REMATCH[1]}.txt" ]]; then
    echo $file;
  fi
done

How it works:

  1. Checks using regexp (note the =~ ) that the file/folder's name is "A_" followed by number.
  2. At the same time, it captures the numbers (note the parentheses) and stores them in ${BASH_REMATCH[1]}
  3. Next, check if the folder contains {number}.txt .
  4. If it does not, echo the folder's name.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM