You are not logged in.

#1 2017-01-13 14:13:29

anatolik
Developer
Registered: 2012-09-27
Posts: 458

[SOLVED] bash: delete all files except matching some glob

In my PKGBUILD (i.e. bash) file I need to clean a package directory. Basically I have a list of files/directories that I want to preserver and delete everything else. Here is an example of such list:

Rakefile
ext/build/*.a
vendor/foo/include/

I want to delete all the files/directories in "." that do not match any of the the patterns above. A pattern can be path to directory (in this case whole directory shall be preserved) and/or a glob.

I can't find an elegant bash way to do it. Maybe someone can help me?

Last edited by anatolik (2017-01-14 00:53:19)


Read it before posting http://www.catb.org/esr/faqs/smart-questions.html
Ruby gems repository done right https://bbs.archlinux.org/viewtopic.php?id=182729
Fast initramfs generator with security in mind https://wiki.archlinux.org/index.php/Booster

Offline

#2 2017-01-13 14:42:56

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 29,449
Website

Re: [SOLVED] bash: delete all files except matching some glob

find . ! -name "Rakefile" ! -path "ext/build/*.a" ! -path "vendor/foo/include/*" -delete

Should work.  But replace -delete with -print or similar first to test.

Really the Rakefile could also use a -path option and it'd be fine.  If you have a text file list of these matches, you could assemble the find command using -path with each line.  If you cannot modify the text file to include an asterisk after directories (e.g., your vendor/foo/include/) you'd need to preprocess the file or each line to append the asterisk to lines ending in /

As an alternative, wouldn't it be possible to do everything in a staging directory (somewhere in srcdir, or in a builddir) then just copy/move the needed files from there to pkgdir.  I assume this has been ruled out for some reason, but I can't imagine what would prevent this from being possible.


"UNIX is simple and coherent..." - Dennis Ritchie, "GNU's Not UNIX" -  Richard Stallman

Offline

#3 2017-01-13 15:45:22

mis
Member
Registered: 2016-03-16
Posts: 234

Re: [SOLVED] bash: delete all files except matching some glob

Trilby wrote:
find . ! -name "Rakefile" ! -path "ext/build/*.a" ! -path "vendor/foo/include/*" -delete

This won't work

man find wrote:

Note that the pattern match test applies to the whole file name, starting from one of the start points named on the command line.

the -path patterns must be changed to

"*ext/build/*.a"     "*vendor/foo/include*"

or, if the target patterns are in the root of the search directory:

"./ext/build/*.a"     "./vendor/foo/include*"

Not sure if it's elegant, but there is also the -regex option.

find . ! -regex '.*\(Rakefile\|ext/build/.*\.a\|vendor/foo/include.*\)$' -delete

Offline

#4 2017-01-13 16:16:30

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 29,449
Website

Re: [SOLVED] bash: delete all files except matching some glob

Ah, right.  But I'd definitely only prepend ./ not * as the later could get a lot of unintended matches where something anything like Rakefile in any subdirectory would also match.  The regex approach is probably better, but again not using any prefix, just ./


"UNIX is simple and coherent..." - Dennis Ritchie, "GNU's Not UNIX" -  Richard Stallman

Offline

#5 2017-01-13 16:33:54

mis
Member
Registered: 2016-03-16
Posts: 234

Re: [SOLVED] bash: delete all files except matching some glob

Ah, didn't think about unintended matches enough. Then I would just prepend  / , though it becomes a bit unreadable..

find . ! -regex '.*\(/Rakefile\|/ext/build/.*\.a\|/vendor/foo/include.*\)$' -delete

Offline

#6 2017-01-13 16:39:40

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 29,449
Website

Re: [SOLVED] bash: delete all files except matching some glob

No, you missed my point, the problem isn't just names like 'fooRakefile' but a file named Rakefile in a subdirectory - you need to get rid of the leading wildcard matching:

$ touch Rakefile
$ mkdir subdir
$ touch subdir/Rakefile
$ find . -regex '.*\(/Rakefile\|/ext/build/.*\.a\|/vendor/foo/include.*\)$' -printf "%p\n"
./subdir/Rakefile
./Rakefile
$ find . -regex '\./\(Rakefile\|ext/build/.*\.a\|vendor/foo/include.*\)$' -printf "%p\n"
./Rakefile

Match against the provided names prepended with a literal "./" not prepended with any wildcard match.


"UNIX is simple and coherent..." - Dennis Ritchie, "GNU's Not UNIX" -  Richard Stallman

Offline

#7 2017-01-13 17:07:29

frostschutz
Member
Registered: 2013-11-15
Posts: 1,409

Re: [SOLVED] bash: delete all files except matching some glob

In a script (which you will test and verify), a monster like find delete is probably the way to go.

On interactive shells, I prefer to stick to simple commands, so I invert this problem. Make a new directory, copy the files I want to keep. The old directory can be deleted as a whole, at a later time, when I'm sure I no longer need it.

In a build script (make clean or whatever) I would expect that the files to be deleted are listed explicitely. Otherwise you'd inadvertently remove too much.

For example in a C project you could state to keep *.c *.h but maybe you're editing and the editor has created a #foobar.c# temporarily, or you tried to patch it and thus you have a *.rej file with failed patches, or someone added a readme, or whatever...

It's easy to delete things but hard to make sure you'll never delete too much.

Offline

#8 2017-01-13 17:39:44

mis
Member
Registered: 2016-03-16
Posts: 234

Re: [SOLVED] bash: delete all files except matching some glob

Trilby wrote:

... the problem isn't just names like 'fooRakefile' but a file named Rakefile in a subdirectory

I thought that was the goal, delete find all files named Rakefile... wink

edit: same as  -name "Rakefile"

Last edited by mis (2017-01-13 17:59:37)

Offline

#9 2017-01-13 18:49:24

anatolik
Developer
Registered: 2012-09-27
Posts: 458

Re: [SOLVED] bash: delete all files except matching some glob

mis wrote:

I thought that was the goal, delete find all files named Rakefile... wink

In my example above the goal is to match a file called exactly 'Rakefile' and located exactly in the root directory.

Thank you folks for the ideas, let me try to script them.


Read it before posting http://www.catb.org/esr/faqs/smart-questions.html
Ruby gems repository done right https://bbs.archlinux.org/viewtopic.php?id=182729
Fast initramfs generator with security in mind https://wiki.archlinux.org/index.php/Booster

Offline

#10 2017-01-14 00:52:15

anatolik
Developer
Registered: 2012-09-27
Posts: 458

Re: [SOLVED] bash: delete all files except matching some glob

Using -path and -regexp quickly leads to unreadable command line and requires a lot of text escaping. So I decided what Trilby suggested - just copy files to temp dir and then replace current directory. It works well. Thank you all.


Read it before posting http://www.catb.org/esr/faqs/smart-questions.html
Ruby gems repository done right https://bbs.archlinux.org/viewtopic.php?id=182729
Fast initramfs generator with security in mind https://wiki.archlinux.org/index.php/Booster

Offline

Board footer

Powered by FluxBB