(已解决) bash脚本:如何应对不同的cp行为?

(solved) bash script: how to cope with the different cp behaviors?

在大量的 cp 问题中,我没有发现任何关于这种行为差异的信息(在 Ubuntu 18.04 上测试)。抱歉丢了post,不过设置有点复杂

案例 1:这是预期的行为

给定以下文件夹

 source                     
    file1.cpp
    file2.cpp

在 运行安装此脚本后

 #!/bin/bash
 cp -r source/ target/   

我确实得到了这个结果

 source                     # same as above, plus a copy in "target"
    file1.cpp
    file2.cpp
 target  
    file1.cpp
    file2.cpp

情况 2:使用相同的脚本,源文件夹存在并且在目标文件夹中为空

这里还有一个空文件夹 来源
file1.cpp file2.cpp 目标 来源

和运行相同的脚本

 #!/bin/bash
 cp -r source/ target/     

这给了我一个不同的、不想要的结果

 source                     # same as above, plus a copy in "target"
    file1.cpp
    file2.cpp
 target  
    source
       file1.cpp
       file2.cpp

Case1 和 Case2 的正常解

 cp -r source/  target/       # works only for Case 1
 cp -r source/* target/       # works only for Case 2

在错误的情况下使用,一个会导致错误,另一个会产生错误的结果,这会非常混乱。这意味着对于每个复制操作,我必须检查目标文件夹是否存在并使用不同的命令。这非常麻烦,但我不知道有更简单的解决方案。

Case2 的未解决情况

但是,我遇到的问题是:当我使用变量作为源和目标时,我的脚本如下所示

 #!/bin/bash
 SOURCE="source"
 TARGET="target"

 if [ -d "$TARGET" ]; then
   cp -r $SOURCE $TARGET     
 else
   cp -r $SOURCE/* $TARGET     # note "$SOURCE/*" would fail.
 fi

我有一个带空格的 $SOURCE 路径。

来源="source code"

由于我不能对源变量使用引号,这导致两个 'directory not found errors'。

Case2 如何解决这个问题?

编辑

为了更清楚地说明问题。这个

SOURCE="source" 
cp -r "$SOURCE/*" $TARGET

失败并出现错误 "cannot stat source/: No such file or directory"。我认为这意味着 bash 不能用文件列表替换 / 并且 cp 将其作为文件文字获取。名称为 "source/*" 的文件或文件夹显然不存在。不过可能是我想的太简单了,bash做的不一样。

虽然您的主要问题与 cp 命令有关,但对于您的尝试,我还有一些想说的。那么让我们一步步来吧。

问题 1:cp 行为

当目标文件夹包含与源文件夹同名的文件夹时,cp 命令的行为不同。这种行为是有意的,但可以根据 man 使用 -T 选项来避免。

Here 您可以找到 -T 选项的扩展说明。

因此,您只需执行:

cp -rT source/ target/

问题 2:包含空格的路径

在您的尝试中,您提到了使用空格处理路径时的问题。尽管使用之前的解决方案不需要自定义脚本,但我想强调的是,路径包含空格的变量需要所有访问都用双引号引起来。变量内容必须加双引号,不是星号(因为要globstar展开,不要按字面意思)。因此,您之前的脚本将如下所示:

#!/bin/bash

SOURCE=${1:-"source"}
TARGET=${2:-"target"}

if [ -d "$TARGET" ]; then
  cp -r "$SOURCE" "$TARGET"     
else
  cp -r "$SOURCE"/* "$TARGET"    # note "$SOURCE/*" would fail.
fi
#!/bin/bash
cp -r --copy-contents source/ target/

--copy-contents表示只复制source

的内容

为了更好地理解您案例中发生的情况,请测试此脚本:

#!/bin/bash
pwd

如果这个 pwd 写在不同的地方,你可以这样做:

#!/bin/bash
cd SOURCE_PARENT
cp -r --copy-contents source/ target/

如果目标或源名称中有空格,请记住这一点 cp [选项]...源...目录

target name <= "target realTarget"
cp -r source target realTarget

cp -r source target realTarget 相信你想在 realTarget 中复制 source & target 它不明白 "target realTarget" 是一个全名,如果你需要复制它,你必须在命令中使用双引号

cp -r source "target realTarget"

cp -r source "target realTarget" 现在"target realTarget"作为文件夹名

和源码一样用双引号就解决了

->加上额外的:(使用 \ 转义引号)

SOURCE="\"source realsource\"" 
cp -rT --copy-contents $SOURCE $TARGET

-T, --no-target-directory 将 DEST 视为普通文件

也许我们对单个文件使用 CP,对目录使用 wse rsync?

rsync -vazh /source /destination

(包括 'source' 目录)

rsync -vazh /source/ /destination

(不包括 'source' 目录)