以下脚本循环遍历文件列表,并将文件副本复制到文件夹" src"位于与脚本相同的文件夹中。
其中一个文件/文件夹列表是包含脚本的文件夹。
如何防止它以递归方式将src文件夹复制到自身:
#!/bin/bash
FILES=files.txt
if [ -d src ]; then
mkdir -p src
fi
rm -rf src/*
while read FILE; do
DIR="src$(dirname $FILE)"
NAME=$(basename $FILE)
if [ ! -d "$DIR" ]; then
echo "Create $DIR"
mkdir -p $DIR
fi
if [ -d "$FILE" ]; then
echo Copying "FOLDER $FILE > $DIR/$NAME"
cp -rp "$FILE" "$DIR/$NAME"
elif [ -f "$FILE" ]; then
echo Copying "FILE $FILE > $DIR/$NAME"
cp -p "$FILE" "$DIR/$NAME"
fi
done <$FILES
希望清楚,听起来有点令人困惑,但我不确定如何用它来表达它!
我的最终目标实际上是将磁盘中的特定文件和文件夹收集到src文件夹中,然后将这些源文件推送到git repo。
答案 0 :(得分:1)
您的脚本存在一些问题。首先,您要求修复它,而不更改任何其他问题:
添加一项检查,看$FILE
是否等同于$PWD/src
。如果是,只需continue
循环,如
# avoid recursively copying src into itself
if [ "$FILE" == "$PWD/src" ];
then
continue
fi
但是,这假定files.txt
中的路径是绝对路径。
如果路径是相对的,则它们必须在其列出的名称下可见,以使dirname
,basename
和cp
起作用,这意味着它们是相对于当前工作目录的路径,我们可以将检查简化为"$FILE" == "src"
如果你有像src/../src
这样的非规范化路径,那么支票就不行了。
我最喜欢在使用GNU实用程序的Linux上处理此问题的方法是使用readlink -f
规范化完整路径,如
if [ "$(readlink -f "$FILE")" == "$(readlink -f "$PWD/src")" ];
then
continue
fi
您可能想知道为什么我在readlink
上使用$PWD
,但如果您认为为了到达当前目录而遍历的其中一个目录是符号链接,则会有意义。在这种情况下,将$FILE
的路径规范化的结果会错误地与$PWD
不匹配。
如果您使用的是具有BSD实用程序的系统(如OSX计算机),则readlink
不支持-f
选项,事情开始变得棘手。
请记住,我们尝试处理的情况是files.txt
中包含符号链接的路径,但实际上是指src
。像../mysymlink/src
这样的东西,其中mysymlink
实际指向当前目录。
我知道的最简单的方法是检查src
的inode编号并检查它是否符合符号链接时的文件:
# fetch the inode number for src, following symlinks
src_inode_num="$(stat -L --format=%i src)"
# fetch the inode number for FILE, following symlinks
file_inode_num="$(stat -L --format=%i "$FILE")"
# compare inode numbers to see if they are the same directory
if [ "$file_inode_num" == "$src_inode_num" ];
then
continue
fi
我建议您查看stat
联机帮助页,但简而言之-L
表示stat
跟踪符号链接而未提供stat
信息,而--format=%i
表示统计信息仅打印inode编号。
如果您有关于files.txt
的更多信息,则可以使用其他解决方案,您可以使用grep
或其他工具删除src
的实例,甚至在处理文件之前
现在所有这些都得到了解决,您应该考虑可能出现在文件列表中的其他符号链接,因为它们会导致原始文件的重复。
简单的解决方案是
if [ -L "$FILE" ];
then
...
cp -P "$FILE" "$DIR/$NAME"
fi
请注意,这不会阻止if [ -f
和if [ -d
检查成功 - 符号链接也会通过这些检查,因此请务必在if [ -L
通过时跳过它们。
当然,所有这些都容易受到src
上面的同一组问题的影响,所以如果你想在路径中嵌入符号链接时避免重复,你应该做更多的工作。
同样,您可以使用readlink -f
,或者,因为您要复制内容,您可以遍历路径(重复dirname
正常工作)查找链接,并使用{{1}重新创建找到的链接}。
一些狡辩:
cp -P
,因为if [ -d src
即使存在也是安全的。我发现在没有mkdir -p src
块的情况下更容易阅读,以及像if
这样的简单评论。此外,您当前的检查是错误的 - 如果它已经存在,它只会创建# ensure src exists
。src
,因为我们很清楚我们是连接路径。在shell中src/$(dirname "$FILE")
相当于//
,因此没有任何危害。如果它困扰你,你可以随时/
,但这会忽略像sed 's://:/:g'
这样的路径,所以我不会打扰。a\//b
,为什么不把它放在一个变量中呢?也许是像#34; target&#34;。"$DIR/$NAME"
s echo
一样,无需在src
之前检查存在。mkdir -p src
"$(basename "$FILE")"
实际上只是src/$(dirname "$FILE")/$(basename "$FILE")
,为什么不使用它?即src/"$FILE"
,在这种情况下,我们可以省略对target="src/$FILE"
我在所有这些结尾处最终得到的问题是&#34;你想做什么?&#34;
您已经为我们提供了一个可以执行某项操作的脚本,并且可以轻松地在其上修补更多逻辑以完成您想要的操作,但也许您应该编辑问题以与我们分享您的实际目标。
也许在这里很好地使用basename
,使用tar
作为文件表输入,或者这可能通过聪明的files.txt
命令解决。
我不想浪费时间根据脚本内容进行推测,但我看到这个问题时的第一直觉是你要创建一个备份 - 当然,在这种情况下,一个名为rsync
的目录没有多大意义。