Wildcards and exceptions

Hello:

I have a very basic question. I'd like to select all files except for one file. For example, say I want to move all of the files in my current directory to a subdirectory called archive, I would use

mv ./* archive/

But what if I want to move all files except for README.txt? Is there an easy way to do this?

Thanks in advance.

Expansions like this in shell are usually called globs. Don't think there's a straightforward way with standard globbing.

Depending on your goal though, there may be other means. Why are you moving them to archive? If you want to create a tarball out of them, you could do so directly using tar's exclude options...

Thanks for the reply, Corona688. tar might be a good option then. Basically, I'm trying to write a script that takes all the directories in my current directory and put them in a subdirectory (or tar ball, I guess). So, I use

mv */ archive/

but get the warning

mv: cannot move `archive/' to a subdirectory of itself, `archive/archive'

I guess an alternative is just to suppress that output (i.e., redirect to /dev/null)?

Yeah, that would work.

Another option would be find, if you have the -maxdepth option. What's your system?

Mac OS X 10.8.2.

You don't have maxdepth, then unfortunately.

You can do this:

for FILE in *
do
        [ -d "$FILE" ] || continue # Ignore non-directories
        [ "$FILE" = "archive" ] && continue # Ignore archive folder

        # other stuff you want to do for each folder
done

If you have zsh you could use extended globbing:

zsh $ echo $ZSH_VERSION
5.0.2
zsh $ setopt extendedglob
zsh $ ls -l
total 0
drwxr-xr-x+ 1 chubler Users 0 Mar 13 06:33 archive
drwxr-xr-x+ 1 chubler Users 0 Mar 13 06:33 dir1
drwxr-xr-x+ 1 chubler Users 0 Mar 13 06:33 dir2
-rw-r--r--  1 chubler Users 0 Mar 13 06:36 file1
zsh $ echo ^archive(/)
dir1 dir2

Note that ksh and bash also support extended globbing.
The syntax is different from the one Chubler_XL mentioned;
zsh actually supports both (see the ksh_glob option).
With bash (adding archive to the exclude list for obvious reasons):

shopt -s extglob
mv -v -- !(@(README.txt|archive)) archive

[drop the -v switch, if your mv implementation doesn't support it]
The syntax above originates from the ksh, where it's enabled by default.

PS: The code won't work correctly when there are no matching files.

I seem to recall *cp -r uses cpio, so:

find ... | grep -v 'unwanted' | cpio -i... | ( cd dest ; cpio -od... )

I think the OP only wants to match directories.

I don't think bash/ksh extended globbing has an equivalent of the (/) glob qualifier

Edit: Nice DGPickett, I had something similar in mind, with an xargs at then end of the pipe, but I gave up on that when I realized the OSX mv doesn't support -t DIRECTORY

Sorry for not reading carefully.
All shells have <glob>/ :

$ mkdir archive dir{1..3}
$ touch file{1..3} README.txt
$ shopt -s extglob
$ mv -v -- !(@(README.txt|archive))/ archive
`dir1/' -> `archive/dir1'
`dir2/' -> `archive/dir2'
`dir3/' -> `archive/dir3'
1 Like

Actually, if README.txt is not a directory, this should be sufficient (extended glob is not needed):

mv -- */ archive

To get rid of the error message about moving the archive directory (and if 2>/dev/null is not an option, because the
exit status is important), with extended glob:

shopt -s extglob
mv -- !(archive)/ archive

Note that you may need to add some code/option to handle the case when no directory matches
or when you want to include hidden directories.

I believe I saw a similar subtree copy utility with tar, but it did not have a way to exclude files. Havng the file list allows you to do tricky things like sorting by extension and then by path so similar files hit a compressor in the middle before an ssh/rsh to another host over the network where you decompress and cpio -o. It optimizes the compression that effectively multiplies the network speed. I like the simple, modular tools, but you can do something similar with rsync using 'ssh -C -o CompressionLevel=9'. Looking at the man, I see rsync allows you to exclude files, and it says GNU tar does, too: Man Page for rsync (all Section 0) - The UNIX and Linux Forums

-maxdepth is available in OS X's find.

$ sw_vers -productVersion                      
10.8.2

$ man find | col -b | grep -A1 -- -maxdepth    
     -maxdepth n
	     Always true; descend at most n directory
1 Like

Glad someone cleared that up. I saw -maxdepth was in the find manual for 10.6.2 hosted here, but I didn't have access to 10.8.2 to check it hadn't been removed.

Yes, it's still there.

We should perhaps update the man pages for the platforms that have changed since we implemented man page feature.

Volunteers welcome :slight_smile:

I like the die.net ones: find(1) - Linux man page

Maybe we should not duplicate other internet efforts. The ones here do not make it to Google's first page: man page find linux - Google Search

You've linked to a Linux manual page.

We wanted a place to find all platforms manual pages in one place.

That was why we started this.

Yes, you support several popular flavors, but there are always those on old or odd. This gets a bit confusing as the search can range across many potential targets but one is silently preferred. Really, if there are many, the choose page should always come up.

Every flavor is supported elsewhere, if you trusted them enough to link them in. Less overhead but more fragile, and I suppose they might not like being linked in!

I have no idea what you just said.