You are not logged in.

#1 2009-10-27 03:18:22

Ranguvar
Member
Registered: 2008-08-12
Posts: 2,549

[SOLVED] Simple Bash, delete all except

Really annoying me, though simple.

Say I have a directory, foo.  I also have an array of paths of files AND folders under 'foo' that I want to keep -- but I want to delete everything else.  The kept files should retain their permissions and such.

Is there a simple way? hmm  I've dug through 'find', maybe I missed something... will check again tomorrow.

Thanks.

Last edited by Ranguvar (2009-10-27 21:44:07)

Offline

#2 2009-10-27 04:21:41

chpln
Member
From: Australia
Registered: 2009-09-17
Posts: 361

Re: [SOLVED] Simple Bash, delete all except

'find' would work if you are able to formulate an expression for the paths, but I don't believe it can be made to utilise an array.  Personally, I'd just resort to something a little more primitive:

#!/bin/bash

literal_paths=(subdir1/file.foo subdir2/file.bar) # Add literal paths relative to 'foo' here.
tempdir="../foo-tmp"
for file in ${literal_paths[@]}; do
    mkdir -p "$tempdir/$(dirname "$file")"
    mv "$file" "$tempdir/$file"
done

Confirm everything required has been moved, then:  "rm -rf foo; mv foo-tmp foo".

Last edited by chpln (2009-10-27 04:26:43)

Offline

#3 2009-10-27 04:50:34

sctincman
Member
From: CO (USA)
Registered: 2009-04-08
Posts: 85

Re: [SOLVED] Simple Bash, delete all except

Why not something like

rm -r `ls -d foo/* | sed /regexpres/`

I can never remember regular expressions, but I'm sure theres a way to format it to pull out any matches.

edit: Also just found an option for ls in the manpage, --ignore=PATTERN that might be good to look into

Last edited by sctincman (2009-10-27 04:54:17)

Offline

#4 2009-10-27 08:28:25

scragar
Member
Registered: 2009-07-14
Posts: 108

Re: [SOLVED] Simple Bash, delete all except

sctincman wrote:

Why not something like

rm -r `ls -d foo/* | sed /regexpres/`

I can never remember regular expressions, but I'm sure theres a way to format it to pull out any matches.

edit: Also just found an option for ls in the manpage, --ignore=PATTERN that might be good to look into

That would be horrible for file names with spaces in, might be a good idea to use xargs instead.

ls --ignore=PATTERN foo/parent | xargs rm -rf

I do however recommend checking that code before running it, I'd hate to think you'd delete something you want.

Offline

#5 2009-10-27 15:06:55

steve___
Member
Registered: 2008-02-24
Posts: 452

Re: [SOLVED] Simple Bash, delete all except

You can use extented globs.  Something like:

shopt -s extglob ; rm !(files_to_keep.txt) ; shopt -u extglob

Offline

#6 2009-10-27 15:14:16

Daenyth
Forum Fellow
From: Boston, MA
Registered: 2008-02-24
Posts: 1,244

Re: [SOLVED] Simple Bash, delete all except

The safest way would be to move the stuff you want and remove all else. Every other method has a lot of risks.

Offline

#7 2009-10-27 15:17:26

sctincman
Member
From: CO (USA)
Registered: 2009-04-08
Posts: 85

Re: [SOLVED] Simple Bash, delete all except

scragar wrote:
sctincman wrote:

Why not something like

rm -r `ls -d foo/* | sed /regexpres/`

I can never remember regular expressions, but I'm sure theres a way to format it to pull out any matches.

edit: Also just found an option for ls in the manpage, --ignore=PATTERN that might be good to look into

That would be horrible for file names with spaces in, might be a good idea to use xargs instead.

ls --ignore=PATTERN foo/parent | xargs rm -rf

I do however recommend checking that code before running it, I'd hate to think you'd delete something you want.

Very true! didn't think about that. Have never heard of xargs, but looking at the man page looks like it will run into the same problem

Because  Unix  filenames  can contain blanks and newlines, this default
       behaviour is often problematic; filenames containing blanks and/or new‐
       lines  are  incorrectly  processed by xargs.  In these situations it is
       better to use the -0 option, which prevents such problems.

but, -0 expects null terminated items, so I think ls needs to be changed too, but can't find any null terminated options for ls. How about this?

ls -1 --ignore=PATTERN foo/parent | xargs -d '\n' rm -r

Not sure how many files have newlines in their name.

Offline

#8 2009-10-27 15:23:50

brisbin33
Member
From: boston, ma
Registered: 2008-07-24
Posts: 1,796
Website

Re: [SOLVED] Simple Bash, delete all except

Daenyth is right, if you have an /array/ of paths to keep then just use a for loop through the array to cp -a then to a safe place, rm -rf all else and cp -a it back.

on the other hand, if you have a /regex/ representing the paths to keep then find ./foo ! -name 'regex' -exec rm -rf {} \; always works great for me.  replace rm with ls for a test run of course.

with the array, you can even use the for loop to build a find command that ends up like...

find ./foo ! -wholename ./foo/path/to/keep1 ! -wholename ./foo/path/to/keep2 ... -exec rm -rf {} \;

that'd work well too.

Offline

#9 2009-10-27 15:33:51

Procyon
Member
Registered: 2008-05-07
Posts: 1,819

Re: [SOLVED] Simple Bash, delete all except

I tried to do it with find, but the spaces issue remained, in this case if you have spaces in the array items, so it needed eval. Maybe there's a better way to do it with find.

eval find -depth \\\( $(for file in "${skip[@]}"; do echo -n "-path ./'$file' -o " ; done | sed 's/ -o $//') \\\) -prune -o -delete

In this case -delete will try and fail to delete non-empty directories if you have only specified an item in a directory but not the directory itself.


EDIT:

brisbin33 wrote:

find ./foo ! -wholename ./foo/path/to/keep1 ! -wholename ./foo/path/to/keep2 ... -exec rm -rf {} \;

But then if you want to save everything in
./a

You would have to mention every file or something like this won't match:
./a/1.txt

Last edited by Procyon (2009-10-27 15:40:03)

Offline

#10 2009-10-27 16:05:44

brisbin33
Member
From: boston, ma
Registered: 2008-07-24
Posts: 1,796
Website

Re: [SOLVED] Simple Bash, delete all except

Yes Procyon, you're right; i hadn't thought through the subtleties of -wholename.  your first code block was basically what i was going for there.

Offline

#11 2009-10-27 19:37:58

Ranguvar
Member
Registered: 2008-08-12
Posts: 2,549

Re: [SOLVED] Simple Bash, delete all except

Thank everyone smile
I was going for the move-and-delete-and-move approach, but had some trouble:

_keep_files=('usr/bin/clang' 'usr/lib/clang' 'usr/libexec' 'usr/share/man/man1/clang.1.gz')
for i in "${_keep_files[@]}"; do
        cp -ar "$pkgdir/$i" "$srcdir/tmp/$i" || return 1
done
rm -rf "$pkgdir/"*
mv "$srcdir/tmp/"* "$pkgdir/" || return 1

This fails because it doesn't want to create non-existing folders.  I tried using install -D, but that won't install directories.
Bah.

EDIT: Never mind me, I'm silly and use loops and arrays when I could just do things manually tongue

Last edited by Ranguvar (2009-10-27 21:43:59)

Offline

#12 2009-10-27 21:49:22

brisbin33
Member
From: boston, ma
Registered: 2008-07-24
Posts: 1,796
Website

Re: [SOLVED] Simple Bash, delete all except

so this may or may not work wink

#!/bin/bash
#
# pbrisbin 2009
#
###

_keep_files=( 'usr/bin/clang'
              'usr/lib/clang'
              'usr/libexec'
              'usr/share/man/man1/clang.1.gz' )

move_them() {
  src="$1"; dst="$2"

  # create the dir if needed
  if [ ! -d "$(dirname "$dst")" ]; then
    mkdir -p "$dst" || return 1
  fi

  # -a is all that's needed
  cp -a "$src" "$dst" || return 1
}

for i in "${_keep_files[@]}"; do
  move_them "$pkgdir/$i" "$srcdir/tmp/$i" || return 1
done

rm -rf "$pkgdir/"*

for i in "${_keep_files[@]}"; do
  move_them "$srcdir/tmp/$i" "$pkgdir/$i" || return 1
done

Offline

#13 2009-10-27 21:50:01

brisbin33
Member
From: boston, ma
Registered: 2008-07-24
Posts: 1,796
Website

Re: [SOLVED] Simple Bash, delete all except

Ranguvar wrote:

EDIT: Never mind me, I'm silly and use loops and arrays when I could just do things manually tongue

hey! i introduced a function so what does that say about me?

Offline

#14 2009-10-27 22:07:23

xd-0
Member
From: Sweden
Registered: 2007-11-02
Posts: 327
Website

Re: [SOLVED] Simple Bash, delete all except

Example removes all files that are not png files in the current directory:

for i in `ls * | grep -v .png`; do rm $i; done

Should do it. Dunno if you are able to use wildcards in grep though.

Offline

#15 2009-10-27 22:34:14

brisbin33
Member
From: boston, ma
Registered: 2008-07-24
Posts: 1,796
Website

Re: [SOLVED] Simple Bash, delete all except

xd-0 wrote:

Dunno if you are able to use wildcards in grep though.

wha? that's like... like saying... "Dunno if we're allowed to eat tacos while working with cactus"

of course! cactus LOVES tacos!

EDIT: you do bring up a good point though, `ls | grep -vx "path/to/ignore1\|path/to/ignore2\|..."` might have been the simplest solution anyway...

Last edited by brisbin33 (2009-10-27 22:36:35)

Offline

#16 2009-10-27 23:03:24

Ranguvar
Member
Registered: 2008-08-12
Posts: 2,549

Re: [SOLVED] Simple Bash, delete all except

brisbin33 wrote:
xd-0 wrote:

Dunno if you are able to use wildcards in grep though.

wha? that's like... like saying... "Dunno if we're allowed to eat tacos while working with cactus"

of course! cactus LOVES tacos!

EDIT: you do bring up a good point though, `ls | grep -vx "path/to/ignore1\|path/to/ignore2\|..."` might have been the simplest solution anyway...

Perhaps, with some finagling, because that isn't recursive through the directory wink

Offline

Board footer

Powered by FluxBB