2009-11-28 43 views
16

như bạn có thể thấy trong tiêu đề tôi cố gắng đồng bộ một thư mục với một danh sách các tập tin. Tôi hy vọng rằng lệnh này sẽ xóa tất cả các tập tin trong dest/mà không có trong danh sách, nhưng nó không.rsync --delete --files-from = list/dest/không xóa các tập tin không mong muốn

Vì vậy, tôi đã tìm kiếm một chút và biết bây giờ, rằng rsync không thể làm điều này.

Nhưng tôi cần nó, vì vậy bạn có biết cách nào để làm điều đó không?

PS: Danh sách được tạo bởi tập lệnh python, do đó, bạn có thể tưởng tượng rằng giải pháp của bạn sử dụng một số mã python.

EDIT, chúng ta hãy bê tông:

Danh sách này trông như thế này:

/home/max/Musik/Coldplay/Parachutes/Trouble.mp3 
/home/max/Musik/Coldplay/Parachutes/Yellow.mp3 
/home/max/Musik/Coldplay/A Rush of Blood to the Head/Warning Sign.mp3 
/home/max/Musik/Coldplay/A Rush of B-Sides to Your Head/Help Is Around the Corner.mp3 
/home/max/Musik/Coldplay/B-Sides (disc 3)/Bigger Stronger.mp3 

và lệnh như thế này:

rsync --delete --files-from=/tmp/list//home/max/Desktop/foobar/ 

này hoạt động, nhưng nếu tôi xóa một dòng, nó không bị xóa trong foobar /.

EDIT 2:

rsync -r --include-from=/tmp/list --exclude=* --delete-excluded//home/max/Desktop/foobar/ 

Đó làm việc không ...

+0

Btw .: rsync phiên bản 3.0.6 giao thức phiên bản 30 quên rằng, xin lỗi – dAnjou

+1

Một trong những điều tôi ghét nhất về rsync, là thiếu sự hỗ trợ cho chính xác những gì bạn đang yêu cầu. Bài tốt. –

Trả lời

14

lẽ bạn có thể làm điều này bằng cách sử dụng danh sách bao gồm các mô hình thay vào đó, và sử dụng --delete-excluded (mà không như tên cho thấy)? Một cái gì đó như:

rsync -r --include-from=<patternlistfile> --exclude=* --delete-excluded/dest/ 

Nếu tên tập tin có khả năng chứa ký tự đại diện (*, ?[) sau đó bạn có thể cần phải sửa đổi Python để thoát khỏi chúng:

re.sub("([[*?])", r"\\\1", "abc[def*ghi?klm") 

Edit: Khuôn mẫu đối sánh dựa trên hoạt động hơi khác với --files-from trong đó rsync sẽ không tái sử dụng vào các thư mục khớp với mẫu loại trừ vì lý do hiệu quả.Vì vậy, nếu các tập tin của bạn trong /some/dir/some/other/dir sau đó tập mô hình của bạn cần phải trông giống như:

/some/ 
/some/dir/ 
/some/dir/file1 
/some/dir/file2 
/some/other/ 
/some/other/dir/ 
/some/other/dir/file3 
... 

Ngoài ra, nếu tất cả các file nằm trong thư mục cùng thì bạn có thể viết lại lệnh hơi:

rsync -r --include-from=<patternlistfile> --exclude=* --delete-excluded /some/dir/ dest/ 

và sau đó mô hình của bạn trở nên:

/file1 
/file2 

Edit: Suy nghĩ về nó, bạn có thể ở clude tất cả các thư mục với một mẫu:

/**/ 

nhưng sau đó bạn sẽ kết thúc với toàn bộ cây thư mục trong dest/ mà có lẽ không phải là những gì bạn muốn. Nhưng việc kết hợp nó với -m (mà mận thư mục rỗng) nên giải quyết rằng - vì vậy lệnh kết thúc lên một cái gì đó như:

rsync -m -r --delete-excluded --include-from=<patternfile> --exclude=*/dest/ 

và file mẫu:

/**/ 
/some/dir/file1 
/some/other/dir/file3 
+0

Cảm ơn bạn, nhưng lệnh của bạn yêu cầu -d hoặc -r và không hoạt động. – dAnjou

+0

Trên thực tế, lệnh của bạn không sao chép bất kỳ thứ gì thành dest/..: P – dAnjou

+1

Các tệp trong thư mục con? Nếu vậy, thư mục (và cha mẹ của nó) cần phải có trong danh sách mẫu, nếu không rsync thậm chí sẽ không chấp nhận chúng. – SimonJ

-1

rsync là lý tưởng cho việc giữ các thư mục đồng bộ, trong số những thứ hữu ích khác. Nếu bạn có bản sao chính xác trên SOURCE và muốn xóa tệp trên DEST, bạn có thể xóa chúng khỏi SOURCE và tùy chọn rsync --delete cũng sẽ xóa chúng khỏi DEST.

Tuy nhiên, nếu bạn chỉ có một danh sách tùy ý các tập tin mà bạn muốn xóa, tôi đề nghị bạn sử dụng SSH để thực hiện điều đó:

ssh [email protected] rm /path/to/file1 /path/to/file2 

này sẽ thực hiện lệnh rm trên máy chủ từ xa.

Sử dụng python, bạn có thể:

import subprocess 
FileList = ['/path/to/file1', '/path/to/file2'] 
subprocess.call(['ssh', '[email protected]', 'rm'] + FileList) 

~ thưởng thức

+1

Hiểu lầm. Tôi không có danh sách các tệp cần xóa. Tôi có một danh sách các tập tin cần sao chép. Tôi muốn những tệp KHÔNG có trong danh sách bị xóa. Nhưng cảm ơn câu trả lời của bạn. – dAnjou

1

Explicit build --exclude-từ = ... có vẻ là cách duy nhất để đồng bộ hóa danh sách các tập tin.

stdin = subprocess.PIPE 
other_params.append("--exclude-from=-") #from stdin 

p = subprocess.Popen('rsync -e ssh -zthvcr --compress-level=9 --delete'.split() + other_params + [src, dst], stdin = PIPE) 

if relative_files_list != None: 
    #hack: listing of excluded files seems the only way to delete unwanted files at destination 
    files = set(map(norm_fn, relative_files_list)) #make hash table, for huge lists 
    for path, ds, fs in os.walk(src): 
     for f in fs: 
      rel_path_f = norm_fn(os.path.relpath(os.path.join(path, f), src)) 
      if rel_path_f not in files: 
       #print 'excluding', rel_path_f.replace('\\', '/') 
       p.stdin.write(rel_path_f + '\n') 
    p.stdin.close() 
assert 0 == p.wait() 
6

Như bạn đã giải thích, lệnh

rsync -r --delete --files-from=$FILELIST [email protected]:/ $DEST/ 

không xóa nội dung trong điểm đến khi một mục từ $ filelist đã bị xoá. Một giải pháp đơn giản là sử dụng thay thế như sau.

mkdir -p $DEST 
rm -rf $TEMP 
rsync -r --link-dest=$DEST --files-from=$FILELIST [email protected]:/ $TEMP/ 
rm -r $DEST 
mv $TEMP $DEST 

Điều này sẽ hướng dẫn rsync sử dụng điểm đến trống. Các tệp đã có trong thư mục liên kết-đích được liên kết cứng cục bộ và không được sao chép. Cuối cùng, điểm đến cũ được thay thế bằng điểm đến mới. Mkdir đầu tiên tạo $ DEST trống nếu $ DEST không tồn tại, để ngăn lỗi rsync. (Các $ -variables được giả định mang đường dẫn đầy đủ đến tệp hoặc thư mục tương ứng.)

Có một số chi phí nhỏ cho liên kết cứng, nhưng bạn không cần phải gây rối với các chiến lược bao gồm/loại trừ phức tạp .

4

Lấy cảm hứng từ m4t, nhưng sử dụng ... rsync để dọn dẹp

rsync -r --link-dest=$dst --files-from=filelist.txt [email protected]:$source/ $temp 
rsync -ra --delete --link-dest=$temp $temp/ $dest 
+0

thx! đã tìm kiếm một thời gian cho giải pháp đó. –

+0

'rm -rf $ TEMP' là cần thiết trước mã của bạn, nếu không, nếu $ temp có các tệp không mong muốn trong đó, chúng sẽ kết thúc bằng $ dest. – kakyo

+0

Tôi nghĩ rằng có một lỗi đánh máy ở đây, không chính xác chắc chắn nơi –

0

Tôi nhận ra câu hỏi này đã được hỏi một thời gian dài trước đây, nhưng tôi đã không hài lòng với câu trả lời.

Dưới đây là cách tôi giải quyết vấn đề, giả sử một danh sách nhạc được tạo ra bởi mpd:

#!/bin/bash                 

playlist_path="/home/cpbills/.config/mpd/playlists" 
playlist="${playlist_path}/${1}.m3u" 
music_src="/home/cpbills/files/music" 
music_dst="/mnt/sdcard/music/" 

if [[ -e "$playlist" ]]; then 
    # Remove old files 
    find "$music_dst" -type f | while read file; do 
    name="$(echo "$file" | sed -e "s!^$music_dst!!")" 
    if ! grep -qF "$name" "$playlist"; then 
     rm "$file" 
    fi 
    done 

    # Remove empty directories 
    find "$music_dst" -type d -exec rmdir {} \; 2>/dev/null 

    rsync -vu \ 
     --inplace \ 
     --files-from="$playlist" \ 
     "$music_src" "$music_dst" 
else 
    printf "%s does not exist\n" "$playlist" 1>&2 
    exit 1 
fi 
8

Đây không phải là chính xác các giải pháp, nhưng mọi người đến đây có thể tìm thấy điều này hữu ích: Kể từ rsync 3.1.0 có một --delete-missing-args tham số sẽ xóa các tệp trong thư mục đích khi bạn đồng bộ hóa hai thư mục bằng cách sử dụng --files-from.Bạn sẽ cần phải xác định các tập tin đã xóa trong /tmp/list cùng với các tập tin bạn muốn sao chép:

rsync --delete-missing-args --files-from=/tmp/list /source/dir /destination/dir 

Xem the man page để biết thêm chi tiết.

Các vấn đề liên quan