LinuxQuestions.org
Review your favorite Linux distribution.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices

Reply
 
Search this Thread
Old 12-09-2012, 12:16 PM   #1
adol83
Member
 
Registered: Jul 2012
Location: Rome
Distribution: RHEL6, CentOs
Posts: 92

Rep: Reputation: 1
Scripting - Removing all files but.


Hello to everyone,

I have a directory with some files. I would like some scripts to remove any files but.

For example, under /directory

I have

file1 file2 directory1 directory2

I was thinking to do

Code:
rm -rf * |grep ^file1
to remove any file and directory but file1. Is that correct?
What if I have "file1" under "directory2" ?

I hope I've explained myself. Thank you for paying attention.
 
Old 12-09-2012, 01:17 PM   #2
ntubski
Senior Member
 
Registered: Nov 2005
Distribution: Debian
Posts: 2,541

Rep: Reputation: 878Reputation: 878Reputation: 878Reputation: 878Reputation: 878Reputation: 878Reputation: 878
Quote:
Originally Posted by adol83 View Post
I was thinking to do

Code:
rm -rf * |grep ^file1
to remove any file and directory but file1. Is that correct?
No, it's not correct. That removes all files and directories in the current directory and checks the output of rm (Note: rm outputs nothing) for lines starting with "file1".

Instead try find:
Code:
find . ! -name file1 -print  # list   all files and directories except file1
find . ! -name file1 -delete # delete all files and directories except file1
 
1 members found this post helpful.
Old 12-09-2012, 02:14 PM   #3
firstfire
Member
 
Registered: Mar 2006
Location: Ekaterinburg, Russia
Distribution: Debian, Ubuntu
Posts: 640

Rep: Reputation: 375Reputation: 375Reputation: 375Reputation: 375
Hi.

In recent versions of bash you may use extended patterns:

Quote:
If the extglob shell option is enabled using the shopt builtin, several extended pattern matching
operators are recognized. In the following description, a pattern-list is a list of one or more pat‐
terns separated by a |. Composite patterns may be formed using one or more of the following sub-pat‐
terns:

?(pattern-list)
Matches zero or one occurrence of the given patterns
*(pattern-list)
Matches zero or more occurrences of the given patterns
+(pattern-list)
Matches one or more occurrences of the given patterns
@(pattern-list)
Matches one of the given patterns
!(pattern-list)
Matches anything except one of the given patterns
(man bash)

For example, to remove all files except file1, type
Code:
rm !(file1)
 
Old 12-10-2012, 06:16 AM   #4
adol83
Member
 
Registered: Jul 2012
Location: Rome
Distribution: RHEL6, CentOs
Posts: 92

Original Poster
Rep: Reputation: 1
In gnu-Bash 2.05b

directory /tmp
files in directory : file1 file2 file3

Code:
 rm * !(file1) 
-bash: !: event not found
Why "event" ?
---

Same Bash shell,

Code:
find . ! -name file2 -print
output is ok (file1, file3)

but

Code:
find . ! -name file2 -delete
find: invalid predicate `-delete'

Last edited by adol83; 12-10-2012 at 06:19 AM.
 
Old 12-10-2012, 11:14 AM   #5
firstfire
Member
 
Registered: Mar 2006
Location: Ekaterinburg, Russia
Distribution: Debian, Ubuntu
Posts: 640

Rep: Reputation: 375Reputation: 375Reputation: 375Reputation: 375
Hi.

Your bash version is by no means recent (4.2). Again, looking into man bash, read about events:
Quote:
Event Designators
An event designator is a reference to a command line entry in the history list. Unless the reference
is absolute, events are relative to the current position in the history list.

! Start a history substitution, except when followed by a blank, newline, carriage return, = or (
(when the extglob shell option is enabled using the shopt builtin).
!n Refer to command line n.
!-n Refer to the current command minus n.
!! Refer to the previous command. This is a synonym for `!-1'.
!string
Refer to the most recent command preceding the current position in the history list starting
with string.
!?string[?]
Refer to the most recent command preceding the current postition in the history list containing
string. The trailing ? may be omitted if string is followed immediately by a newline.
^string1^string2^
Quick substitution. Repeat the previous command, replacing string1 with string2. Equivalent
to ``!!:s/string1/string2/'' (see Modifiers below).
!# The entire command line typed so far.
Try this:
Code:
$ find . ! -name file2 -print0 | xargs -0 rm
or
Code:
$ find . ! -name file2 | xargs rm
 
1 members found this post helpful.
Old 12-10-2012, 12:39 PM   #6
ntubski
Senior Member
 
Registered: Nov 2005
Distribution: Debian
Posts: 2,541

Rep: Reputation: 878Reputation: 878Reputation: 878Reputation: 878Reputation: 878Reputation: 878Reputation: 878
Quote:
Originally Posted by adol83 View Post
In gnu-Bash 2.05b

directory /tmp
files in directory : file1 file2 file3

Code:
 rm * !(file1) 
-bash: !: event not found
  1. The "!(file)" is supposed to replace the "*", what you wrote above would delete all files, and also all files that are not "file1" (meaning it would attempt to delete file2 and file3 twice).
  2. Possibly the version of bash you're using doesn't support extended globs, but even if does you need to do shopt -s extglob first.
  3. Use set +H to turn off history expansion (that's the event thing).
 
1 members found this post helpful.
Old 12-12-2012, 04:20 AM   #7
adol83
Member
 
Registered: Jul 2012
Location: Rome
Distribution: RHEL6, CentOs
Posts: 92

Original Poster
Rep: Reputation: 1
Firsfire

Code:
Try this:
 

Code:
$ find . ! -name file2 -print0 | xargs -0 rm or
 

Code:
$ find . ! -name file2 | xargs rm 
__________________
Worked. Thank you, I close the post but that would be useful to understand a little bit how works scripts.
 
Old 12-12-2012, 04:58 AM   #8
firstfire
Member
 
Registered: Mar 2006
Location: Ekaterinburg, Russia
Distribution: Debian, Ubuntu
Posts: 640

Rep: Reputation: 375Reputation: 375Reputation: 375Reputation: 375
Hi.

find produces a list of files to be deleted and xargs runs a given command (rm) with paths from that list as arguments (it may even run rm a few times if the list is too long for a single command). The only difference between these two commands is the delimiter between the items. From man xargs:
Quote:
xargs reads items from the standard input, delimited by blanks (which can be protected with double or single quotes or a backslash) or newlines,
and executes the command (default is /bin/echo) one or more times with any initial-arguments followed
by items read from standard input. Blank lines on the standard input are ignored.

Because Unix filenames can contain blanks and newlines, this default behaviour is often problematic;
filenames containing blanks and/or newlines are incorrectly processed by xargs. In these situations
it is better to use the -0 option, which prevents such problems. When using this option you will
need to ensure that the program which produces the input for xargs also uses a null character as a
separator. If that program is GNU find for example, the -print0 option does this for you.
 
1 members found this post helpful.
Old 12-12-2012, 06:24 AM   #9
adol83
Member
 
Registered: Jul 2012
Location: Rome
Distribution: RHEL6, CentOs
Posts: 92

Original Poster
Rep: Reputation: 1
So you're saying that "xargs" does echo with the input?

Code:
find . ! -name file2 | xargs mv * ../
This command, as sample, should move all files but file2 to the upper directory by what you mean?
 
Old 12-12-2012, 07:49 AM   #10
firstfire
Member
 
Registered: Mar 2006
Location: Ekaterinburg, Russia
Distribution: Debian, Ubuntu
Posts: 640

Rep: Reputation: 375Reputation: 375Reputation: 375Reputation: 375
Quote:
Originally Posted by adol83 View Post
So you're saying that "xargs" does echo with the input?

Code:
find . ! -name file2 | xargs mv * ../
This command, as sample, should move all files but file2 to the upper directory by what you mean?
No. What 'find . ! -name file2 | xargs mv * ../' does by default is roughly equivalent to
Code:
mv * ../ $(find . ! -name file2)
that is the output of find is appended to command line arguments of rm. Your example with mv won't work as expected -- insert echo before mv and look at the output. You can do this with xargs as follows:
Code:
find . ! -name file2 | xargs -I{} echo mv {} ../
Remove echo to actually move files. In this case xargs replaces {} in 'mv {} ../' by strings read from standard input. This kind of usage, I believe, can be better expressed using an explicit for loop.
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
removing some files rng Linux - General 4 12-13-2011 08:01 AM
manually removing the .vdi files left over after removing VirtualBox adityavpratap Linux - General 2 10-24-2010 01:04 PM
removing files kjs Linux - Software 1 02-17-2005 03:18 PM
Removing files wihtout removing containing Direcotry caps_phisto Linux - General 2 10-07-2004 09:16 AM
Removing files ascii2k Linux - General 2 11-26-2001 12:20 PM


All times are GMT -5. The time now is 05:00 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration