如何同时移动和重新创建文件夹?


9

statistics在Ubuntu服务器中有一个名为定期存储数据文件的文件夹。重新创建文件夹以用于存储新文件时如何重命名statistics文件夹?backup-xxstatistics

文件statistics夹中的文件由PHP创建file_put_contents

我更喜欢重命名文件夹,因为文件夹中有很多文件statistics


起初,我以为您的意思是“同时”表示该操作应该是“原子的”(尽可能)。
phk

@phk是的,这正是我的意思。
Googlebot

正确的术语是“目录”而不是“文件夹”。
BerkÖzbalcı17年

Answers:


7
mv statistics backup-xx && mkdir statistics

这会将现有statistics目录重命名为backup-xx,如果成功,它将继续创建一个新statistics目录。

要进行更原子化的操作,请考虑创建目录statistics-001(或类似目录,也许以001合适的格式替换为今天的日期),并创建一个指向该目录的符号链接statistics

mkdir statistics-001
ln -s statistics-001 statistics

当您要“旋转”它以便新数据进入一个干净的目录时,请首先创建目录,然后重新创建statistics指向该目录的链接:

mkdir statistics-002
ln -sf statistics-002 statistics

mv statistics-001 backup-001

这样一来,任何程序写入的statistics目录将永远不会(即该符号链接指向的目录)1未能找到它。

如果需要在statistics指向的目录上设置特殊权限或所有权,请在(重新)创建链接之前进行设置。

1 或者,更确切地说,使用标准Unix工具,可以最大程度地缩短程序没有有效目标目录的时间。


1
您可能还需要chown --reference=backup-xx statistics ; chmod --reference=backup-xx statistics设置所有权和权限。Ideall您将在重命名之前执行此操作,因此需要进行mkdir new ; chown ; chmod ; mv stats backup ; mv new stats类型处理。
史蒂芬·哈里斯

@StephenHarris是的,在具有这些标志的系统上。
库萨兰达

但是,这不是原子的。它接近原子,但不完全相同。
CVn

@MichaelKjörling修复它。
Kusalananda

ln -sf不是原子的。已指定要取消链接旧的符号链接,然后创建一个新的符号链接,这不一定是原子性的。相反,您必须进行一个附加的临时符号链接,并使用该rename函数(mv例如,通过命令)以原子方式替换旧的符号链接。在这里查看我的处理方法:git.musl-libc.org/cgit/musl/tree/tools/…–
R .. GitHub停止帮助ICE

12

无法将目录自动替换为另一个目录。您可以移动旧目录,然后创建一个新目录:

mv statistics backup-xx
mkdir statistics

但这留下了一个很小的时间窗口,在此期间statistics不存在。如果某些进程可能随时将文件拖放到目录中,则会出现问题。

为了有效地原子替换目录,您需要使用符号链接。创建一个目录,其名称包括从头开始的时间段:

mkdir "statistics-$(date +%Y%m%d)"

(或者,但是您要选择目录命名约定)。创建一个具有固定名称的符号链接到当前位置:

ln -s  statistics

要替换目录,请首先创建一个新目录和一个新的符号链接,然后将其移动以覆盖旧的符号链接。请注意,mv符号链接上的纯文本或纯文本ln -s都不会这样做:它们将在目标目录内创建一个条目。GNU coreutils的ln -snf方法也不适合,因为它在创建新的符号链接之前先删除了现有的符号链接,这留下了一个很小的时间窗口,在此期间该路径不存在。您可以mv -T在新的符号链接上使用GNU coreutils 。

new_dir="statistics-$(date +%Y%m%d)"
mkdir "$new_dir"
ln -s statistics.new
mv -Tf statistics.new statistics

busybox' ln -sf也不是原子的,我不知道是什么实现。
phk

1
除了phk的注释符号链接之外,它也不是100%安全的,因为正在运行的进程可能仍然具有打开的目录文件描述符(符号链接目标),并且它可能在重命名的目录中创建更多新文件(考虑openat()或CWD)。我只会将目录的内容移动到新目录。对于打开的文件,这仍然是不安全的,但要好一些。有疑问的使用logrotate应最好地尊重此类问题。
rudimeier '17

1
@phk symlink系统调用不会覆盖现有文件,因此不幸的是,不可能直接以原子方式直接切换符号链接。该rename系统调用将覆盖现有文件,但恼人没有可移植的方式来做到这一点的壳; 借助该-T选项,GNU coreutils成为可能。
吉尔斯(Gilles)'所以

3

根本不要重命名目录。您说您更喜欢重命名目录,因为它有很多文件。我能想到的唯一原因是因为复制文件会花费很长时间。但是,只要将文件移动到同一文件系统上的某个位置,它们即刻移动(即重命名)。我认为这是您要执行的操作,因为如果要更改文件系统,mvcp无论是移动目录还是移动目录都将花费很多时间。

因此,只需:

mkdir backup-xx && mv statistics/* backup-xx

如果还需要获取隐藏文件,则可以执行以下操作:

mkdir backup-xx && mv statistics/* statistics/.* backup-xx

或者,如果使用bash

shopt -s dotglob; mkdir backup-xx && mv statistics/* statistics/.* backup-xx

这样,目录始终存在,但是您仍然可以通过简单而快速的操作来移动目录的内容。


1

您可以将统计信息文件夹的内容移动到新创建的目录中,而不是移动文件夹本身。如果移动整个文件夹,则必须运行另一个命令来更改目录权限。

mkdir -p <path>/backup-xxx
mv statistics/* <path>/backup-xxx/.
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.