Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I want to delete folders using regexp in a Mac terminal.

0129_0140 (no delete)
0140_0140 (delete)
0150_0160 (no delete)
0170_0170 (delete)

I just want to delete folders such as 0140_0140 , 0170_0170 .

(Added) I want to delete the nonempty folders, recursively.

share|improve this question
    
does mac have gnu find ? – 123 Feb 10 at 10:17
    
Yes, mac has the command find. – jakeoung Feb 10 at 10:19
    
@123, all unix-likes have a find command, but the find on OS/X is not GNU find. – Stéphane Chazelas Feb 10 at 10:23
    
@StéphaneChazelas Okay thanks – 123 Feb 10 at 10:23
    
@123, for future reference, OSX man pages: developer.apple.com/library/mac/documentation/Darwin/Reference/… – glenn jackman Feb 10 at 13:25
up vote 12 down vote accepted

Non-recursive

With ksh93 (on OS/X available as ksh):

rmdir {4}(\d)_\1

(beware it could delete a directory called {4}(\d)_\1 if there's no file matching that pattern).

With zsh (on OS/X available as zsh):

setopt extendedglob
rmdir [0-9](#c4)_[0-9]##(/e:'[[ ${REPLY%_*} = ${REPLY#*_} ]]':)

(that one also has the benefit of only considering files of type directory, using the / glob qualifier above).

With bash or other POSIX shell (like the sh of most systems including OS/X):

set -- [0-9][0-9][0-9][0-9]_[0-9][0-9][0-9][0-9]
for f do
  [ "${f#*_}" = "${f%_*}" ] && set -- "$@" "$f"
  shift
done
rmdir "$@"

(beware it could delete a directory called [0-9][0-9][0-9][0-9]_[0-9][0-9][0-9][0-9] if there are no XXXX_XXXX files in the current directory).

Using find and grep:

find . ! -name . -prune -type d -name '[0-9][0-9][0-9][0-9]_[0-9][0-9][0-9][0-9]' |
  grep -x '\./\(.*\)_\1' |
  xargs rmdir

With BSD find (as found on OS/X):

find . -maxdepth 1 -regex './\([0-9]\{4\}\)_\1' -type d -delete

With GNU find (as typically not found on OS/X unless installed via macports/homebrew/fink...):

find . -maxdepth 1 -regextype grep -regex './\([0-9]\{4\}\)_\1' -type d -delete

Recursively:

  • ksh93:

    set -o globstar
    rmdir -- **/{4}(\d)\1
    

    (beware that it won't remove 1111_1111 in case there's a 1111_1111/2222_2222 as it will try to remove the 1111_1111 one first which it can't as there's a 2222_2222 dir in it, ksh93 doesn't have the od glob qualifier (for depth-first order) of zsh)

  • zsh:

    setopt extendedglob
    rmdir -- **/[0-9](#c4)_[0-9]##(Dod/e@'[[ ${${REPLY:t}%_*} = ${REPLY##*_} ]]'@)
    
  • BSD find:

    LC_ALL=C find . -regex '.*/\([0-9]\{4\}\)_\1' -type d -delete
    
  • GNU find:

    LC_ALL=C find . -regextype grep -regex '.*/\([0-9]\{4\}\)_\1' -type d -delete
    
share|improve this answer
    
The command doesn't work for me. I also tried find . -regex '{4}([0-9])_\1', but it also failed. Could you explain about the command? – jakeoung Feb 10 at 10:22
    
Doesn't osx use bash (As default anyway) ? – 123 Feb 10 at 10:24
    
@jakeoung, shells are command line interpreters, the application that are usually started within terminal emulators like OS/X Terminal. By default terminal emulators usually start your login shell which by default on OS/X I believe is something like tcsh or bash. To start another shell, just enter its name at a shell prompt. zsh or ksh for instance. OS/X El Capitan at least has all of bash, zsh and ksh93 pre-installed. – Stéphane Chazelas Feb 10 at 10:45
1  
@jakeoung, well you never said it had to be recursive, the -prune is to explicitely tell it not to recurse. Please edit your answer to add the information, also specify whether you want to delete the directory contents as well (if those directories may not be empty), and if dirs like 0001_0001/0002_0002 may exist. – Stéphane Chazelas Feb 10 at 11:02
1  
@123, directories that are not empty cannot be removed obviously. See my comment for ksh93 in recursively – Stéphane Chazelas Feb 10 at 11:46

POSIX (remove echo from echo rmdir to actually erase the files) :

for dir in [0-9][0-9][0-9][0-9]_[0-9][0-9][0-9][0-9]/; do
    a="$(expr "$dir" : '\(.*\)_\1/')"
    ${a:+false} || echo rmdir "$dir"
done

Or:

for d in [0-9][0-9][0-9][0-9]_[0-9][0-9][0-9][0-9]/; do
    expr "$d" : '\(\(.*\)_\2\)/' >/dev/null && echo rmdir "$d"
done

Or:

set -- [0-9][0-9][0-9][0-9]_[0-9][0-9][0-9][0-9]/
for    d
do     expr "$d" : '\(\(.*\)_\2\)/' >/dev/null && echo rmdir "$d"
done
share|improve this answer

Try this:

find -type d -regextype posix-extended -regex '\./([0-9]{4})_\1' -delete

regex type setting is needed for the {4}.

share|improve this answer
    
Thats GNU find. – 123 Feb 10 at 10:33
1  
Note that POSIX extended regexps don't have backreferences, so that command might not work on all systems where GNU find is available if it's configured to use the system regexp library. Use posix-basic instead which has backreferences (also note that \{4\} was added to BRE before {4} was added to EREs (and broke backward portability when that happened which explains why the default regexps in GNU find don't support it for instance)). – Stéphane Chazelas Feb 10 at 10:54
    
A basic-regex is: find . -regextype posix-basic -regex '\./\([0-9]\{4\}\)_\1' – BinaryZebra Feb 10 at 11:30

A pair of simple, POSIX-compliant alternatives:

Non-recursive (newlines disallowed in basename):

ls -F | grep '^\([0-9]\{4\}\)_\1/$' | xargs rm -fr

Recursive:

find . -type d -exec expr {} : '.*/\([0-9]\{4\}\)_\1$' \; -prune \
       -exec rm -fr {} + >/dev/null
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.