130

Consider:

ls -al ../public-back
drwxrwxr-x  4 apache   apache     4096 Apr 19 03:32 templates

ls -al ../public-back/templates

drwxrwxr-x  2 apache   apache    4096 Apr 19 03:33 content
drwxrwxr-x  2 apache   apache   20480 Apr 20 06:14 images
drwxrwxr-x  2 apache   apache    4096 Apr 19 03:35 video

ls -al /public

drwxrwxr-x  4 apache   apache     4096 Apr 20 09:49 templates

ls -al /public/templates

drwxrwxr-x  2 apache   apache    4096 Apr 20 09:50 content
drwxrwxr-x  2 apache   apache    4096 Apr 20 09:50 images
drwxrwxr-x  2 apache   apache    4096 Apr 20 09:50 video

How do I move the contents of /public-back/templates recursively with permissions into /public/templates?

Peter Mortensen
  • 12,090
  • 23
  • 70
  • 90
siliconpi
  • 2,687
  • 6
  • 25
  • 28

9 Answers9

153

Unless I am misunderstanding the question, this would work:

mv /public-back/templates/* /public/templates

Also, unless you have a huge list of files, adding -i will ask before it overwrites anything, which add some safety when using wildcards like *.

Peter Mortensen
  • 12,090
  • 23
  • 70
  • 90
DQdlM
  • 2,679
  • 4
  • 22
  • 25
  • 36
    This does not move hidden files. – Arda Sep 26 '14 at 23:34
  • 5
    See http://askubuntu.com/a/259386/358964 for setting dotglob so hidden files will also be moved. – mkobit Aug 21 '15 at 13:58
  • 7
    Note: This will not overwrite files in subdirectories. You will get a `Directory not empty` message. – Armstrongest Oct 16 '15 at 18:34
  • 1
    Seems that it flattened the directory hierarchy. Did not preserve folders within the original folder for me. All files ended up in the same folder, rather than literally moving the original folder with the same structure. – Robert Noack Jan 24 '16 at 17:33
  • This solution works, but if you see this error: `mv: target '/public/templates' is not a directory` just create the destination folder manually: `mkdir /public/templates`. – Ali Shabdar Mar 02 '18 at 07:17
  • 1
    Note: To move the hidden files and folders, use: `mv /public-bak/templates/.[!.]* /public/templates`. – Ali Shabdar Mar 02 '18 at 08:24
  • This breaks if you have too many files. For example, I was migrating a directory with twenty thousand images into its parent and needless to say, the `*` expands in bash prior to the mv command being called. A better methodology is to use `find ... -exec mv ...` or an `xargs` equivalent. – Supernovah May 21 '20 at 04:22
  • @AliShabdar That is wrong, it is actually supposed to be braces not bracket: so like this: ```mv /public-bak/templates/{.,}* /public/templates ``` – Rami Apr 08 '23 at 03:08
20

The man page for cp states:

-p same as --preserve=mode,ownership,timestamps
-r same as --recursive=copy directories recursively

Try;

cp -rp /public-back/templates/* /public/templates/
Himalay
  • 403
  • 1
  • 5
  • 14
  • 25
    `mv` is for _move_, while `cp` is for _copy_ – a semantical/etymological distinction. – Marius Butuc Mar 19 '13 at 17:34
  • 3
    `cp` is way slower than `mv`. `cp` forces the computer to copy everything from the disk to RAM, and then write it to the disk again which may take a long time depending on the size of the files. However, `mv` always happens instantly because only the links have to be rewritten. – tjespe Mar 07 '17 at 18:40
  • @Marius Butuc What? First, move is like cut and paste, while copy preserves the original. that's not just a semantic difference. Second, why are you talkintg about mv? How in the world does that comment have 16 votes. it's flat out wrong. – ahnbizcad Jun 09 '20 at 02:03
  • -1: The TO asks about `move`, not `copy` – Putnik Oct 06 '22 at 17:59
11

When moving items from my thumb drive to my OSMC system, I've found the following very useful:

find /media/Pi\ Hard\ 16GB/ -name '*' -exec mv -v {} /media/External\ HDD/Videos/ \;

Explanation on how it works below.

BTW, Don't forget to add a backslash before any spaces in the source or destination directory names (see above).

find  finds all files and folders in the destination path.

/media/Pi Hard 16GB/ is the path searched. Escape special char such as spaces.

-name '*' filters on names. If you do not escape or quote this then 
          the shell will expand it before find sees it.

-exec     Executes a command, in our case mv

-v        Verbose, so you can see what's happening (optional)

{}        is replaced by the name of the found object.

Effectively, you are finding all files and all folders and moving them one by one (or if a directory gets found first, you are moving that directory and the contents in it). This starts a new process for each move and is very inefficient. Only use this when the regular commands fail.

Pi Hard
  • 121
  • 1
  • 5
5

It is possible to move instead of copy with rsync by using the --remove-source-files argument. This will preserve properties such as permissions and dates modified. It has the added benefit of checking whether files don't need to be moved to the target directory (i.e., if a newer file with the same name already exists there).

rsync -arctuxz --remove-source-files /public-back/templates /public/templates/

Of course you can also copy the files and remove the original directory.

mkdir -p /public/templates
rsync -arctuxz --remove-source-files /public-back/templates /public/templates/
rm -rfi /public-back/templates/

This is my recommended parameters for rsync but there are other arguments for preserving various properties or handling links and compression/encryption of large files. This command also supports copying to remote file systems via ssh tunnels.

Tom Kelly
  • 151
  • 1
  • 4
  • 1
    It doesn't seem to move hidden files (eg: .htaccess), nor any content within folders which are hidden as well (eg: files within .git/ ) – siliconpi Apr 15 '22 at 07:39
  • rsync does support hidden files actually: https://unix.stackexchange.com/a/454474/172987 – Tom Kelly Apr 22 '22 at 07:51
5

mv doesn't seem to do this. But you can use this little trick, works like a charm:

tar cf - . |(cd /targetdir; tar xvf -)

and preserves permissions and all.

Note: none of the above worked for me, that's why this workaround.

svye
  • 151
  • 1
  • 2
3
cp -a --link ../public-back/* /public/.  &&  rm -rf ../public-back

So create hard links in the destination directory and remove the source dir. 'mv' simply will not work in your case, and in general works only when source dir and dest have no common subtrees.

Note that I'm assuming that the word 'move' in the question means that the source dir should be gone after the operation.

Boudewijn
  • 31
  • 1
2

None of the answers in this thread fit my usecase, so I came up with one on my own as a shell script.

At the heart of it is this function:

recurse() {
    if [ ! -d "$1" ] || [ ! -e "$2" ]; then
        mv -u "$1" "$2" || exit
        return
    fi
    for entry in "$1/"* "$1/."[!.]* "$1/.."?*; do
        if [ -e "$entry" ]; then
            recurse "$entry" "$2/${entry##"$1/"}"
        fi
    done
}

Which you could invoke like so (for the OP usecase):

recurse /public-back/templates /public/templates

If source is a file or a directory for which the destination does not exist yet, it simply moves it with mv -u. If source is a directory for which the destination already exists, it iterates through its contents and recursively performs the same check followed by move|recurse with each of its members.

I used -u because I only needed old files freshened and newer files untouched, but you could replace it with -f for an unconditional move or -i for an interactive one. Or not change anything and simply rm -rf your source after the script is done moving things.

[A slightly modified repost from Server Fault]

antichris
  • 1,166
  • 7
  • 14
1

You can move the normal files with the following:

mv /path/to/source/* /path/to/destination/

Then move the hidden files with this:

mv /path/to/source/.* /path/to/destination/

You will get errors telling you that . and .. cannot be moved, but that's not a problem.

  • This solution is very simple and the most practical for most use cases. It gets the job done, and it's easy to memorize. – Jaacko Torus Aug 19 '23 at 20:17
0

As noted above, on the same filesystem mv is faster than cp. By example, the following preserves timestamps and ownerships, and recursively moves directories and files including hidden files and directories.

Initial conditions:

  • note ownership of dir02/* is root:victoria
[victoria@victoria test]$ tree -La 5 -F
.
└── hourly.0/
    ├── .dir01/
    ├── dir01/
    │   ├── .dir02/
    │   ├── dir02/
    │   │   ├── .dir03/
    │   │   ├── dir03/
    │   │   │   ├── .file03
    │   │   │   └── file03
    │   │   ├── .file02
    │   │   └── file02
    │   ├── .file01
    │   └── file01
    ├── .file00
    └── file00

7 directories, 8 files

[victoria@victoria test]$ ls -laR
.:
total 12
drwxr-xr-x 3 victoria victoria 4096 Apr 27 10:04 .
drwxrwxr-x 4 victoria victoria 4096 Apr 27 09:19 ..
drwxr-xr-x 4 victoria victoria 4096 Apr 27 09:45 hourly.0

./hourly.0:
total 16
drwxr-xr-x 4 victoria victoria 4096 Apr 27 09:45 .
drwxr-xr-x 3 victoria victoria 4096 Apr 27 10:04 ..
drwxr-xr-x 2 victoria victoria 4096 Apr 27 09:44 .dir01
drwxr-xr-x 4 victoria victoria 4096 Apr 27 09:45 dir01
-rw-r--r-- 1 victoria victoria    0 Apr 27 09:17 .file00
-rw-r--r-- 1 victoria victoria    0 Apr 27 09:17 file00

./hourly.0/.dir01:
total 8
drwxr-xr-x 2 victoria victoria 4096 Apr 27 09:44 .
drwxr-xr-x 4 victoria victoria 4096 Apr 27 09:45 ..

./hourly.0/dir01:
total 16
drwxr-xr-x 4 victoria victoria 4096 Apr 27 09:45 .
drwxr-xr-x 4 victoria victoria 4096 Apr 27 09:45 ..
drwxr-xr-x 2 victoria victoria 4096 Apr 27 09:44 .dir02
drwxr-xr-x 4 root     victoria 4096 Apr 27 09:45 dir02
-rw-r--r-- 1 victoria victoria    0 Apr 27 09:17 .file01
-rw-r--r-- 1 victoria victoria    0 Apr 27 09:17 file01

./hourly.0/dir01/.dir02:
total 8
drwxr-xr-x 2 victoria victoria 4096 Apr 27 09:44 .
drwxr-xr-x 4 victoria victoria 4096 Apr 27 09:45 ..

./hourly.0/dir01/dir02:
total 16
drwxr-xr-x 4 root     victoria 4096 Apr 27 09:45 .
drwxr-xr-x 4 victoria victoria 4096 Apr 27 09:45 ..
drwxr-xr-x 2 root     victoria 4096 Apr 27 09:44 .dir03
drwxr-xr-x 2 root     victoria 4096 Apr 27 09:45 dir03
-rw-r--r-- 1 root     victoria    0 Apr 27 09:17 .file02
-rw-r--r-- 1 root     victoria    0 Apr 27 09:17 file02

./hourly.0/dir01/dir02/.dir03:
total 8
drwxr-xr-x 2 root victoria 4096 Apr 27 09:44 .
drwxr-xr-x 4 root victoria 4096 Apr 27 09:45 ..

./hourly.0/dir01/dir02/dir03:
total 8
drwxr-xr-x 2 root victoria 4096 Apr 27 09:45 .
drwxr-xr-x 4 root victoria 4096 Apr 27 09:45 ..
-rw-r--r-- 1 root victoria    0 Apr 27 09:17 .file03
-rw-r--r-- 1 root victoria    0 Apr 27 09:17 file03

Move those files, directories:

This appears to preserve:

  • timestamps
  • recursively moves files, directories (including hidden files, directories)
  • preserves ownerships
[victoria@victoria test]$ mv hourly.0/ hourly.1

After the move:

[victoria@victoria test]$ tree -La 5 -F
.
└── hourly.1/
    ├── .dir01/
    ├── dir01/
    │   ├── .dir02/
    │   ├── dir02/
    │   │   ├── .dir03/
    │   │   ├── dir03/
    │   │   │   ├── .file03
    │   │   │   └── file03
    │   │   ├── .file02
    │   │   └── file02
    │   ├── .file01
    │   └── file01
    ├── .file00
    └── file00

7 directories, 8 files

[victoria@victoria test]$ ls -laR
.:
total 12
drwxr-xr-x 3 victoria victoria 4096 Apr 27 10:05 .
drwxrwxr-x 4 victoria victoria 4096 Apr 27 09:19 ..
drwxr-xr-x 4 victoria victoria 4096 Apr 27 09:45 hourly.1

./hourly.1:
total 16
drwxr-xr-x 4 victoria victoria 4096 Apr 27 09:45 .
drwxr-xr-x 3 victoria victoria 4096 Apr 27 10:05 ..
drwxr-xr-x 2 victoria victoria 4096 Apr 27 09:44 .dir01
drwxr-xr-x 4 victoria victoria 4096 Apr 27 09:45 dir01
-rw-r--r-- 1 victoria victoria    0 Apr 27 09:17 .file00
-rw-r--r-- 1 victoria victoria    0 Apr 27 09:17 file00

./hourly.1/.dir01:
total 8
drwxr-xr-x 2 victoria victoria 4096 Apr 27 09:44 .
drwxr-xr-x 4 victoria victoria 4096 Apr 27 09:45 ..

./hourly.1/dir01:
total 16
drwxr-xr-x 4 victoria victoria 4096 Apr 27 09:45 .
drwxr-xr-x 4 victoria victoria 4096 Apr 27 09:45 ..
drwxr-xr-x 2 victoria victoria 4096 Apr 27 09:44 .dir02
drwxr-xr-x 4 root     victoria 4096 Apr 27 09:45 dir02
-rw-r--r-- 1 victoria victoria    0 Apr 27 09:17 .file01
-rw-r--r-- 1 victoria victoria    0 Apr 27 09:17 file01

./hourly.1/dir01/.dir02:
total 8
drwxr-xr-x 2 victoria victoria 4096 Apr 27 09:44 .
drwxr-xr-x 4 victoria victoria 4096 Apr 27 09:45 ..

./hourly.1/dir01/dir02:
total 16
drwxr-xr-x 4 root     victoria 4096 Apr 27 09:45 .
drwxr-xr-x 4 victoria victoria 4096 Apr 27 09:45 ..
drwxr-xr-x 2 root     victoria 4096 Apr 27 09:44 .dir03
drwxr-xr-x 2 root     victoria 4096 Apr 27 09:45 dir03
-rw-r--r-- 1 root     victoria    0 Apr 27 09:17 .file02
-rw-r--r-- 1 root     victoria    0 Apr 27 09:17 file02

./hourly.1/dir01/dir02/.dir03:
total 8
drwxr-xr-x 2 root victoria 4096 Apr 27 09:44 .
drwxr-xr-x 4 root victoria 4096 Apr 27 09:45 ..

./hourly.1/dir01/dir02/dir03:
total 8
drwxr-xr-x 2 root victoria 4096 Apr 27 09:45 .
drwxr-xr-x 4 root victoria 4096 Apr 27 09:45 ..
-rw-r--r-- 1 root victoria    0 Apr 27 09:17 .file03
-rw-r--r-- 1 root victoria    0 Apr 27 09:17 file03

[victoria@victoria test]$ 
Victoria Stuart
  • 473
  • 3
  • 5
  • This is true if you want to move a folder. I believe that in the case of the question, the target folder already has contents, and the idea is to merge the contents of two folders. Because of that, I believe your answer does not answer the question. However, I see how it might be useful to future searchers, who are trying to use `mv folder/*` to move a folder instead of trying to merge folder contents. – Jaacko Torus Aug 19 '23 at 20:27