rsync:mkdir“2014-11/.”失败:没有该文件或目录 (2)

rsync:mkdir“2014-11/.”失败:没有该文件或目录 (2)

我正在编写一个脚本,用于使用 rsync 自动将文件从服务器 a 复制到服务器 b 这是我的脚本:

#!/bin/bash
NOW=$(date +"%Y-%m")
rsync -au --ignore-existing /var/www/uploads/$NOW/* -e [email protected]:/var/www/uploads/$NOW/.

当我们要去下个月,比如从十月到十一月时,我的脚本出现这个错误:

`

rsync: mkdir "/var/www/uploads/2014-11/." failed: No such file or directory (2)
rsync error: error in file IO (code 11) at main.c(605) [Receiver=3.0.9]
rsync: connection unexpectedly closed (9 bytes received so far) [sender]
rsync error: error in rsync protocol data stream (code 12) at io.c(605) [sender=3.0.9]

`我该如何修复这个错误?请帮帮我

答案1

首先,确保目标上的父目录存在。即[email protected]:/var/www/uploads应该存在。我认为按照您的表述,尾随.是指 rsync 尝试创建的目录,除非父目录已经存在,否则它无法这样做。即父目录是[email protected]:/var/www/uploads/$NOW

其次,要意识到 rsync 的行为与 cp 的行为在文件名末尾带有“/”方面有细微的不同。我发现最安全、最直观的方法是/在所有目录末尾使用尾随符号。如下所示:

rsync -au --ignore-existing /var/www/uploads/$NOW/ -e [email protected]:/var/www/uploads/$NOW/

与 cp 不同,rsync 会可靠地将源参数中的目录内容复制到目标目录的内容中,如果需要则创建目标目录(尽管它的父目录必须存在),并且如果目标已经存在则不将源目录(即父目录)放入目标目录中。

这与您所做的稍有不同,因为您执行的方式会排除源目录中名称以 开头的文件.,并且如果复制的文件列表太长将会失败(如果我没记错的话,bash 扩展的总命令行长度上限为大约 32K 个字符)。

答案2

需要删除结尾的点,将脚本更改为:

rsync -au --ignore-existing /var/www/uploads/$NOW/* -e [email protected]:/var/www/uploads/$NOW

答案3

尝试让 rsync 在目标上创建所有需要的目录:

NOW=$(date +"%Y-%m")
rsync -au --ignore-existing --relative /var/www/uploads/$NOW [email protected]:/var/www/uploads/
  • 添加--relative以让 rsync 在目标上创建目录树。
  • 源之后没有斜杠,因此最后一个目录(“ $NOW”)也会在目标上创建,而不仅仅是它的内容。
  • 从目标中删除“$NOW”,因为如果需要它将被创建。
  • 删除了看起来像是错误的孤独-e选项(它需要一个参数:“此选项允许您选择用于通信的备用远程 shell 程序“)。

或者查看这个答案了解更多详细信息和替代方案。

答案4

我在本地运行 rsync(从 python 脚本)时遇到了此错误,不是通过 dir,而是通过 os.walk 循环遍历目录和子目录以找到包含文件的文件夹,然后使用带有 starmap 的 multiprocessing.pool rsync 每个文件。我搜索了很长时间才找到这种情况的答案,最后我找到了此链接提出解决方案;

通过 os.walk,我获取了根目录,如果有与该根目录关联的文件,则我使用 -aR 标志调用 rsync;

        import subprocess
        import os
        import sys
        import multiprocessing
        from util_subprocess import exec_subprocess

        ORIG_SRC_ROOT = '/home/username/workspaces/data/prod'
        # IMPORTANT (slash, period) - we need to tell rsync 
        # that we want it to create subdirs relatively after the period
        # in the DEST_ROOT dir
        REL_SRC_ROOT = ORIG_SRC_ROOT + '/.'
        # rsync will create the directory structure for you below the DEST_ROOT
        DEST_ROOT = '/home/username/workspaces/data/prod_bak'
        
        CPU_COUNT = multiprocessing.cpu_count()
        if(not CPU_COUNT):
            CPU_COUNT = 1
    
        def sync(src, dest):
            '''
            Make the call the subprocess.run to execute rsync.
            
            NOTE:
            The flags are key here:
                --  '-a' (-a, --archive               archive mode; equals -rlptgoD (no -H,-A,-X))
                is pretty standard and covers most everything we need. 
                --  '-R'(-R, --relative              use relative path names), 
                makes sure rsync creates the subdirs on the destination folder.
            '''

            flags: str = r"-aR"
            program_name: str = r"rsync"
            exec_list = [program_name, flags , src, dest]
            return exec_subprocess(exec_list)
    
        def get_sync_params():
            '''Get a list of tuples, each tuple containing the src_file path, and dest_dir path.'''

            sync_params = []
            for root, dirs, files in os.walk(ORIG_SRC_ROOT, topdown=False):
                if(files):
                    for file in files:
                        src_file_temp = os.path.join(root, file)
                        # replace the orig root dir with the relative one from above 
                        src_file = src_file_temp.replace(ORIG_SRC_ROOT, REL_SRC_ROOT)
                        dest_dir = DEST_ROOT
                        # place them into a tuple
                        sync_tuple = (src_file, dest_dir)
                        # add the tuple to the list
                        sync_params.append(sync_tuple)
            return sync_params
    
        if __name__ == "__main__":
            '''Create a pool for multiprocessing and get these done in parallel.'''

            # call the get_sync_params above
            sync_params = get_sync_params()
            # Create a pool of specific number of CPUs
            print("Create {} processes in our pool.".format(CPU_COUNT))
            pool = multiprocessing.Pool(processes=CPU_COUNT)
            '''
            Start each task within the pool -  
            call the 'sync' function above 
            (which calls a separate wrapper function 
            to the subprocess.run call (exec_subprocess)). 
            The return value is a list of tuples 
            and each tuple contains the output (stdout OR stderr) 
            and the return_code results for each pair of src & dest input.
            '''
            results = pool.starmap(sync, sync_params)

因此,我们本质上创建了一个元组列表,其中每个元组都是 src_file 路径和 dest_dir 路径,由 multiprocessing.pool.starmap(function_name, tuple_list) 处理,后者又使用池中进程处理每个元组,并通过 subprocess.run 将其发送到 rsycn。列表中的元组可能如下所示;

[('/home/username/workspaces/data/prod/./math/alg_1/alg_1_test.txt',
'/home/username/workspaces/data/prod_bak/'), ('...', '...'), ]

第一个字符串是 src_file 路径,第二个是 dest_dir 路径。请注意 src_file 路径中的 '.'(告诉 rsync 我们需要在目标中在此之后创建子目录),以及 dest_dir 路径中的尾随 '/',告诉 rsync 将这些新子目录放在此目标根目录下。

相关内容