Linux:复制并创build目标目录,如果它不存在

我想要一个命令(或者可能是cp的一个选项)创build目标目录,如果它不存在。

例:

cp -? file /path/to/copy/file/to/is/very/deep/there 
 test -d "$d" || mkdir -p "$d" && cp file "$d" 

(对于cp没有这个选项)。

如果以下两者都是正确的:

  1. 您正在使用cp的GNU版本(而不是,例如,Mac版本)和
  2. 你正在复制一些现有的目录结构,你只需要重新创build它

那么你可以用cp--parents标志来做到这一点。 从信息页面(可在http://www.gnu.org/software/coreutils/manual/html_node/cp-invocation.html#cp-invocation或;info cpman cp查看):

 --parents Form the name of each destination file by appending to the target directory a slash and the specified name of the source file. The last argument given to `cp' must be the name of an existing directory. For example, the command: cp --parents a/b/c existing_dir copies the file `a/b/c' to `existing_dir/a/b/c', creating any missing intermediate directories. 

例:

 /tmp $ mkdir foo /tmp $ mkdir foo/foo /tmp $ touch foo/foo/foo.txt /tmp $ mkdir bar /tmp $ cp --parents foo/foo/foo.txt bar /tmp $ ls bar/foo/foo foo.txt 

这样一个老问题,但也许我可以提出一个替代解决scheme。

您可以使用install程序来复制您的文件并“即时”创build目标path。

 install -D file /path/to/copy/file/to/is/very/deep/there/file 

但是有一些方面需要考虑,

  1. 您还需要指定目标文件名称 ,而不仅仅是目标path
  2. 目标文件将是可执行的 (至less,据我看到我的testing)

通过添加-m选项来设置目标文件的权限(例如: -m 664将创build具有权限rw-rw-r--的目标文件,就像通过touch创build新文件一样),可以轻松修改#2。 。


这里是我被启发的答案的无耻链接 =)

简答

要将myfile.txt复制到/foo/bar/myfile.txt ,请使用:

 mkdir -p /foo/bar && cp myfile.txt $_ 

这个怎么用?

这里有几个组件,所以我将逐步介绍所有的语法。

在POSIX标准中指定的mkdir实用程序生成目录。 -p参数,根据文档,将导致mkdir

创build任何缺less的中间path名组件

这意味着当调用mkdir -p /foo/bar ,如果/foo不存在, mkdir将创build/foo /foo/bar 。 (没有-p ,它会抛出一个错误。

在POSIX标准 (或Bash手册,如果您愿意的话)中logging的&&列表操作符具有如下效果:如果mkdir -p /foo/bar成功执行,则仅执行cp myfile.txt $_ 。 这意味着如果mkdir失败, cp命令将不会尝试执行,原因很多,可能会失败 。

最后,作为cp的第二个parameter passing的$_是一个“特殊参数”,它可以方便地避免重复长参数(如文件path),而不必将它们存储在variables中。 根据Bash手册 ,它:

扩展到上一个命令的最后一个参数

在这种情况下,这就是我们传递给mkdir/foo/bar 。 因此, cp命令扩展为cp myfile.txt /foo/bar ,它将myfile.txt复制到新创build的/foo/bar目录中。

请注意, $_ 不是 POSIX标准的一部分 ,因此理论上Unix变体可能有一个不支持这种结构的shell。 但是,我不知道任何现代的炮弹不支持$_ ; 当然Bash,Dash和zsh都可以。


最后一点:我在这个答案开始时给出的命令假设你的目录名没有空格。如果你用空格处理名字,你需要引用它们,以便不同的单词不被视为mkdircp不同参数。 所以你的命令实际上是这样的:

 mkdir -p "/my directory/name with/spaces" && cp "my filename with spaces.txt" "$_" 

Shell函数根据需要调用它,将其称为“埋藏”副本,因为它为该文件挖掘出一个空洞:

 bury_copy() { mkdir -p `dirname $2` && cp "$1" "$2"; } 

以下是一种方法:

 mkdir -p `dirname /path/to/copy/file/to/is/very/deep/there` \ && cp -r file /path/to/copy/file/to/is/very/deep/there 

dirname会给你的目的地目录或文件的父。 mkdir -p`dirname …`然后创build该目录,确保当你调用cp -r时,正确的基目录就位。

这种超级父母的优点是,它适用于目的地path中的最后一个元素是文件名的情况。

它将在OS X上工作。

install -D file -m 644 -t /path/to/copy/file/to/is/very/deep/there

cp有多种用法:

 $ cp --help Usage: cp [OPTION]... [-T] SOURCE DEST or: cp [OPTION]... SOURCE... DIRECTORY or: cp [OPTION]... -t DIRECTORY SOURCE... Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY. 

@ AndyRoss的答案适用于

 cp SOURCE DEST 

cp风格,但是如果你使用的是错误的东西

 cp SOURCE... DEST/ 

cp风格。

我认为在这种用法(即目标目录尚不存在的情况下)中,“DEST”是不明确的,这也许是为什么cp从未为此添加过一个选项。

所以这里是我的这个函数的版本,它在dest目录上强制执行尾部的斜杠:

 cp-p() { last=${@: -1} if [[ $# -ge 2 && "$last" == */ ]] ; then # cp SOURCE... DEST/ mkdir -p "$last" && cp "$@" else echo "cp-p: (copy, creating parent dirs)" echo "cp-p: Usage: cp-p SOURCE... DEST/" fi } 

只需在你的.bashrc中添加以下内容,如果你需要的话。 在Ubuntu中工作。

 mkcp() { test -d "$2" || mkdir -p "$2" cp -r "$1" "$2" } 

例如,如果您想将“testing”文件复制到目标目录“d”使用,

 mkcp test a/b/c/d 

mkcp将首先检查目标目录是否存在,如果不存在,则复制源文件/目录。

从源复制到不存在的path

mkdir -p / destination && cp -r / source / $ _

注意:这个命令复制所有的文件

cp -r复制所有文件夹及其内容

$ _作为在上一个命令中创build的目的地

与我所有的尊重上面的答案,我更喜欢使用rsync如下:

 $ rsync -a directory_name /path_where_to_inject_your_directory/ 

例:

 $ rsync -a test /usr/local/lib/ 
 rsync file /path/to/copy/file/to/is/very/deep/there 

你走了,没有问题问。

假设你正在做类似的事情

cp file1.txt A / B / C / D / file.txt

A / B / C / D是不存在的目录

一个可能的解决scheme如下

 DIR=$(dirname A/B/C/D/file.txt) # DIR= "A/B/C/D" mkdir -p $DIR cp file1.txt A/B/C/D/file.txt 

希望有所帮助!