MacOS – Find, select and move/copy multiple files at once via Terminal

findermacosterminal

I looked for relevant posts extensively before writing but I apologise if it has been already asked and solved.

I'd need to find, select and move/copy some files from a folder starting from a list in a text file (but could also paste it directly if needed).

I've found some posts that could've helped and more precisely the ones at the following link: https://stackoverflow.com/questions/29311880/finding-files-from-list-and-copying-them-into-new-directory

This seems perfect but I've got a permission error (cp: /found_files: Permission denied) and couldn't find a work around (tried sudo and many other combinations).

This one seemed fine as well: Find multiple files at once via Terminal. It works very well to find the files but I couldn't find a way to select them in order to be able to move/copy them to a new directory.

Tried all this on macOS Sierra 10.12.6 with no special configurations or changes in the Terminal.

Best Answer

You get cp: /found_files: Permission denied because the script in the linked post, in its current form, is written to copy the listed files to the /found_files directory. The /found_files directory doesn't exist on your Mac and cp interprets found_files as a file located in /. Since / is not writable, you get the permission error.

I modified the script so that it works with other destination directories and expanded it to support copying and moving files:

  1. Launch Terminal. Select a directory where you save your scripts, for example ~/bin:

    cd ~/bin
    
  2. Create a file named cplist.sh with these contents:

    #!/bin/bash
    
    source_dir="$1"
    destination_dir="$2"
    file_list="$3"
    
    # Sanity checks
    if [[ $# -ne 3 ]]; then
        echo "Usage: $0 <source dir> <target dir> <file list>"
        exit 0
    fi
    if [[ ! -d "$source_dir" ]]; then
        echo "$0: '$source_dir' could not be found"
        exit 1
    fi
    if [[ ! -d "$destination_dir" ]]; then
        echo "$0: '$destination_dir' could not be found"
        exit 1
    fi
    if [[ ! -f "$file_list" ]]; then
        echo "$0: '$file_list' could not be found"
        exit 1
    fi
    
    # Copy or move?
    if [[ $(basename $0) == "mvlist.sh" ]]; then
        command="mv"
        action="Moving"
    else
        command="cp -a"
        action="Copying"
    fi
    
    # Copy files    
    while read filename
    do
        echo "$action file '$filename'"
        if [[ -f "$source_dir/$filename" ]]; then
            find "$source_dir" -name "$filename" -exec $command "{}" "$destination_dir" \;
        else
            echo "File '$filename' is listed in '$file_list' but could not be found"
        fi  
    done < "$file_list"
    
  3. Make the file executable:

    chmod a+x cplist.sh
    
  4. Link the file to mvlist.sh:

    ln -s cplist.sh mvlist.sh
    
  5. To copy a set of files, use cplist.sh as follows:

    ./cplist.sh <source dir> <destination dir> <file list>
    

    where <file list> is a text file that contains file names, for example:

    file 1.pdf
    file 2.pdf
    ...
    

    To move a set of files, use mvlist.sh as follows:

    ./mvlist.sh <source dir> <destination dir> <file list> 
    

For example:

 ./mvlist.sh 
 Usage: ./mvlist.sh <source dir> <target dir> <file list>

 ./mvlist.sh /tmp/ /nonexistentfolder filelist.txt
 ./mvlist.sh: '/nonexistentfolder' could not be found

 ./mvlist.sh /tmp/source/ /tmp/destination filelist.txt
 Moving file 'file 1.pdf'
 Moving file 'file 2.pdf'
 Moving file 'file 3.pdf'
 Moving file 'file 4.pdf'
 Moving file 'file 5.pdf'
 Moving file 'file a.pdf'
 File 'file a.pdf' is listed in 'filelist.txt' but could not be found
 Moving file 'file 6.pdf'
 Moving file 'file 7.pdf'
 Moving file 'file 8.pdf'
 Moving file 'file 9.pdf'