我正在根据此配方配置快照每日备份:http://www.mikerubel.org/computers/rsync_snapshots/
总而言之,在备份服务器上,我通过运行以下命令轮换旧副本:
dir=backup_directory
rm -rf ${dir}.3 # <-- this command reports "Permission denied" errors
mv ${dir}.2 ${dir}.3
mv ${dir}.1 ${dir}.2
cp -al ${dir} ${dir}.1
在本地服务器上:
rsync --del -rvatlz local_directory_to_backup/ backup_server:backup_directory/. --exclude=".*" --ignore-errors
由于rsync
保留权限,出现部分备份目录没有写权限,导致rm -rf
删除失败。
我知道我可以chmod -R +w ${dir}.3
先运行,rm
但我想知道是否有更简单的方法?我没有sudo
备份服务器的访问权限或 root 帐户。
答案1
警告
这个答案中的代码可能比更具破坏性
rm -rf
。我尝试编写好的代码,但错误还是会发生。忘记我的名声吧,我只是互联网上的一个普通人。假设代码会删除所有你可以删除的文件。减轻风险的几种方法:- 在虚拟机中测试代码;
- 创建一个只会损害自己利益的新用户帐户;
- 将重要文件备份到外部硬盘,验证,然后物理断开硬盘;
- 理解代码,然后才决定是否要使用它(棘手的)。
在你使用的问题中
rm -rf ${dir}.3
。在许多 shell 中你应该双引号。如果保留${dir}
不引号,您可能会删除超出您想要的内容。
建造核弹
(你好,NSA。我就知道你会来的。)
chmod -R
之前rm
非常简单。您可以通过将任何复杂性隐藏在 shell 函数或脚本后面来进一步简化它。开发一次,然后在需要时只需调用其名称即可。脚本可以无条件地chmod
在之前运行rm
;或者它可以运行rm
并希望成功,如果第一个失败则尝试chmod
+ 。rm
rm
我知道你不想chmod
影响所有人文件因为其中一些文件可能也链接到您要删除的目录之外。换句话说:可能存在硬链接。文件的模式位(权限)存储在其 inode 中,而不是指向 inode 的目录条目中;因此,无法chmod
独立编辑指向同一 inode 的多个条目(路径名)。如果您不想删除chmod
将在其他目录中保留的文件,那么您就不应该chmod -R
盲目地这么做。您的担心是有道理的。
出现问题时,您需要的总是目录chmod
。Linux 不允许硬链接到目录,因此chmod
删除有问题的目录不会产生任何其他影响(而且该目录无论如何都会被删除)。如果您只能chmod -R
删除目录,那么“ chmod
+ rm
”解决方案就很好了。
请参阅这个问题:chmod
区分目录和文件的通用函数。 在我的答案在那里您将找到一个名为的 shell 函数,chmodx
专门用于处理chmod
某些类型的文件。让我们使用它来解决您的问题:
nuke() {
[ "$#" = 0 ] && return 0
chmodx d -R u+w -- "$@"
rm -rf -- "$@"
}
用法:nuke foo ./bar /baz/qux
。
笔记:
--
后rm
将使其停止解析选项,但--
afterchmodx
不会以这种方式工作。如果您运行nuke -whatever
thenfind
(insidechmodx
) 会出现错误。因此您应该nuke ./-whatever
改为这样做。下面我将展示如何解决这个问题。rm -rf --
没有其他参数则不执行任何操作。chmodx d -R u+w --
没有其他参数则find
没有任何起始点。在这种情况下find
使用的一些实现.
。with 行[ "$#" = 0 ]
使得nuke
没有参数的调用成为无操作,即使chmodx d -R u+w --
不会是无操作。chmodx
chmod
针对每个目录运行。nuke
您可以修改其代码,并将-perm
(参见)插入到需要删除的目录man 1 find
中的正确位置。或者您可以像这样滥用注入:chmod
chmod
chmodx
! -perm -u+w
nuke() { [ "$#" = 0 ] && return 0 chmodx d -R u+w -- -u+w -perm ! "$@" rm -rf -- "$@" }
此变体仅检查并设置用户的权限。这种方法似乎适合您的使用情况。
处理目录树(或树)chmodx
然后用处理相同的树rm
似乎不是最佳选择。如果您的find
支持-delete
(可能不会) 则find foo -delete
不应比 慢很多rm -rf foo
,除非dir1/dir2/…/dirN/fileZ
无法删除但仍find
试图删除dirN
的情况dir1
。注意( 的一些实现)rm
可能知道尝试删除这些目录是没有意义的。
但 find foo -delete
可以改进,如果-delete
失败了可以采取一些措施。-execdir
(您find
可能支持也可能不支持)解决您的问题的基本方法可以是:
nuke() {
find "$@" ! -delete -execdir chmod u+w . \; -delete
}
主要优点是目录树不会被处理两次。chmod
只有在需要时才会生成附加进程 ( )。缺点如下:
- 如果第一个
-delete
失败,则会将一条消息打印到 stderr。您可以使用2>/dev/null
但其他(可能有用的)消息也会被抑制。我们可以使用rm -f … 2>/dev/null
而不是-delete
但这需要一个 shell. shell 和rm
是我们想要避免的额外进程。 nuke -whatever
会造成混淆find
。使用nuke ./-whatever
。- (上面)的例子
dir1/dir2/…/dirN/fileZ
仍然适用。 - (优势或劣势)
nuke /foo/bar
最终会尝试删除bar
。如果尝试失败,则将chmod u+w
处理foo
不是意味着要删除。您可能想要或不想更改 的模式位foo
。如果您不介意更改它们,那么chmod u+w
比 好得多chmod +w
。请注意,在相同情况下, 的变体chmodx
将保持foo
不变,因此它可能不会删除bar
。
我认为你不能轻易地建立一个find
命令,chmod
只在需要chmod
删除目录和-delete
其中的文件时才会删除目录之后。这是因为-delete
暗示-depth
和-depth
意味着目录的内容将在目录本身之前被处理。
好的,让我们构建改进的nuke
:
nuke() (
[ "$#" = 0 ] && exit 0
err=0
for p do
case "$p" in
-* )
p="./$p"
;;
esac
2>/dev/null find "$p" ! -delete -execdir chmod u+w . \; -delete
if [ -e "$p" ]; then
>&2 printf '%s survived\n' "$p"
err=1
fi
done
exit "$err"
)
该函数逐个删除其参数。它将幸存者报告给 stderr。-
支持以 开头的路径。如果需要,nuke /foo/bar
请注释。chmod … /foo
该函数使用子shell有两个原因:
- 使所有变量都变为局部变量;
- 允许
exit
而不是return
,这样您就可以将函数主体逐字粘贴到文件中并根据需要制作独立脚本(唯一需要添加的是shebang)。
shell 代码是可移植的(应该可以在 中工作sh
)。不可移植的是-delete
和-execdir
。