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

发布于 2024-12-26 00:49:46 字数 767 浏览 0 评论 0原文

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

/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
  ...

我熟悉 findgrep 和 xargs但不知道如何解决这个问题。预先非常感谢!

I have a directory which contains multiple sub-directories with mov and jpg files.

/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

I need to find a way using command-line tools (on Mac OSX, ideally) to move all the mov files to a new location. However, one requirement is to keep directory structure i.e.:

/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
  ...

I am familiar with find, grep, and xargs but wasn't sure how to solve this issue. Thank you very much beforehand!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

笙痞 2025-01-02 00:49:46

这稍微取决于您的操作系统,更具体地说,取决于您的 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 {} +

It depends slightly on your O/S and, more particularly, on the facilities in your version of tar and whether you have the command cpio. It also depends a bit on whether you have newlines (in particular) in your file names; most people don't.

Option #1

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

Option #2

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

The cpio command has a pass-through (copy) mode which does exactly what you want given a list of file names, one per line, on its standard input.

Some versions of the tar command have an option to read the list of file names, one per line, from standard input; on MacOS X, that option is -T - (where the lone - means 'standard input'). For the first tar command, the option -f - means (in the context of writing an archive with -c, write to standard output); in the second tar command, the -x option means that the -f - means 'read from standard input'.

There may be other options; look at the manual page or help output of tar rather carefully.

This process copies the files rather than moving them. The second half of the operation would be:

find . -name '*.mov' -exec rm -f {} +
深海里的那抹蓝 2025-01-02 00:49:46

ASSERT:没有文件包含换行符。然而,空格是可以的。

# 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/{} \;

ASSERT: No files have newline characters in them. Spaces, however, are 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/{} \;
物价感观 2025-01-02 00:49:46

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

# 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
}

Being large files, if they are on the same file system you don't want to copy them, but just to replicate their directory structure while moving.
You can use this function:

# 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"
}

Or, adding support to merging existing directories:

# 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
}
小伙你站住 2025-01-02 00:49:46

复制文件会更容易,例如:

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

It is easier to just copy the files like:

cp --parents some/folder/*/*.mov new_folder/
少女的英雄梦 2025-01-02 00:49:46

从“dir 的父目录执行此命令:

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

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

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

from the parent directory of "dir execute this:

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

Then cd to the directory you want to move the files to and execute this:

tar xvf /path/to/parent/directory/of"dir"/mov.tar
巷子口的你 2025-01-02 00:49:46

如果您想将所有 mov 文件移动到名为新位置的目录,这应该可行 -

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

This should work if you want to move all mov files to a directory called new location -

find ./dir -iname '*.mov' -exec mv '{}' ./newlocation \;

However, if you wish to move the mov files along with their sub-dirs then you can do something like this -

Step 1: Copy entire structure of /dir to a new location using cp

cp -iprv dir/ newdir

Step 2: Find jpg files from newdir and delete them.

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

Test:

[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
夜未央樱花落 2025-01-02 00:49:46

我修改了@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

I amended the function of @djjeck, because it didn't work as I needed. The function below moves a source file to a destination directory also creating the needed levels of hierarchy in the source file path (see the example below):

# 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}"
}

example:

$ 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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文