2

I have this situation where I want to exclude a directory while using the mv command. I saw this example where the syntax would be !(exclude_dir), but when I set up a scenario to test it I get results that I don't fully understand.

Now I have created three folders: f1,f2 and f3. Now I use the command in this way:

mv -t f3/ !(f1) f2

This produces this error:

mv: cannot move 'f3' to a subdirectory of itself, 'f3/f3'
mv: cannot stat 'f2': No such file or directory

Now funny thing is the structure of the folder is now:

.
├── f1
└── f3
    └── f2

3 directories, 0 files

It does what I want but why the error messages. Obviously I am not using that command correctly.

7

This doesn't have anything to do with mv, but is a bash feature, citing man bash:

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 patterns separated by a |. Composite patterns may be formed using one or more of the following sub-patterns:

!(pattern-list)
Matches anything except one of the given patterns

!(f1) matches f2 f3 in your example, so effectively you're doing:

mv -t f3/ f2 f3 f2

To achieve your goal you should rather do:

mv -t f3/ !(f[13]) # or !(f1|f3)

This expression matches everything except f1 and f3.

This also works with *, ? and […]:

$ ls
e1  e2  e3  f1  f2  f3
$ ls !(e*|?[12])
f3
4

!(f1) is an extended glob expression, so (provided the extglob shell option is set) it expands to a list of (non)-matching files. In other words, if your directory originally contained f1, f2, f3 then

mv -t f3/ !(f1) f2

expands as

mv -t f3/ f2 f3 f2

The first error should be obvious; the second is because it attempts to move f2 twice - and fails the second time.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.