How to Find Files Recursively by File Type and Copy Them to a Directory

How to find files recursively by file type and copy them to a directory?

Try this:

find . -name "*.pdf" -type f -exec cp {} ./pdfsfolder \;

Find all files from today recursively and copy them

Remove -maxdepth 1 from your find command to find files in subdirectories and use -exec to move those to the target directory:

find /dir -type f -mtime -1 -exec mv {} /pdf \;

Recursively Find Files With Particular File Extension and Content

What do you mean by keyword? Is that a word, present inside the file? Or is it a part of the filename?

In case it's the part of the filename, you can use file: in the Windows search, like in following example:

file:*keyword*.py

This will show you all files, called *keyword*.py. After you've done that, you might change your Windows explorer's view, clicking on the "View" tab and choose "Details", this will also show you the directory where those files are located.

How to recursively copy all files with a certain extension in a directory using Python?

If I understand correctly, you want glob with recursive=True, which, with the ** specifier, will recursively traverse directories and find all files satisfying a format specifier:

import glob
import os
import shutil

def copy(src, dest):
for file_path in glob.glob(os.path.join(src, '**', '*.bmp'), recursive=True):
new_path = os.path.join(dest, os.path.basename(file_path))
shutil.copy(file_path, new_path)

Recursive find and copy to other directory

The above will get you everything in /media, but to get exactly what you want you probably want to use something like:

Method 1: Copy only what you need recursively, per your requirements:

    mkdir ../media2; find . -name "*.jpg" -exec cp -r --parents {} ../media2 \;

I ran this from inside the directory you want to search recursively. It does a couple things:

1 - create the new destination directory

    mkdir ../media2

2 - then finds all files ending with ".jpg" recursively.

    find . -name "*.jpg"

3 - uses -exec to pass the copy command to each file returned to find as a match, and subs that in as the first argument (which with the syntax of cp, is going to be your source file):

    -exec cp -r --parents {} ../media2 \;

the "--parents" flag retains existing directory structure and recursively creates subsequent parent directories. Super useful right?

Method 2: there might be a better way to do this with xargs, but the above ended up being the most simple method imho. That said, if you want to think outside the box, you could simply copy the entire directory over recursively, then remove anything NOT ending with ".jpg" with something like:

    cp -r media media2; find ./media '!'-name "*.jpg" -type f | xargs rm

Recursively copy directories and files into destination

You could easily achieve this by implementing the FileVisitor interface. This is a code sample just to show you how it works. It should do what you asked.

EDIT: Updated with custom size handling

public class FileCopier implements FileVisitor<Path> {

private final Path sourcePath;
private final Path targetPath;

private HashMap<String, Long> mapSize;

public FileCopier(Path sourcePath, Path targetPath) throws IOException {
//Check whether the destination directory exists or not
if (!Files.exists(targetPath)) {
Files.createDirectories(targetPath);
}

this.sourcePath = sourcePath.toRealPath();
this.targetPath = targetPath.toRealPath();
this.mapSize = new HashMap<>();
}

@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
//Copying the directory first and then its content (directory copy does not copy its content)

//Retrieving the last bit of the path starting from the source location
Path lastBitPath = sourcePath.relativize(dir.toAbsolutePath().normalize());

//Adding the last bit to the target path
Path targetCopyPath = targetPath.resolve(lastBitPath).toAbsolutePath().normalize();

if (!Files.exists(targetCopyPath)) {
Files.copy(dir, targetCopyPath, StandardCopyOption.COPY_ATTRIBUTES);
}

//Defining 0 bytes for the new visited directory
mapSize.put(targetCopyPath.toString(), 0L);
System.out.println("Started: " + targetCopyPath);
return FileVisitResult.CONTINUE;
}

@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Path targetCopyPath = targetPath.resolve(sourcePath.relativize(file.toAbsolutePath().normalize())).toAbsolutePath().normalize();
Files.copy(file, targetCopyPath, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES);

//Adding the current copied file's bytes to the corresponding folder
mapSize.put(targetCopyPath.getParent().toString(), mapSize.get(targetCopyPath.getParent().toString()) + Files.size(file));
System.out.println("Finished FILE: " + targetCopyPath);
return FileVisitResult.CONTINUE;
}

@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) {
return FileVisitResult.TERMINATE;
}

@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
//Retrieving the last bit of the path starting from the source location
Path lastBitPath = sourcePath.relativize(dir.toAbsolutePath().normalize());

//Adding the last bit to the target path
Path targetCopyPath = targetPath.resolve(lastBitPath).toAbsolutePath().normalize();

//Showing the number of bytes copied within the copied directory
System.out.println("Total " + this.mapSize.get(targetCopyPath.toString()) + " bytes were copied into " + targetCopyPath);
return FileVisitResult.CONTINUE;
}

public static void main(String[] args) throws IOException {
Path sourcePath = Paths.get("./test");
Path targetPath = Paths.get("./subtest");
FileCopier fc = new FileCopier(sourcePath, targetPath);
Files.walkFileTree(sourcePath, fc);
}
}

Copy specific files from different directories without changing file extension

Assuming you want to use the subfolder name (number) as a suffix to the new
file name, would you please try:

#!/bin/bash

folder="folder" # directory name
base="1" # basename of the jpg file
ext="jpg" # extention of the jpg file
new="new" # directory name for the "new" files

mkdir -p "$folder/$new" # create "new" directory if nonexistent

while IFS= read -r -d "" f; do
n=${f#*$folder/}; n=${n%/$base.$ext}
echo cp -i -- "$f" "$folder/$new/$base($n).$ext"
done < <(find "$folder" -type f -regex "$folder/[0-9]+/$base\.$ext" -print0)
  • find "$folder" -type f -regex "$folder/[0-9]+/$base\.$ext" finds
    all numbered folders which contains "1.jpg". You do not have to specify
    the range between 1 and 100.
  • -print0 option uses a null character to delimit filenames. It is useful
    to protect filenames which may contain special characters such as blank
    characters.
  • The output of find command, matched filenames delimited by null characters,
    is redirected to the read command within the while loop.
  • The -d "" option to the read command splits the input on null characters
    corresponding to -print0.
  • n=${f#*$folder/}; n=${n%/$base.$ext} assigns n to the subfolder name
    which contains the jpg file.
  • "$folder/$new/$base($n).$ext" constructs the new filename rearranging
    the substrings.

If the output of the echo command looks okay, drop echo.



Related Topics



Leave a reply



Submit