You are not logged in.
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? 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
'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
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
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
You can use extented globs. Something like:
shopt -s extglob ; rm !(files_to_keep.txt) ; shopt -u extglob
Offline
The safest way would be to move the stuff you want and remove all else. Every other method has a lot of risks.
[git] | [AURpkgs] | [arch-games]
Offline
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
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.
//github/
Offline
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:
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
Thank everyone
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
Last edited by Ranguvar (2009-10-27 21:43:59)
Offline
so this may or may not work
#!/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
//github/
Offline
EDIT: Never mind me, I'm silly and use loops and arrays when I could just do things manually
hey! i introduced a function so what does that say about me?
//github/
Offline
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
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)
//github/
Offline
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
Offline