递归移动某种类型的文件并保留其目录结构

时间:2012-01-10 03:19:54

标签: bash shell command-line find grep

我有一个目录,其中包含多个带 mov jpg 文件的子目录。

/dir/
  /subdir-a/  # contains a-1.jpg, a-2.jpg, a-1.mov
  /subdir-b/  # contains b-1.mov
  /subdir-c/  # contains c-1.jpg
  /subdir-d/  # contains d-1.mov
  ...         # more directories with the same pattern

我需要找到一种方法,使用命令行工具(理想情况下在Mac OSX上)将所有 mov 文件移动到新位置。但是,一个要求是保持目录结构,即:

/dir/
  /subdir-a/  # contains a-1.mov
  /subdir-b/  # contains b-1.mov
              # NOTE: subdir-c isn't copied because it doesn't have mov files 
  /subdir-d/  # contains d-1.mov
  ...

我熟悉find, grep, and xargs,但不知道如何解决这个问题。非常感谢你!

7 个答案:

答案 0 :(得分:17)

这取决于您的操作系统,更具体地说,取决于您的tar版本中的设施以及您是否拥有命令cpio。它还取决于你的文件名中是否有换行符(特别是);大多数人没有。

选项#1

cd /old-dir
find . -name '*.mov' -print | cpio -pvdumB /new-dir

选项#2

find . -name '*.mov' -print | tar -c -f - -T - |
(cd /new-dir; tar -xf -)

cpio命令具有直通(复制)模式,该模式在标准输入上给出文件名列表(每行一个),完全符合您的要求。

某些版本的tar命令可以选择从标准输入读取文件名列表,每行一个;在MacOS X上,该选项为-T -(单独-表示'标准输入')。对于第一个tar命令,选项-f -表示(在使用-c编写存档的上下文中,写入标准输出);在第二个tar命令中,-x选项表示-f -表示“从标准输入中读取”。

可能还有其他选择;请仔细查看手册页或帮助tar的输出。

此过程复制文件而不是移动文件。该行动的后半部分将是:

find . -name '*.mov' -exec rm -f {} +

答案 1 :(得分:3)

作为大文件,如果它们位于同一文件系统上,则您不想复制它们,而只是在移动时复制其目录结构。 您可以使用此功能:

# moves a file (or folder) preserving its folder structure (relative to source path)
# usage: move_keep_path source destination
move_keep_path () {
  # create directories up to one level up
  mkdir -p "`dirname "$2"`"
  mv "$1" "$2"
}

或者,添加对合并现有目录的支持:

# moves a file (or folder) preserving its folder structure (relative to source path)
# usage: move_keep_path source destination
move_keep_path () {
  # create directories up to one level up
  mkdir -p "`dirname "$2"`"
  if [[ -d "$1" && -d "$2" ]]; then
    # merge existing folder
    find "$1" -depth 1 | while read file; do
      # call recursively for all files inside
      mv_merge "$file" "$2/`basename "$file"`"
    done
    # remove after merge
    rmdir "$1"
  else
    # either file or non-existing folder
    mv "$1" "$2"
  fi
}

答案 2 :(得分:1)

来自“目录”的父目录执行此命令:

find ./dir -name "*.mov" | xargs tar cif mov.tar

然后cd到要移动文件的目录并执行:

tar xvf /path/to/parent/directory/of"dir"/mov.tar

答案 3 :(得分:1)

ASSERT:没有文件中包含换行符。然而,空间是AOK。

# TEST FIRST: CREATION OF FOLDERS
find . -type f -iname \*.mov -printf '%h\n' | sort | uniq | xargs -n 1 -d '\n' -I '{}' echo mkdir -vp "/TARGET_FOLDER_ROOT/{}"

# EXECUTE CREATION OF EMPTY TARGET FOLDERS
find . -type f -iname \*.mov -printf '%h\n' | sort | uniq | xargs -n 1 -d '\n' -I '{}' mkdir -vp "/TARGET_FOLDER_ROOT/{}"

# TEST FIRST: REVIEW FILES TO BE MOVED
find . -type f -iname \*.mov -exec echo mv {} /TARGET_FOLDER_ROOT/{} \;

# EXECUTE MOVE FILES
find . -type f -iname \*.mov -exec mv {} /TARGET_FOLDER_ROOT/{} \;

答案 4 :(得分:0)

如果要将所有mov文件移动到名为new location -

的目录,这应该有效
find ./dir -iname '*.mov' -exec mv '{}' ./newlocation \;

但是,如果您希望将mov文件与其子目录一起移动,那么您可以执行以下操作 -

步骤1:使用cp

将/ dir的整个结构复制到新位置
cp -iprv dir/ newdir

第2步:从newdir中查找jpg个文件并删除它们。

find ./newdir -iname "*.jpg" -delete

测试:

[jaypal:~/Temp] ls -R a
a.mov aa    b.mov

a/aa:
aaa   c.mov d.mov

a/aa/aaa:
e.mov f.mov
[jaypal:~/Temp] mkdir d
[jaypal:~/Temp] find ./a -iname '*.mov' -exec mv '{}' ./d \;
[jaypal:~/Temp] ls -R d
a.mov b.mov c.mov d.mov e.mov f.mov

答案 5 :(得分:0)

仅复制以下文件会更容易:

cp --parents some/folder/*/*.mov new_folder/

答案 6 :(得分:0)

我修改了@djjeck 的功能,因为它没有按我的需要工作。下面的函数将源文件移动到目标目录,同时在源文件路径中创建所需的层次结构级别(参见下面的示例):

# moves a file, creates needed levels of hierarchy in destination
# usage: move_with_hierarchy source_file destination top_level_directory
move_with_hierarchy () {
    path_tail=$(dirname $(realpath --relative-to="$3" "$1"))

    cd "$2"
    mkdir -p $path_tail
    cd - > /dev/null

    mv "$1" "${2}/${path_tail}"
}

示例:

$ ls /home/sergei/tmp/dir1/dir2/bla.txt
/home/sergei/tmp/dir1/dir2/bla.txt
$ rm -rf tmp2
$ mkdir tmp2
$ move_with_hierarchy /home/sergei/tmp/dir1/dir2/bla.txt /home/sergei/tmp2 /home/sergei/tmp
$ tree ~/tmp2
/home/sergei/tmp2
└── dir1
    └── dir2
        └── bla.txt

2 directories, 1 file