(已解决) 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' 目录)
在大量的 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' 目录)