I have a file in a directory as /a/b/c/xxxxx.sql
I have another directory, /a/b/d
, having no further subdirectories.
How should I copy xxxxx.sql
into /a/b/d
, to have the new file with directory as /a/b/d/c/xxxxx.sql
, in a single command?
I have a file in a directory as /a/b/c/xxxxx.sql
I have another directory, /a/b/d
, having no further subdirectories.
How should I copy xxxxx.sql
into /a/b/d
, to have the new file with directory as /a/b/d/c/xxxxx.sql
, in a single command?
With the install
command:
install -D -m644 /a/b/c/xxxxx.sql /a/b/d/c/xxxxx.sql
From man install
:
install
- copy files and set attributes
You can chose the Unix rights by modifying 644
by what you want, default is 755
as that command is primarily intended for software deployment. The umask
is ignored.
The command will transparently create all the directory structure if not exists with -D
switch:
-D
Create all leading components of
DEST
except the last, or all components of--target-directory
, then copySOURCE
toDEST
The directories that are created in the process will always have rwxr-xr-x
(755
) permissions (though possibly affected by setgid bits and default ACLs) regardless of the umask
. Directories that were already there won't have their permissions modified.
Using GNU cp, do the copy from the starting point of the path you want to see reflected in the new directory and use the --parents
option:
cd /a/b &&
cp --parents c/foo d
Example:
% cp --parents c/foo d --verbose
c -> d/c
'c/foo' -> 'd/c/foo'
To make it a single command:
{ cd /a/b && cp --parents c/foo d; } # compound command
env -C /a/b cp --parents c/foo d # simple command assuming BSD/GNU env
With -a
, cp
will copy all attributes from the source including file type, permissions, ACLs, extended attributes, sparseness and ownership if permitted by the system, both for the c
directory and the foo
file.
You can use rsync relative option.
rsync --relative /a/b/./c/xxxxx.sql /a/b/d/
Note that .
separates where --relative
path should start.
To move the whole directory (c
), don't forget to add --recursive
flag
to copy these files recursively.
sh
. system()
functions of many languages do invoke sh, but that exact command line wouldn't trigger a EISDIR error. Possibly you have rsync -R /a/b/./c/xxxxx.sql > /a/b/d/
instead of rsync -R /a/b/./c/xxxxx.sql /a/b/d/
.
– Stéphane Chazelas
May 11 '23 at 07:14
In addition to rsync, tar
will do what you need:
tar cf - -C /a/b c/xxxxxx.sql | tar xpf - -C /a/b/d
An example:
$ mkdir -p /a/b/c /a/b/d
$ touch /a/b/c/xxxxxx.sql
$ tar cf - -C /a/b c/xxxxxx.sql | tar xpf - -C /a/b/d
$ find /a/b
/a/b
/a/b/c
/a/b/c/xxxxxx.sql
/a/b/d
/a/b/d/c
/a/b/d/c/xxxxxx.sql
You can roll your own command too. Here's a function implementation but you could equally drop a variant of this into an executable script somewhere along your $PATH
mdcopy() {
mkdir -p -- "$2" &&
cp -p -- "$1" "$2"
}
Usage
mdcopy /a/b/c/xxxxx.sql /a/b/d/c
An advantage of this approach is that you can have the utility to exactly what you want. This implementation requires a directory as its second argument but you could equally adapt it to expect a file pathname as the second argument. It's whatever works best for you.