Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Recursively deleting all "*.foo" files with corresponding "*.bar" files

How can I recursively delete all files ending in .foo which have a sibling file of the same name but ending in .bar? For example, consider the following directory tree:

.
├── dir
│   ├── dir
│   │   ├── file4.bar
│   │   ├── file4.foo
│   │   └── file5.foo
│   ├── file2.foo
│   ├── file3.bar
│   └── file3.foo
├── file1.bar
└── file1.foo

In this example file.foo, file3.foo, and file4.foo would be deleted since there are sibling file{1,3,4}.bar files. file{2,5}.foo should be left alone leaving this result:

.
├── dir
│   ├── dir
│   │   ├── file4.bar
│   │   └── file5.foo
│   ├── file2.foo
│   ├── file3.bar
└── file1.bar
like image 561
knpwrs Avatar asked Jul 01 '14 18:07

knpwrs


3 Answers

Remember to first take a backup before you try this find and rm command.

Use this find:

find . -name "*.foo" -execdir bash -c '[[ -f "${1%.*}.bar" ]] && rm "$1"' - '{}' \;
like image 84
anubhava Avatar answered Nov 14 '22 23:11

anubhava


while IFS= read -r FILE; do
    rm -f "${FILE%.bar}".foo
done < <(exec find -type f -name '*.bar')

Or

find -type f -name '*.bar' | sed -e 's|.bar$|.foo|' | xargs rm -f
like image 29
konsolebox Avatar answered Nov 14 '22 22:11

konsolebox


In bash 4.0 and later, and in zsh:

shopt -s globstar   # Only needed by bash
for f in **/*.foo; do
    [[ -f ${f%.foo}.bar ]] && rm ./"$f"
done

In zsh, you can define a selective pattern that matches files ending in .foo only if there is a corresponding .bar file, so that rm is invoked only once, rather than once per file.

rm ./**/*.foo(e:'[[ -f ${REPLY%.foo}.bar ]]':)
like image 45
chepner Avatar answered Nov 14 '22 23:11

chepner