How to exclude a folder when using the mv command

27,890

Solution 1

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

Then, it successfully moves f2 to f3, raises the first error trying to move f3 to itself, and raises the second error when trying to move f2 to f3 again because it was already moved and is no longer in the current directory.

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

Solution 2

!(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.

Solution 3

If you're looking for a way to backup current files, it would be safer to split the move command into copy & remove. For example:

# Allow wildcard and hidden files search
shopt -s extglob dotglob

# Make a new directory (skip if exists)
mkdir -p BACKUP

# Copy all files to BACKUP (-a to keep attributes, -f to overwrite existing)
cp -af !(BACKUP) BACKUP/

# Remove all files except BACKUP (and hidden files starting with ".keep")
rm -rf !(BACKUP|.keep*)
Share:
27,890

Related videos on Youtube

George Udosen
Author by

George Udosen

Fullstack developer | Python | GCP, Azure Cloud Certified | AWS & Azure Cloud Savy | Linux Sysadmin | Bash script writer | Google IT Support Professional...

Updated on September 18, 2022

Comments

  • George Udosen
    George Udosen almost 2 years

    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.