如何仅移动list.txt中* not *的文件?

时间:2015-10-05 17:21:16

标签: macos bash unix

我有一个.jpg文件的文件名列表。除了列表中的那些之外,我想将所有图像移出给定的filetree。我一直在尝试使用find循环来完成这项工作,但它并不常用:

x=$(find . -type f -not -name "$line")
while IFS= read -r line ; do
mv "$x" Destination/
done < Filenames.txt

摘自Filenames.txt:

IMG_5253 (2).jpg
IMG_5255 (2).jpg
IMG_5256 (2).jpg
IMG_3988.JPG
IMG_3989.JPG
IMG_3990.JPG

我想我可以看出为什么这是有问题的(我真的不想要一个循环,确切地说),但我看不出如何修复它。有什么好办法呢?

编辑:在@ghoti和此帖子的帮助下,Rsync为我工作:https://unix.stackexchange.com/questions/76237/rsync-certain-files-excluding-the-rest-ignoring-svn-directory-recursively

rsync -rv --exclude-from '/Path/To/Filename.txt' --exclude='*Pattern/For/Other/Files/That/Should/Stay/Put*' --include='*.jpg' --include='*.JPG' --include='*/' --exclude="*" --remove-source-files Path/To/Source Path/To/Destination

我也很幸运下面发布的Perl解决方案,与其他一些选项相比,它的运行速度非常快。我将rsync标记为我的解决方案,因为这是我使用的,但其他人后来可能也想看看@ Tom_Fenench的解决方案。

5 个答案:

答案 0 :(得分:2)

这不是很快,但应该有效。

import

这将从square()开始,然后浏览所有子目录,查找以find /startpath -name \*.jpg -not -exec grep -q '^{}$' filenames.txt \; -exec mv -v {} /target/path/ 结尾的文件。对于其中的每一个,它将运行您文件的/startpath,如果该grep .jpg成功,将在第二个grep中移动文件时打印文件名。

请注意,由于-not匹配事物的方式,您可能需要在路径前加上文件名,即使这些路径为-exec

另请注意,这不是速度优化或IO优化的解决方案,因为它会为找到的每个文件启动单独的find命令。

或者,如果你想使用./,你可以这样做:

grep

答案 1 :(得分:1)

以下是使用Perl解决问题的一种方法:

#!/usr/bin/env perl

use strict;
use warnings;
use autodie;    
use File::Find;
use File::Copy;

my %files;
open my $fh, "<", "Filenames.txt";
while (<$fh>) {
    chomp;
    $files{$_}++;
}

sub wanted {
    if (-f && /\.jpg$/ && !exists $files{$_}) {
        move($_, "/path/to/destination");
    }
}
find(\&wanted, ".");

它从Filenames.txt读取文件名,并使用它们构建哈希%files。然后它在当前目录中递归搜索,为它找到的所有内容执行子例程wanted。它将每个以.jpg结尾且在散列中找不到的文件移动到目标目录path/to/destination中(假设该目录已存在)。

确保目的地位于树外是很重要的,否则会干扰搜索。

答案 2 :(得分:0)

根据以下@Sorpigal评论更新了答案:

while IFS= read -d '' -r file ; do
    mv "$file" Destination/
done < <(find . -type f -print0 | grep -ZzFfv Filenames.txt)

答案 3 :(得分:0)

我认为在这种情况下使用find太笨重了。我建议如下:

#!/bin/sh
dest=/fully/qualified/destination
# run this script in the directory with all your .jpg files
for filename in *.jpg; do
    if grep -q "$filename" Filenames.txt
    then
            #echo "Found file $filename in Filenames.txt, will do nothing"
    else
            #echo "Did not find file $filename in Filenames.txt, will move unwanted file"
            mv "$filename" $dest
    fi
done

我认为使用find的解决方案仅在同一目录中有成千上万个文件名到命令行无法扩展所有条目的位置时才有用,这完全是另一个问题。

如果你在目录中有这么多文件,那么我会同意Tom,你应该使用更强大的语言,或者使用find find

答案 4 :(得分:0)

我认为你的文件名可以有空格但没有换行符 使用换行符,Filenames.txt的布局可能会有问题。 当所有图片都在一个目录中时(假设图像),你可以不用找到:

comm -23  <(ls -1 images) <(sort Filenames.txt) | while read file; do
   mv images/"$file" Destination/
done

当您想要下降目录时,此解决方案更糟糕:

#!/bin/bash
# Only sort Filenames.txt once
tmpSorted=/tmp/sortedFiles
sort Filenames.txt > ${tmpSorted}
# Go through directories
find . -type d | while read dir; do
      comm -23  <(ls -1 "${dir}" 2>/dev/null | sort) <(cat ${tmpSorted}) | while read file; do
         # remove the echo when it looks ok
         echo mv "${dir}"/"$file" Destination/
   done
done
rm ${tmpSorted}